feat: add updatedBy field to track last record modifier (#16807)
<!-- CURSOR_SUMMARY --> > [!NOTE] > Implements last-modifier tracking and unified actor injection. > > - New `ActorFromAuthContextService` replaces createdBy-only logic; pre-query hooks now inject both `createdBy` and `updatedBy` on create and `updatedBy` on update > - Add `updatedBy` standard field to core/custom objects (e.g., `person`, `company`, `task`, `note`, `attachment`, `dashboard`, `workflow`, `workflowRun`) with IDs, metadata builders, and ORM entity fields > - Record CRUD: `create` now sets both `createdBy` and `updatedBy`; `update` sets `updatedBy`; workflow actions use a shared workflow actor builder; REST base handler uses the new actor service > - Seeder data and snapshots updated to include `updatedBy`; GraphQL result formatting adds defaults/handling for empty composite fields (incl. actor) > - Frontend `useUpdateOneRecord` upserts returned record into the local store after mutation > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 1f283778e9cb28a35bf84632a1a2997250bb3131. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Félix Malfait <felix.malfait@gmail.com> Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
@@ -5,6 +5,7 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata
|
||||
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||
import { useGetRecordFromCache } from '@/object-record/cache/hooks/useGetRecordFromCache';
|
||||
import { getObjectTypename } from '@/object-record/cache/utils/getObjectTypename';
|
||||
import { getRecordFromRecordNode } from '@/object-record/cache/utils/getRecordFromRecordNode';
|
||||
import { getRecordNodeFromRecord } from '@/object-record/cache/utils/getRecordNodeFromRecord';
|
||||
import { updateRecordFromCache } from '@/object-record/cache/utils/updateRecordFromCache';
|
||||
import { useGenerateDepthRecordGqlFieldsFromObject } from '@/object-record/graphql/record-gql-fields/hooks/useGenerateDepthRecordGqlFieldsFromObject';
|
||||
@@ -165,6 +166,11 @@ export const useUpdateOneRecord = <
|
||||
const record = data?.[mutationResponseField];
|
||||
if (!isDefined(record)) return;
|
||||
|
||||
const recordToUpsert = getRecordFromRecordNode({
|
||||
recordNode: record,
|
||||
});
|
||||
upsertRecordsInStore({ partialRecords: [recordToUpsert] });
|
||||
|
||||
triggerUpdateRecordOptimisticEffect({
|
||||
cache,
|
||||
objectMetadataItem,
|
||||
|
||||
+6
@@ -20,6 +20,12 @@ const baseNote = {
|
||||
workspaceMemberId: '1',
|
||||
context: {},
|
||||
},
|
||||
updatedBy: {
|
||||
name: 'Test',
|
||||
source: FieldActorSource.MANUAL,
|
||||
workspaceMemberId: '1',
|
||||
context: {},
|
||||
},
|
||||
createdAt: '2021-01-01',
|
||||
updatedAt: '2021-01-01',
|
||||
noteTargets: [],
|
||||
|
||||
@@ -15,7 +15,7 @@ import { RestToCommonSelectedFieldsHandler } from 'src/engine/api/rest/core/rest
|
||||
import { parseCorePath } from 'src/engine/api/rest/input-request-parsers/path-parser-utils/parse-core-path.utils';
|
||||
import { Depth } from 'src/engine/api/rest/input-request-parsers/types/depth.type';
|
||||
import { AuthenticatedRequest } from 'src/engine/api/rest/types/authenticated-request';
|
||||
import { CreatedByFromAuthContextService } from 'src/engine/core-modules/actor/services/created-by-from-auth-context.service';
|
||||
import { ActorFromAuthContextService } from 'src/engine/core-modules/actor/services/actor-from-auth-context.service';
|
||||
import { ApiKeyRoleService } from 'src/engine/core-modules/api-key/services/api-key-role.service';
|
||||
import { AccessTokenService } from 'src/engine/core-modules/auth/token/services/access-token.service';
|
||||
import { WorkspaceDomainsService } from 'src/engine/core-modules/domain/workspace-domains/services/workspace-domains.service';
|
||||
@@ -57,7 +57,7 @@ export abstract class RestApiBaseHandler {
|
||||
@Inject()
|
||||
protected readonly workspaceCacheService: WorkspaceCacheService;
|
||||
@Inject()
|
||||
protected readonly createdByFromAuthContextService: CreatedByFromAuthContextService;
|
||||
protected readonly actorFromAuthContextService: ActorFromAuthContextService;
|
||||
@Inject()
|
||||
protected readonly workspaceCacheStorageService: WorkspaceCacheStorageService;
|
||||
@Inject()
|
||||
|
||||
@@ -3,10 +3,12 @@ import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { CreatedByCreateManyPreQueryHook } from 'src/engine/core-modules/actor/query-hooks/created-by.create-many.pre-query-hook';
|
||||
import { CreatedByCreateOnePreQueryHook } from 'src/engine/core-modules/actor/query-hooks/created-by.create-one.pre-query-hook';
|
||||
import { UpdatedByUpdateManyPreQueryHook } from 'src/engine/core-modules/actor/query-hooks/updated-by.update-many.pre-query-hook';
|
||||
import { UpdatedByUpdateOnePreQueryHook } from 'src/engine/core-modules/actor/query-hooks/updated-by.update-one.pre-query-hook';
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module';
|
||||
|
||||
import { CreatedByFromAuthContextService } from './services/created-by-from-auth-context.service';
|
||||
import { ActorFromAuthContextService } from './services/actor-from-auth-context.service';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@@ -16,12 +18,16 @@ import { CreatedByFromAuthContextService } from './services/created-by-from-auth
|
||||
providers: [
|
||||
CreatedByCreateManyPreQueryHook,
|
||||
CreatedByCreateOnePreQueryHook,
|
||||
CreatedByFromAuthContextService,
|
||||
UpdatedByUpdateManyPreQueryHook,
|
||||
UpdatedByUpdateOnePreQueryHook,
|
||||
ActorFromAuthContextService,
|
||||
],
|
||||
exports: [
|
||||
CreatedByCreateManyPreQueryHook,
|
||||
CreatedByCreateOnePreQueryHook,
|
||||
CreatedByFromAuthContextService,
|
||||
UpdatedByUpdateManyPreQueryHook,
|
||||
UpdatedByUpdateOnePreQueryHook,
|
||||
ActorFromAuthContextService,
|
||||
],
|
||||
})
|
||||
export class ActorModule {}
|
||||
|
||||
+10
-10
@@ -9,9 +9,9 @@ import {
|
||||
} from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception';
|
||||
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
|
||||
import {
|
||||
CreatedByFromAuthContextService,
|
||||
type CreateInput,
|
||||
} from 'src/engine/core-modules/actor/services/created-by-from-auth-context.service';
|
||||
ActorFromAuthContextService,
|
||||
type RecordInput,
|
||||
} from 'src/engine/core-modules/actor/services/actor-from-auth-context.service';
|
||||
import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
|
||||
|
||||
@WorkspaceQueryHook(`*.createMany`)
|
||||
@@ -19,14 +19,14 @@ export class CreatedByCreateManyPreQueryHook
|
||||
implements WorkspacePreQueryHookInstance
|
||||
{
|
||||
constructor(
|
||||
private readonly createdByFromAuthContextService: CreatedByFromAuthContextService,
|
||||
private readonly actorFromAuthContextService: ActorFromAuthContextService,
|
||||
) {}
|
||||
|
||||
async execute(
|
||||
authContext: AuthContext,
|
||||
objectName: string,
|
||||
payload: CreateManyResolverArgs<CreateInput>,
|
||||
): Promise<CreateManyResolverArgs<CreateInput>> {
|
||||
payload: CreateManyResolverArgs<RecordInput>,
|
||||
): Promise<CreateManyResolverArgs<RecordInput>> {
|
||||
if (!isDefined(payload.data)) {
|
||||
throw new GraphqlQueryRunnerException(
|
||||
'Payload data is required',
|
||||
@@ -36,11 +36,11 @@ export class CreatedByCreateManyPreQueryHook
|
||||
|
||||
return {
|
||||
...payload,
|
||||
data: await this.createdByFromAuthContextService.injectCreatedBy(
|
||||
payload.data,
|
||||
objectName,
|
||||
data: await this.actorFromAuthContextService.injectActorFieldsOnCreate({
|
||||
records: payload.data,
|
||||
objectMetadataNameSingular: objectName,
|
||||
authContext,
|
||||
),
|
||||
}),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+11
-11
@@ -1,4 +1,4 @@
|
||||
import { isDefined } from 'class-validator';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { type WorkspacePreQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
|
||||
import { type CreateOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
|
||||
@@ -9,9 +9,9 @@ import {
|
||||
} from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception';
|
||||
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
|
||||
import {
|
||||
CreatedByFromAuthContextService,
|
||||
type CreateInput,
|
||||
} from 'src/engine/core-modules/actor/services/created-by-from-auth-context.service';
|
||||
ActorFromAuthContextService,
|
||||
type RecordInput,
|
||||
} from 'src/engine/core-modules/actor/services/actor-from-auth-context.service';
|
||||
import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
|
||||
|
||||
@WorkspaceQueryHook(`*.createOne`)
|
||||
@@ -19,14 +19,14 @@ export class CreatedByCreateOnePreQueryHook
|
||||
implements WorkspacePreQueryHookInstance
|
||||
{
|
||||
constructor(
|
||||
private readonly createdByFromAuthContextService: CreatedByFromAuthContextService,
|
||||
private readonly actorFromAuthContextService: ActorFromAuthContextService,
|
||||
) {}
|
||||
|
||||
async execute(
|
||||
authContext: AuthContext,
|
||||
objectName: string,
|
||||
payload: CreateOneResolverArgs<CreateInput>,
|
||||
): Promise<CreateOneResolverArgs<CreateInput>> {
|
||||
payload: CreateOneResolverArgs<RecordInput>,
|
||||
): Promise<CreateOneResolverArgs<RecordInput>> {
|
||||
if (!isDefined(payload.data)) {
|
||||
throw new GraphqlQueryRunnerException(
|
||||
'Payload data is required',
|
||||
@@ -35,11 +35,11 @@ export class CreatedByCreateOnePreQueryHook
|
||||
}
|
||||
|
||||
const [recordToCreateData] =
|
||||
await this.createdByFromAuthContextService.injectCreatedBy(
|
||||
[payload.data],
|
||||
objectName,
|
||||
await this.actorFromAuthContextService.injectActorFieldsOnCreate({
|
||||
records: [payload.data],
|
||||
objectMetadataNameSingular: objectName,
|
||||
authContext,
|
||||
);
|
||||
});
|
||||
|
||||
return {
|
||||
...payload,
|
||||
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { type WorkspacePreQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
|
||||
import { type UpdateManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
|
||||
|
||||
import {
|
||||
GraphqlQueryRunnerException,
|
||||
GraphqlQueryRunnerExceptionCode,
|
||||
} from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception';
|
||||
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
|
||||
import {
|
||||
ActorFromAuthContextService,
|
||||
type RecordInput,
|
||||
} from 'src/engine/core-modules/actor/services/actor-from-auth-context.service';
|
||||
import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
|
||||
|
||||
@WorkspaceQueryHook(`*.updateMany`)
|
||||
export class UpdatedByUpdateManyPreQueryHook
|
||||
implements WorkspacePreQueryHookInstance
|
||||
{
|
||||
constructor(
|
||||
private readonly actorFromAuthContextService: ActorFromAuthContextService,
|
||||
) {}
|
||||
|
||||
async execute(
|
||||
authContext: AuthContext,
|
||||
objectName: string,
|
||||
payload: UpdateManyResolverArgs<RecordInput>,
|
||||
): Promise<UpdateManyResolverArgs<RecordInput>> {
|
||||
if (!isDefined(payload.data)) {
|
||||
throw new GraphqlQueryRunnerException(
|
||||
'Payload data is required',
|
||||
GraphqlQueryRunnerExceptionCode.INVALID_QUERY_INPUT,
|
||||
);
|
||||
}
|
||||
|
||||
const [recordToUpdateData] =
|
||||
await this.actorFromAuthContextService.injectUpdatedBy({
|
||||
records: [payload.data],
|
||||
objectMetadataNameSingular: objectName,
|
||||
authContext,
|
||||
});
|
||||
|
||||
return {
|
||||
...payload,
|
||||
data: recordToUpdateData,
|
||||
};
|
||||
}
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { type WorkspacePreQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
|
||||
import { type UpdateOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
|
||||
|
||||
import {
|
||||
GraphqlQueryRunnerException,
|
||||
GraphqlQueryRunnerExceptionCode,
|
||||
} from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception';
|
||||
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
|
||||
import {
|
||||
ActorFromAuthContextService,
|
||||
type RecordInput,
|
||||
} from 'src/engine/core-modules/actor/services/actor-from-auth-context.service';
|
||||
import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
|
||||
|
||||
@WorkspaceQueryHook(`*.updateOne`)
|
||||
export class UpdatedByUpdateOnePreQueryHook
|
||||
implements WorkspacePreQueryHookInstance
|
||||
{
|
||||
constructor(
|
||||
private readonly actorFromAuthContextService: ActorFromAuthContextService,
|
||||
) {}
|
||||
|
||||
async execute(
|
||||
authContext: AuthContext,
|
||||
objectName: string,
|
||||
payload: UpdateOneResolverArgs<RecordInput>,
|
||||
): Promise<UpdateOneResolverArgs<RecordInput>> {
|
||||
if (!isDefined(payload.data)) {
|
||||
throw new GraphqlQueryRunnerException(
|
||||
'Payload data is required',
|
||||
GraphqlQueryRunnerExceptionCode.INVALID_QUERY_INPUT,
|
||||
);
|
||||
}
|
||||
|
||||
const [recordToUpdateData] =
|
||||
await this.actorFromAuthContextService.injectUpdatedBy({
|
||||
records: [payload.data],
|
||||
objectMetadataNameSingular: objectName,
|
||||
authContext,
|
||||
});
|
||||
|
||||
return {
|
||||
...payload,
|
||||
data: recordToUpdateData,
|
||||
};
|
||||
}
|
||||
}
|
||||
+27
-23
@@ -7,7 +7,7 @@ import {
|
||||
type FullNameMetadata,
|
||||
} from 'twenty-shared/types';
|
||||
|
||||
import { CreatedByFromAuthContextService } from 'src/engine/core-modules/actor/services/created-by-from-auth-context.service';
|
||||
import { ActorFromAuthContextService } from 'src/engine/core-modules/actor/services/actor-from-auth-context.service';
|
||||
import { type ApiKeyEntity } from 'src/engine/core-modules/api-key/api-key.entity';
|
||||
import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
|
||||
import { type UserEntity } from 'src/engine/core-modules/user/user.entity';
|
||||
@@ -31,8 +31,8 @@ const fromFullNameMetadataToName = ({
|
||||
lastName,
|
||||
}: FullNameMetadata) => `${firstName} ${lastName}`;
|
||||
|
||||
describe('CreatedByFromAuthContextService', () => {
|
||||
let service: CreatedByFromAuthContextService;
|
||||
describe('ActorFromAuthContextService', () => {
|
||||
let service: ActorFromAuthContextService;
|
||||
const mockWorkspaceMemberRepository = {
|
||||
findOneOrFail: jest.fn(),
|
||||
};
|
||||
@@ -51,7 +51,7 @@ describe('CreatedByFromAuthContextService', () => {
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [
|
||||
CreatedByFromAuthContextService,
|
||||
ActorFromAuthContextService,
|
||||
{
|
||||
provide: GlobalWorkspaceOrmManager,
|
||||
useValue: globalWorkspaceOrmManager,
|
||||
@@ -93,8 +93,8 @@ describe('CreatedByFromAuthContextService', () => {
|
||||
],
|
||||
}).compile();
|
||||
|
||||
service = module.get<CreatedByFromAuthContextService>(
|
||||
CreatedByFromAuthContextService,
|
||||
service = module.get<ActorFromAuthContextService>(
|
||||
ActorFromAuthContextService,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -129,11 +129,11 @@ describe('CreatedByFromAuthContextService', () => {
|
||||
mockedWorkspaceMember,
|
||||
);
|
||||
|
||||
const result = await service.injectCreatedBy(
|
||||
[{}],
|
||||
'person',
|
||||
authContext as AuthContext,
|
||||
);
|
||||
const result = await service.injectCreatedBy({
|
||||
records: [{}],
|
||||
objectMetadataNameSingular: 'person',
|
||||
authContext: authContext as AuthContext,
|
||||
});
|
||||
|
||||
expect(result).toEqual<ExpectedResult>([
|
||||
{
|
||||
@@ -169,11 +169,11 @@ describe('CreatedByFromAuthContextService', () => {
|
||||
mockedWorkspaceMember,
|
||||
);
|
||||
|
||||
const result = await service.injectCreatedBy(
|
||||
[{}],
|
||||
'person',
|
||||
authContext as AuthContext,
|
||||
);
|
||||
const result = await service.injectCreatedBy({
|
||||
records: [{}],
|
||||
objectMetadataNameSingular: 'person',
|
||||
authContext: authContext as AuthContext,
|
||||
});
|
||||
|
||||
expect(result).toEqual<ExpectedResult>([
|
||||
{
|
||||
@@ -196,11 +196,11 @@ describe('CreatedByFromAuthContextService', () => {
|
||||
workspace: { id: '20202020-bdec-497f-847a-1bb334fefe58' },
|
||||
} as const satisfies TestingAuthContext;
|
||||
|
||||
const result = await service.injectCreatedBy(
|
||||
[{}],
|
||||
'person',
|
||||
authContext as AuthContext,
|
||||
);
|
||||
const result = await service.injectCreatedBy({
|
||||
records: [{}],
|
||||
objectMetadataNameSingular: 'person',
|
||||
authContext: authContext as AuthContext,
|
||||
});
|
||||
|
||||
expect(result).toEqual<ExpectedResult>([
|
||||
{
|
||||
@@ -220,9 +220,13 @@ describe('CreatedByFromAuthContextService', () => {
|
||||
} as const satisfies TestingAuthContext;
|
||||
|
||||
await expect(
|
||||
service.injectCreatedBy([{}], 'person', authContext as AuthContext),
|
||||
service.injectCreatedBy({
|
||||
records: [{}],
|
||||
objectMetadataNameSingular: 'person',
|
||||
authContext: authContext as AuthContext,
|
||||
}),
|
||||
).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
`"Unable to build createdBy metadata - no valid actor information found in auth context"`,
|
||||
`"Unable to build actor metadata - no valid actor information found in auth context"`,
|
||||
);
|
||||
});
|
||||
});
|
||||
+87
-31
@@ -6,6 +6,7 @@ import { assertIsDefinedOrThrow, isDefined } from 'twenty-shared/utils';
|
||||
import { type WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface';
|
||||
|
||||
import { buildCreatedByFromApiKey } from 'src/engine/core-modules/actor/utils/build-created-by-from-api-key.util';
|
||||
import { buildCreatedByFromApplication } from 'src/engine/core-modules/actor/utils/build-created-by-from-application.util';
|
||||
import { buildCreatedByFromFullNameMetadata } from 'src/engine/core-modules/actor/utils/build-created-by-from-full-name-metadata.util';
|
||||
import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
|
||||
import { WorkspaceNotFoundDefaultError } from 'src/engine/core-modules/workspace/workspace.exception';
|
||||
@@ -14,25 +15,78 @@ import { buildFieldMapsFromFlatObjectMetadata } from 'src/engine/metadata-module
|
||||
import { buildObjectIdByNameMaps } from 'src/engine/metadata-modules/flat-object-metadata/utils/build-object-id-by-name-maps.util';
|
||||
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
|
||||
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
|
||||
import { buildCreatedByFromApplication } from 'src/engine/core-modules/actor/utils/build-created-by-from-application.util';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export type CreateInput = Record<string, any>;
|
||||
export type RecordInput = Record<string, unknown>;
|
||||
|
||||
export type InjectActorParams = {
|
||||
records: RecordInput[];
|
||||
objectMetadataNameSingular: string;
|
||||
authContext: AuthContext;
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class CreatedByFromAuthContextService {
|
||||
private readonly logger = new Logger(CreatedByFromAuthContextService.name);
|
||||
export class ActorFromAuthContextService {
|
||||
private readonly logger = new Logger(ActorFromAuthContextService.name);
|
||||
|
||||
constructor(
|
||||
private readonly globalWorkspaceOrmManager: GlobalWorkspaceOrmManager,
|
||||
private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService,
|
||||
) {}
|
||||
|
||||
async injectCreatedBy(
|
||||
records: CreateInput[],
|
||||
objectMetadataNameSingular: string,
|
||||
authContext: AuthContext,
|
||||
): Promise<CreateInput[]> {
|
||||
async injectCreatedBy({
|
||||
records,
|
||||
objectMetadataNameSingular,
|
||||
authContext,
|
||||
}: InjectActorParams): Promise<RecordInput[]> {
|
||||
return this.injectActorField({
|
||||
records,
|
||||
objectMetadataNameSingular,
|
||||
authContext,
|
||||
fieldName: 'createdBy',
|
||||
});
|
||||
}
|
||||
|
||||
async injectActorFieldsOnCreate({
|
||||
records,
|
||||
objectMetadataNameSingular,
|
||||
authContext,
|
||||
}: InjectActorParams): Promise<RecordInput[]> {
|
||||
const recordsWithCreatedBy = await this.injectActorField({
|
||||
records,
|
||||
objectMetadataNameSingular,
|
||||
authContext,
|
||||
fieldName: 'createdBy',
|
||||
});
|
||||
|
||||
return await this.injectActorField({
|
||||
records: recordsWithCreatedBy,
|
||||
objectMetadataNameSingular,
|
||||
authContext,
|
||||
fieldName: 'updatedBy',
|
||||
});
|
||||
}
|
||||
|
||||
async injectUpdatedBy({
|
||||
records,
|
||||
objectMetadataNameSingular,
|
||||
authContext,
|
||||
}: InjectActorParams): Promise<RecordInput[]> {
|
||||
return this.injectActorField({
|
||||
records,
|
||||
objectMetadataNameSingular,
|
||||
authContext,
|
||||
fieldName: 'updatedBy',
|
||||
});
|
||||
}
|
||||
|
||||
private async injectActorField({
|
||||
records,
|
||||
objectMetadataNameSingular,
|
||||
authContext,
|
||||
fieldName,
|
||||
}: InjectActorParams & { fieldName: 'createdBy' | 'updatedBy' }): Promise<
|
||||
RecordInput[]
|
||||
> {
|
||||
const workspace = authContext.workspace;
|
||||
|
||||
assertIsDefinedOrThrow(workspace, WorkspaceNotFoundDefaultError);
|
||||
@@ -46,7 +100,7 @@ export class CreatedByFromAuthContextService {
|
||||
);
|
||||
|
||||
this.logger.log(
|
||||
`Injecting createdBy from auth context for object ${objectMetadataNameSingular} and workspace ${workspace.id}`,
|
||||
`Injecting ${fieldName} from auth context for object ${objectMetadataNameSingular} and workspace ${workspace.id}`,
|
||||
);
|
||||
|
||||
const { idByNameSingular } = buildObjectIdByNameMaps(
|
||||
@@ -68,9 +122,9 @@ export class CreatedByFromAuthContextService {
|
||||
`Object metadata found with fields: ${Object.keys(fieldIdByName)}`,
|
||||
);
|
||||
|
||||
if (!isDefined(fieldIdByName['createdBy'])) {
|
||||
if (!isDefined(fieldIdByName[fieldName])) {
|
||||
this.logger.log(
|
||||
`CreatedBy field not found in object metadata, skipping injection`,
|
||||
`${fieldName} field not found in object metadata, skipping injection`,
|
||||
);
|
||||
|
||||
return records;
|
||||
@@ -78,33 +132,35 @@ export class CreatedByFromAuthContextService {
|
||||
|
||||
const clonedRecords = structuredClone(records);
|
||||
|
||||
const createdBy = await this.buildCreatedBy(authContext);
|
||||
const actorMetadata = await this.buildActorMetadata(authContext);
|
||||
|
||||
if (Array.isArray(clonedRecords)) {
|
||||
for (const datum of clonedRecords) {
|
||||
this.injectCreatedByToRecord(createdBy, datum);
|
||||
}
|
||||
} else {
|
||||
this.injectCreatedByToRecord(createdBy, clonedRecords);
|
||||
for (const record of clonedRecords) {
|
||||
this.injectActorToRecord(actorMetadata, record, fieldName);
|
||||
}
|
||||
|
||||
return clonedRecords;
|
||||
}
|
||||
|
||||
private injectCreatedByToRecord(
|
||||
createdBy: ActorMetadata,
|
||||
record: CreateInput,
|
||||
private injectActorToRecord(
|
||||
actorMetadata: ActorMetadata,
|
||||
record: RecordInput,
|
||||
fieldName: 'createdBy' | 'updatedBy',
|
||||
) {
|
||||
// Front-end can fill the source field
|
||||
if (createdBy && (!record.createdBy || !record.createdBy?.name)) {
|
||||
record.createdBy = {
|
||||
...createdBy,
|
||||
source: record.createdBy?.source ?? createdBy.source,
|
||||
};
|
||||
const existingValue = record[fieldName] as ActorMetadata | undefined;
|
||||
|
||||
if (fieldName === 'createdBy') {
|
||||
if (actorMetadata && (!existingValue || !existingValue.name)) {
|
||||
record[fieldName] = {
|
||||
...actorMetadata,
|
||||
source: existingValue?.source ?? actorMetadata.source,
|
||||
};
|
||||
}
|
||||
} else {
|
||||
record[fieldName] = actorMetadata;
|
||||
}
|
||||
}
|
||||
|
||||
private async buildCreatedBy(
|
||||
private async buildActorMetadata(
|
||||
authContext: AuthContext,
|
||||
): Promise<ActorMetadata> {
|
||||
const { workspace, user, apiKey, application } = authContext;
|
||||
@@ -151,7 +207,7 @@ export class CreatedByFromAuthContextService {
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
'Unable to build createdBy metadata - no valid actor information found in auth context',
|
||||
'Unable to build actor metadata - no valid actor information found in auth context',
|
||||
);
|
||||
}
|
||||
}
|
||||
+7
-4
@@ -124,14 +124,17 @@ export class CreateRecordService {
|
||||
flatFieldMetadataMaps,
|
||||
);
|
||||
|
||||
const actorMetadata = params.createdBy ?? {
|
||||
source: FieldActorSource.WORKFLOW,
|
||||
name: 'Workflow',
|
||||
};
|
||||
|
||||
const insertResult = await repository.insert(
|
||||
{
|
||||
...transformedObjectRecord,
|
||||
position,
|
||||
createdBy: params.createdBy ?? {
|
||||
source: FieldActorSource.WORKFLOW,
|
||||
name: 'Workflow',
|
||||
},
|
||||
createdBy: actorMetadata,
|
||||
updatedBy: actorMetadata,
|
||||
},
|
||||
undefined,
|
||||
selectedColumns,
|
||||
|
||||
+8
@@ -1,6 +1,7 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
|
||||
import deepEqual from 'deep-equal';
|
||||
import { FieldActorSource } from 'twenty-shared/types';
|
||||
import { isDefined, isValidUuid } from 'twenty-shared/utils';
|
||||
import { canObjectBeManagedByWorkflow } from 'twenty-shared/workflow';
|
||||
|
||||
@@ -34,6 +35,7 @@ export class UpdateRecordService {
|
||||
fieldsToUpdate,
|
||||
workspaceId,
|
||||
rolePermissionConfig,
|
||||
updatedBy,
|
||||
} = params;
|
||||
|
||||
if (!workspaceId) {
|
||||
@@ -161,6 +163,12 @@ export class UpdateRecordService {
|
||||
objectRecordId,
|
||||
{
|
||||
...transformedObjectRecord,
|
||||
updatedBy: updatedBy ?? {
|
||||
source: FieldActorSource.WORKFLOW,
|
||||
name: 'Workflow',
|
||||
workspaceMemberId: null,
|
||||
context: {},
|
||||
},
|
||||
},
|
||||
undefined,
|
||||
selectedColumns,
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import { type ActorMetadata } from 'twenty-shared/types';
|
||||
|
||||
import { type RecordCrudExecutionContext } from './record-crud-execution-context.type';
|
||||
|
||||
export type CreateRecordExecutionContext = RecordCrudExecutionContext & {
|
||||
createdBy?: ActorMetadata;
|
||||
};
|
||||
+2
-4
@@ -1,7 +1,5 @@
|
||||
import {
|
||||
type CreateRecordExecutionContext,
|
||||
type RecordCrudExecutionContext,
|
||||
} from './execution-context.type';
|
||||
import { type CreateRecordExecutionContext } from './create-record-execution-context.type';
|
||||
import { type RecordCrudExecutionContext } from './record-crud-execution-context.type';
|
||||
import { type CreateRecordInput } from './record-crud-input.type';
|
||||
|
||||
export type CreateRecordParams = CreateRecordInput &
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { type RecordCrudExecutionContext } from './execution-context.type';
|
||||
import { type RecordCrudExecutionContext } from './record-crud-execution-context.type';
|
||||
import { type DeleteRecordInput } from './record-crud-input.type';
|
||||
|
||||
export type DeleteRecordParams = DeleteRecordInput &
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ import {
|
||||
type ObjectRecordOrderBy,
|
||||
} from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
|
||||
|
||||
import { type RecordCrudExecutionContext } from './execution-context.type';
|
||||
import { type RecordCrudExecutionContext } from './record-crud-execution-context.type';
|
||||
import { type FindRecordsInput } from './record-crud-input.type';
|
||||
|
||||
export type FindRecordsParams = FindRecordsInput &
|
||||
|
||||
-6
@@ -1,12 +1,6 @@
|
||||
import { type ActorMetadata } from 'twenty-shared/types';
|
||||
|
||||
import { type RolePermissionConfig } from 'src/engine/twenty-orm/types/role-permission-config';
|
||||
|
||||
export type RecordCrudExecutionContext = {
|
||||
workspaceId: string;
|
||||
rolePermissionConfig?: RolePermissionConfig;
|
||||
};
|
||||
|
||||
export type CreateRecordExecutionContext = RecordCrudExecutionContext & {
|
||||
createdBy?: ActorMetadata;
|
||||
};
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import { type ActorMetadata } from 'twenty-shared/types';
|
||||
|
||||
import { type RecordCrudExecutionContext } from './record-crud-execution-context.type';
|
||||
|
||||
export type UpdateRecordExecutionContext = RecordCrudExecutionContext & {
|
||||
updatedBy?: ActorMetadata;
|
||||
};
|
||||
+3
-2
@@ -1,4 +1,5 @@
|
||||
import { type RecordCrudExecutionContext } from './execution-context.type';
|
||||
import { type UpdateRecordInput } from './record-crud-input.type';
|
||||
import { type UpdateRecordExecutionContext } from './update-record-execution-context.type';
|
||||
|
||||
export type UpdateRecordParams = UpdateRecordInput & RecordCrudExecutionContext;
|
||||
export type UpdateRecordParams = UpdateRecordInput &
|
||||
UpdateRecordExecutionContext;
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { type RecordCrudExecutionContext } from './execution-context.type';
|
||||
import { type RecordCrudExecutionContext } from './record-crud-execution-context.type';
|
||||
import { type UpsertRecordInput } from './record-crud-input.type';
|
||||
|
||||
export type UpsertRecordParams = UpsertRecordInput & RecordCrudExecutionContext;
|
||||
|
||||
+37
@@ -244,6 +244,42 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({
|
||||
applicationId: applicationId ?? null,
|
||||
};
|
||||
|
||||
const updatedByFieldId = v4();
|
||||
const updatedByField: FlatFieldMetadata<FieldMetadataType.ACTOR> = {
|
||||
type: FieldMetadataType.ACTOR,
|
||||
id: updatedByFieldId,
|
||||
viewFieldIds: [],
|
||||
mainGroupByFieldMetadataViewIds: [],
|
||||
kanbanAggregateOperationViewIds: [],
|
||||
calendarViewIds: [],
|
||||
isLabelSyncedWithName: false,
|
||||
isUnique: false,
|
||||
objectMetadataId,
|
||||
universalIdentifier: updatedByFieldId,
|
||||
workspaceId,
|
||||
standardId: CUSTOM_OBJECT_STANDARD_FIELD_IDS.updatedBy,
|
||||
name: 'updatedBy',
|
||||
label: 'Updated by',
|
||||
icon: 'IconUserCircle',
|
||||
description: 'The workspace member who last updated the record',
|
||||
isNullable: false,
|
||||
isActive: true,
|
||||
isCustom: false,
|
||||
isSystem: false,
|
||||
isUIReadOnly: true,
|
||||
defaultValue: { name: "''", source: "'MANUAL'" },
|
||||
viewFilterIds: [],
|
||||
createdAt,
|
||||
updatedAt: createdAt,
|
||||
options: null,
|
||||
standardOverrides: null,
|
||||
relationTargetFieldMetadataId: null,
|
||||
relationTargetObjectMetadataId: null,
|
||||
settings: null,
|
||||
morphId: null,
|
||||
applicationId: applicationId ?? null,
|
||||
};
|
||||
|
||||
const positionFieldId = v4();
|
||||
const positionField: FlatFieldMetadata<FieldMetadataType.POSITION> = {
|
||||
type: FieldMetadataType.POSITION,
|
||||
@@ -327,6 +363,7 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({
|
||||
nameField,
|
||||
createdAtField,
|
||||
updatedAtField,
|
||||
updatedByField,
|
||||
deletedAtField,
|
||||
createdByField,
|
||||
positionField,
|
||||
|
||||
@@ -69,6 +69,16 @@ export class CustomWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
createdBy: ActorMetadata;
|
||||
|
||||
@WorkspaceField({
|
||||
standardId: CUSTOM_OBJECT_STANDARD_FIELD_IDS.updatedBy,
|
||||
type: FieldMetadataType.ACTOR,
|
||||
label: msg`Updated by`,
|
||||
icon: 'IconUserCircle',
|
||||
description: msg`The workspace member who last updated the record`,
|
||||
})
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
updatedBy: ActorMetadata;
|
||||
|
||||
@WorkspaceRelation({
|
||||
standardId: CUSTOM_OBJECT_STANDARD_FIELD_IDS.noteTargets,
|
||||
label: msg`Notes`,
|
||||
|
||||
@@ -2,6 +2,7 @@ import { isPlainObject } from '@nestjs/common/utils/shared.utils';
|
||||
|
||||
import { isNull } from '@sniptt/guards';
|
||||
import {
|
||||
FieldActorSource,
|
||||
FieldMetadataType,
|
||||
compositeTypeDefinitions,
|
||||
} from 'twenty-shared/types';
|
||||
@@ -157,6 +158,13 @@ export function formatResult<T>(
|
||||
: value;
|
||||
}
|
||||
|
||||
// After assembling composite fields, handle those with missing required subfields
|
||||
handleEmptyCompositeFields(
|
||||
newData,
|
||||
flatObjectMetadata,
|
||||
flatFieldMetadataMaps,
|
||||
);
|
||||
|
||||
const fieldMetadataItemsOfTypeDateOnly = getFlatFieldsFromFlatObjectMetadata(
|
||||
flatObjectMetadata,
|
||||
flatFieldMetadataMaps,
|
||||
@@ -250,3 +258,85 @@ function transformCompositeFieldNullValue(
|
||||
] ?? value
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles composite fields with missing required subfields.
|
||||
* - For nullable fields: sets to null if all required subfields are null
|
||||
* - For non-nullable fields: provides a default value to prevent GraphQL errors
|
||||
*
|
||||
* This handles existing records that were created before the field was added
|
||||
* or records with incomplete data.
|
||||
*/
|
||||
function handleEmptyCompositeFields(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
data: Record<string, any>,
|
||||
flatObjectMetadata: FlatObjectMetadata,
|
||||
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
|
||||
) {
|
||||
const compositeFieldMetadataCollection = getCompositeFieldMetadataCollection(
|
||||
flatObjectMetadata,
|
||||
flatFieldMetadataMaps,
|
||||
);
|
||||
|
||||
for (const fieldMetadata of compositeFieldMetadataCollection) {
|
||||
const fieldValue = data[fieldMetadata.name];
|
||||
|
||||
if (!isDefined(fieldValue) || !isPlainObject(fieldValue)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const compositeType = compositeTypeDefinitions.get(fieldMetadata.type);
|
||||
|
||||
if (!compositeType) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const typedFieldValue = fieldValue as Record<string, any>;
|
||||
|
||||
// Check if all required properties are null/undefined
|
||||
const requiredProperties = compositeType.properties.filter(
|
||||
(prop) => prop.isRequired,
|
||||
);
|
||||
|
||||
const allRequiredPropertiesAreNull = requiredProperties.every(
|
||||
(prop) =>
|
||||
!isDefined(typedFieldValue[prop.name]) ||
|
||||
isNull(typedFieldValue[prop.name]),
|
||||
);
|
||||
|
||||
if (allRequiredPropertiesAreNull && requiredProperties.length > 0) {
|
||||
if (fieldMetadata.isNullable) {
|
||||
// Field is nullable, set to null
|
||||
data[fieldMetadata.name] = null;
|
||||
} else {
|
||||
// Field is non-nullable, provide a default value
|
||||
data[fieldMetadata.name] = getDefaultCompositeFieldValue(
|
||||
fieldMetadata.type,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a default value for non-nullable composite fields.
|
||||
*/
|
||||
function getDefaultCompositeFieldValue(
|
||||
fieldType: FieldMetadataType,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
): Record<string, any> | null {
|
||||
switch (fieldType) {
|
||||
case FieldMetadataType.ACTOR:
|
||||
return {
|
||||
source: FieldActorSource.MANUAL,
|
||||
name: '',
|
||||
workspaceMemberId: null,
|
||||
context: {},
|
||||
};
|
||||
default:
|
||||
// For other composite types, return null and let GraphQL handle the error
|
||||
// This should be extended as needed for other non-nullable composite fields
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+9
@@ -15,6 +15,9 @@ type AttachmentDataSeed = {
|
||||
createdBySource: string;
|
||||
createdByWorkspaceMemberId: string;
|
||||
createdByName: string;
|
||||
updatedBySource: string;
|
||||
updatedByWorkspaceMemberId: string;
|
||||
updatedByName: string;
|
||||
personId: string | null;
|
||||
companyId: string | null;
|
||||
noteId: string | null;
|
||||
@@ -30,6 +33,9 @@ export const ATTACHMENT_DATA_SEED_COLUMNS: (keyof AttachmentDataSeed)[] = [
|
||||
'createdBySource',
|
||||
'createdByWorkspaceMemberId',
|
||||
'createdByName',
|
||||
'updatedBySource',
|
||||
'updatedByWorkspaceMemberId',
|
||||
'updatedByName',
|
||||
'personId',
|
||||
'companyId',
|
||||
'noteId',
|
||||
@@ -251,6 +257,9 @@ const GENERATE_ATTACHMENT_SEEDS = (): AttachmentDataSeed[] => {
|
||||
createdBySource: FieldActorSource.MANUAL,
|
||||
createdByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
|
||||
createdByName: 'Tim A',
|
||||
updatedBySource: FieldActorSource.MANUAL,
|
||||
updatedByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
|
||||
updatedByName: 'Tim A',
|
||||
personId,
|
||||
companyId,
|
||||
noteId,
|
||||
|
||||
+9
@@ -11,6 +11,9 @@ type CompanyDataSeed = {
|
||||
createdByWorkspaceMemberId: string;
|
||||
createdByName: string;
|
||||
accountOwnerId: string;
|
||||
updatedBySource: string;
|
||||
updatedByWorkspaceMemberId: string;
|
||||
updatedByName: string;
|
||||
position: number;
|
||||
};
|
||||
|
||||
@@ -25,6 +28,9 @@ export const COMPANY_DATA_SEED_COLUMNS: (keyof CompanyDataSeed)[] = [
|
||||
'createdByWorkspaceMemberId',
|
||||
'createdByName',
|
||||
'accountOwnerId',
|
||||
'updatedBySource',
|
||||
'updatedByWorkspaceMemberId',
|
||||
'updatedByName',
|
||||
'position',
|
||||
];
|
||||
|
||||
@@ -8524,6 +8530,9 @@ const COMPANY_DATA_SEEDS_RAW = [
|
||||
export const COMPANY_DATA_SEEDS: CompanyDataSeed[] = COMPANY_DATA_SEEDS_RAW.map(
|
||||
(company, index) => ({
|
||||
...company,
|
||||
updatedBySource: company.createdBySource,
|
||||
updatedByWorkspaceMemberId: company.createdByWorkspaceMemberId,
|
||||
updatedByName: company.createdByName,
|
||||
position: index + 1,
|
||||
}),
|
||||
);
|
||||
|
||||
+15
@@ -9,6 +9,9 @@ type DashboardDataSeed = {
|
||||
createdBySource: string;
|
||||
createdByWorkspaceMemberId: string;
|
||||
createdByName: string;
|
||||
updatedBySource: string;
|
||||
updatedByWorkspaceMemberId: string;
|
||||
updatedByName: string;
|
||||
position: number;
|
||||
};
|
||||
|
||||
@@ -19,6 +22,9 @@ export const DASHBOARD_DATA_SEED_COLUMNS: (keyof DashboardDataSeed)[] = [
|
||||
'createdBySource',
|
||||
'createdByWorkspaceMemberId',
|
||||
'createdByName',
|
||||
'updatedBySource',
|
||||
'updatedByWorkspaceMemberId',
|
||||
'updatedByName',
|
||||
'position',
|
||||
];
|
||||
|
||||
@@ -41,6 +47,9 @@ export const getDashboardDataSeeds = (
|
||||
createdBySource: 'MANUAL',
|
||||
createdByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
|
||||
createdByName: 'Tim Apple',
|
||||
updatedBySource: 'MANUAL',
|
||||
updatedByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
|
||||
updatedByName: 'Tim Apple',
|
||||
position: 0,
|
||||
},
|
||||
{
|
||||
@@ -53,6 +62,9 @@ export const getDashboardDataSeeds = (
|
||||
createdBySource: 'MANUAL',
|
||||
createdByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.JONY,
|
||||
createdByName: 'Jony Ive',
|
||||
updatedBySource: 'MANUAL',
|
||||
updatedByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.JONY,
|
||||
updatedByName: 'Jony Ive',
|
||||
position: 1,
|
||||
},
|
||||
{
|
||||
@@ -62,6 +74,9 @@ export const getDashboardDataSeeds = (
|
||||
createdBySource: 'MANUAL',
|
||||
createdByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.PHIL,
|
||||
createdByName: 'Phil Schiller',
|
||||
updatedBySource: 'MANUAL',
|
||||
updatedByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.PHIL,
|
||||
updatedByName: 'Phil Schiller',
|
||||
position: 2,
|
||||
},
|
||||
];
|
||||
|
||||
+12
@@ -10,6 +10,9 @@ type NoteDataSeed = {
|
||||
createdByWorkspaceMemberId: string;
|
||||
createdByName: string;
|
||||
createdByContext: string | null;
|
||||
updatedBySource: string;
|
||||
updatedByWorkspaceMemberId: string;
|
||||
updatedByName: string;
|
||||
};
|
||||
|
||||
export const NOTE_DATA_SEED_COLUMNS: (keyof NoteDataSeed)[] = [
|
||||
@@ -22,6 +25,9 @@ export const NOTE_DATA_SEED_COLUMNS: (keyof NoteDataSeed)[] = [
|
||||
'createdByWorkspaceMemberId',
|
||||
'createdByName',
|
||||
'createdByContext',
|
||||
'updatedBySource',
|
||||
'updatedByWorkspaceMemberId',
|
||||
'updatedByName',
|
||||
];
|
||||
|
||||
const GENERATE_NOTE_IDS = (): Record<string, string> => {
|
||||
@@ -161,6 +167,9 @@ const GENERATE_NOTE_SEEDS = (): NoteDataSeed[] => {
|
||||
createdByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
|
||||
createdByName: 'Tim A',
|
||||
createdByContext: null,
|
||||
updatedBySource: 'MANUAL',
|
||||
updatedByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
|
||||
updatedByName: 'Tim A',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -191,6 +200,9 @@ const GENERATE_NOTE_SEEDS = (): NoteDataSeed[] => {
|
||||
createdByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
|
||||
createdByName: 'Tim A',
|
||||
createdByContext: null,
|
||||
updatedBySource: 'MANUAL',
|
||||
updatedByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
|
||||
updatedByName: 'Tim A',
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+9
@@ -15,6 +15,9 @@ type OpportunityDataSeed = {
|
||||
createdBySource: string;
|
||||
createdByWorkspaceMemberId: string;
|
||||
createdByName: string;
|
||||
updatedBySource: string;
|
||||
updatedByWorkspaceMemberId: string;
|
||||
updatedByName: string;
|
||||
};
|
||||
|
||||
export const OPPORTUNITY_DATA_SEED_COLUMNS: (keyof OpportunityDataSeed)[] = [
|
||||
@@ -30,6 +33,9 @@ export const OPPORTUNITY_DATA_SEED_COLUMNS: (keyof OpportunityDataSeed)[] = [
|
||||
'createdBySource',
|
||||
'createdByWorkspaceMemberId',
|
||||
'createdByName',
|
||||
'updatedBySource',
|
||||
'updatedByWorkspaceMemberId',
|
||||
'updatedByName',
|
||||
];
|
||||
|
||||
const GENERATE_OPPORTUNITY_IDS = (): Record<string, string> => {
|
||||
@@ -188,6 +194,9 @@ const GENERATE_OPPORTUNITY_SEEDS = (): OpportunityDataSeed[] => {
|
||||
createdBySource: 'MANUAL',
|
||||
createdByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
|
||||
createdByName: 'Tim Cook',
|
||||
updatedBySource: 'MANUAL',
|
||||
updatedByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
|
||||
updatedByName: 'Tim Cook',
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+9
@@ -17,6 +17,9 @@ type PersonDataSeed = {
|
||||
phonesPrimaryPhoneNumber: string;
|
||||
phonesPrimaryPhoneCountryCode: string;
|
||||
phonesPrimaryPhoneCallingCode: string;
|
||||
updatedBySource: string;
|
||||
updatedByWorkspaceMemberId: string;
|
||||
updatedByName: string;
|
||||
position: number;
|
||||
};
|
||||
|
||||
@@ -36,6 +39,9 @@ export const PERSON_DATA_SEED_COLUMNS: (keyof PersonDataSeed)[] = [
|
||||
'phonesPrimaryPhoneNumber',
|
||||
'phonesPrimaryPhoneCountryCode',
|
||||
'phonesPrimaryPhoneCallingCode',
|
||||
'updatedBySource',
|
||||
'updatedByWorkspaceMemberId',
|
||||
'updatedByName',
|
||||
'position',
|
||||
];
|
||||
|
||||
@@ -21650,6 +21656,9 @@ const PERSON_DATA_SEEDS_RAW = [
|
||||
export const PERSON_DATA_SEEDS: PersonDataSeed[] = PERSON_DATA_SEEDS_RAW.map(
|
||||
(person, index) => ({
|
||||
...person,
|
||||
updatedBySource: person.createdBySource,
|
||||
updatedByWorkspaceMemberId: person.createdByWorkspaceMemberId,
|
||||
updatedByName: person.createdByName,
|
||||
position: index + 1,
|
||||
}),
|
||||
);
|
||||
|
||||
+12
@@ -12,6 +12,9 @@ type TaskDataSeed = {
|
||||
createdBySource: string;
|
||||
createdByWorkspaceMemberId: string;
|
||||
createdByName: string;
|
||||
updatedBySource: string;
|
||||
updatedByWorkspaceMemberId: string;
|
||||
updatedByName: string;
|
||||
};
|
||||
|
||||
export const TASK_DATA_SEED_COLUMNS: (keyof TaskDataSeed)[] = [
|
||||
@@ -26,6 +29,9 @@ export const TASK_DATA_SEED_COLUMNS: (keyof TaskDataSeed)[] = [
|
||||
'createdBySource',
|
||||
'createdByWorkspaceMemberId',
|
||||
'createdByName',
|
||||
'updatedBySource',
|
||||
'updatedByWorkspaceMemberId',
|
||||
'updatedByName',
|
||||
];
|
||||
|
||||
// Generate all task IDs
|
||||
@@ -210,6 +216,9 @@ const GENERATE_TASK_SEEDS = (): TaskDataSeed[] => {
|
||||
createdBySource: 'MANUAL',
|
||||
createdByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
|
||||
createdByName: 'Tim A',
|
||||
updatedBySource: 'MANUAL',
|
||||
updatedByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
|
||||
updatedByName: 'Tim A',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -242,6 +251,9 @@ const GENERATE_TASK_SEEDS = (): TaskDataSeed[] => {
|
||||
createdBySource: 'MANUAL',
|
||||
createdByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
|
||||
createdByName: 'Tim A',
|
||||
updatedBySource: 'MANUAL',
|
||||
updatedByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
|
||||
updatedByName: 'Tim A',
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+18
@@ -29,6 +29,9 @@ export const prefillCompanies = async (
|
||||
'createdBySource',
|
||||
'createdByWorkspaceMemberId',
|
||||
'createdByName',
|
||||
'updatedBySource',
|
||||
'updatedByWorkspaceMemberId',
|
||||
'updatedByName',
|
||||
])
|
||||
.orIgnore()
|
||||
.values([
|
||||
@@ -47,6 +50,9 @@ export const prefillCompanies = async (
|
||||
createdBySource: FieldActorSource.SYSTEM,
|
||||
createdByWorkspaceMemberId: null,
|
||||
createdByName: 'System',
|
||||
updatedBySource: FieldActorSource.SYSTEM,
|
||||
updatedByWorkspaceMemberId: null,
|
||||
updatedByName: 'System',
|
||||
},
|
||||
{
|
||||
id: ANTHROPIC_ID,
|
||||
@@ -63,6 +69,9 @@ export const prefillCompanies = async (
|
||||
createdBySource: FieldActorSource.SYSTEM,
|
||||
createdByWorkspaceMemberId: null,
|
||||
createdByName: 'System',
|
||||
updatedBySource: FieldActorSource.SYSTEM,
|
||||
updatedByWorkspaceMemberId: null,
|
||||
updatedByName: 'System',
|
||||
},
|
||||
{
|
||||
id: STRIPE_ID,
|
||||
@@ -79,6 +88,9 @@ export const prefillCompanies = async (
|
||||
createdBySource: FieldActorSource.SYSTEM,
|
||||
createdByWorkspaceMemberId: null,
|
||||
createdByName: 'System',
|
||||
updatedBySource: FieldActorSource.SYSTEM,
|
||||
updatedByWorkspaceMemberId: null,
|
||||
updatedByName: 'System',
|
||||
},
|
||||
{
|
||||
id: FIGMA_ID,
|
||||
@@ -95,6 +107,9 @@ export const prefillCompanies = async (
|
||||
createdBySource: FieldActorSource.SYSTEM,
|
||||
createdByWorkspaceMemberId: null,
|
||||
createdByName: 'System',
|
||||
updatedBySource: FieldActorSource.SYSTEM,
|
||||
updatedByWorkspaceMemberId: null,
|
||||
updatedByName: 'System',
|
||||
},
|
||||
{
|
||||
id: NOTION_ID,
|
||||
@@ -111,6 +126,9 @@ export const prefillCompanies = async (
|
||||
createdBySource: FieldActorSource.SYSTEM,
|
||||
createdByWorkspaceMemberId: null,
|
||||
createdByName: 'System',
|
||||
updatedBySource: FieldActorSource.SYSTEM,
|
||||
updatedByWorkspaceMemberId: null,
|
||||
updatedByName: 'System',
|
||||
},
|
||||
])
|
||||
.returning('*')
|
||||
|
||||
+18
@@ -26,6 +26,9 @@ export const prefillPeople = async (
|
||||
'createdBySource',
|
||||
'createdByWorkspaceMemberId',
|
||||
'createdByName',
|
||||
'updatedBySource',
|
||||
'updatedByWorkspaceMemberId',
|
||||
'updatedByName',
|
||||
'phonesPrimaryPhoneNumber',
|
||||
'phonesPrimaryPhoneCallingCode',
|
||||
'companyId',
|
||||
@@ -43,6 +46,9 @@ export const prefillPeople = async (
|
||||
createdBySource: FieldActorSource.SYSTEM,
|
||||
createdByWorkspaceMemberId: null,
|
||||
createdByName: 'System',
|
||||
updatedBySource: FieldActorSource.SYSTEM,
|
||||
updatedByWorkspaceMemberId: null,
|
||||
updatedByName: 'System',
|
||||
phonesPrimaryPhoneNumber: '123456789',
|
||||
phonesPrimaryPhoneCallingCode: '+1',
|
||||
companyId: AIRBNB_ID,
|
||||
@@ -58,6 +64,9 @@ export const prefillPeople = async (
|
||||
createdBySource: FieldActorSource.SYSTEM,
|
||||
createdByWorkspaceMemberId: null,
|
||||
createdByName: 'System',
|
||||
updatedBySource: FieldActorSource.SYSTEM,
|
||||
updatedByWorkspaceMemberId: null,
|
||||
updatedByName: 'System',
|
||||
phonesPrimaryPhoneNumber: '555123456',
|
||||
phonesPrimaryPhoneCallingCode: '+1',
|
||||
companyId: ANTHROPIC_ID,
|
||||
@@ -73,6 +82,9 @@ export const prefillPeople = async (
|
||||
createdBySource: FieldActorSource.SYSTEM,
|
||||
createdByWorkspaceMemberId: null,
|
||||
createdByName: 'System',
|
||||
updatedBySource: FieldActorSource.SYSTEM,
|
||||
updatedByWorkspaceMemberId: null,
|
||||
updatedByName: 'System',
|
||||
phonesPrimaryPhoneNumber: '987625341',
|
||||
phonesPrimaryPhoneCallingCode: '+1',
|
||||
companyId: STRIPE_ID,
|
||||
@@ -88,6 +100,9 @@ export const prefillPeople = async (
|
||||
createdBySource: FieldActorSource.SYSTEM,
|
||||
createdByWorkspaceMemberId: null,
|
||||
createdByName: 'System',
|
||||
updatedBySource: FieldActorSource.SYSTEM,
|
||||
updatedByWorkspaceMemberId: null,
|
||||
updatedByName: 'System',
|
||||
phonesPrimaryPhoneNumber: '098822619',
|
||||
phonesPrimaryPhoneCallingCode: '+1',
|
||||
companyId: FIGMA_ID,
|
||||
@@ -103,6 +118,9 @@ export const prefillPeople = async (
|
||||
createdBySource: FieldActorSource.SYSTEM,
|
||||
createdByWorkspaceMemberId: null,
|
||||
createdByName: 'System',
|
||||
updatedBySource: FieldActorSource.SYSTEM,
|
||||
updatedByWorkspaceMemberId: null,
|
||||
updatedByName: 'System',
|
||||
phonesPrimaryPhoneNumber: '882261739',
|
||||
phonesPrimaryPhoneCallingCode: '+1',
|
||||
companyId: NOTION_ID,
|
||||
|
||||
+6
@@ -54,6 +54,9 @@ export const prefillWorkflows = async (
|
||||
'createdByWorkspaceMemberId',
|
||||
'createdByName',
|
||||
'createdByContext',
|
||||
'updatedBySource',
|
||||
'updatedByWorkspaceMemberId',
|
||||
'updatedByName',
|
||||
])
|
||||
.orIgnore()
|
||||
.values([
|
||||
@@ -67,6 +70,9 @@ export const prefillWorkflows = async (
|
||||
createdByWorkspaceMemberId: null,
|
||||
createdByName: 'System',
|
||||
createdByContext: {},
|
||||
updatedBySource: FieldActorSource.SYSTEM,
|
||||
updatedByWorkspaceMemberId: null,
|
||||
updatedByName: 'System',
|
||||
},
|
||||
])
|
||||
.returning('*')
|
||||
|
||||
+17
@@ -54,6 +54,9 @@ export const STANDARD_OBJECTS = {
|
||||
createdBy: {
|
||||
universalIdentifier: ATTACHMENT_STANDARD_FIELD_IDS.createdBy,
|
||||
},
|
||||
updatedBy: {
|
||||
universalIdentifier: ATTACHMENT_STANDARD_FIELD_IDS.updatedBy,
|
||||
},
|
||||
task: { universalIdentifier: ATTACHMENT_STANDARD_FIELD_IDS.task },
|
||||
note: { universalIdentifier: ATTACHMENT_STANDARD_FIELD_IDS.note },
|
||||
person: { universalIdentifier: ATTACHMENT_STANDARD_FIELD_IDS.person },
|
||||
@@ -397,6 +400,7 @@ export const STANDARD_OBJECTS = {
|
||||
},
|
||||
position: { universalIdentifier: COMPANY_STANDARD_FIELD_IDS.position },
|
||||
createdBy: { universalIdentifier: COMPANY_STANDARD_FIELD_IDS.createdBy },
|
||||
updatedBy: { universalIdentifier: COMPANY_STANDARD_FIELD_IDS.updatedBy },
|
||||
people: { universalIdentifier: COMPANY_STANDARD_FIELD_IDS.people },
|
||||
accountOwner: {
|
||||
universalIdentifier: COMPANY_STANDARD_FIELD_IDS.accountOwner,
|
||||
@@ -549,6 +553,9 @@ export const STANDARD_OBJECTS = {
|
||||
createdBy: {
|
||||
universalIdentifier: DASHBOARD_STANDARD_FIELD_IDS.createdBy,
|
||||
},
|
||||
updatedBy: {
|
||||
universalIdentifier: DASHBOARD_STANDARD_FIELD_IDS.updatedBy,
|
||||
},
|
||||
timelineActivities: {
|
||||
universalIdentifier: DASHBOARD_STANDARD_FIELD_IDS.timelineActivities,
|
||||
},
|
||||
@@ -1029,6 +1036,7 @@ export const STANDARD_OBJECTS = {
|
||||
title: { universalIdentifier: NOTE_STANDARD_FIELD_IDS.title },
|
||||
bodyV2: { universalIdentifier: NOTE_STANDARD_FIELD_IDS.bodyV2 },
|
||||
createdBy: { universalIdentifier: NOTE_STANDARD_FIELD_IDS.createdBy },
|
||||
updatedBy: { universalIdentifier: NOTE_STANDARD_FIELD_IDS.updatedBy },
|
||||
noteTargets: { universalIdentifier: NOTE_STANDARD_FIELD_IDS.noteTargets },
|
||||
attachments: { universalIdentifier: NOTE_STANDARD_FIELD_IDS.attachments },
|
||||
timelineActivities: {
|
||||
@@ -1127,6 +1135,9 @@ export const STANDARD_OBJECTS = {
|
||||
createdBy: {
|
||||
universalIdentifier: OPPORTUNITY_STANDARD_FIELD_IDS.createdBy,
|
||||
},
|
||||
updatedBy: {
|
||||
universalIdentifier: OPPORTUNITY_STANDARD_FIELD_IDS.updatedBy,
|
||||
},
|
||||
pointOfContact: {
|
||||
universalIdentifier: OPPORTUNITY_STANDARD_FIELD_IDS.pointOfContact,
|
||||
},
|
||||
@@ -1255,6 +1266,7 @@ export const STANDARD_OBJECTS = {
|
||||
avatarUrl: { universalIdentifier: PERSON_STANDARD_FIELD_IDS.avatarUrl },
|
||||
position: { universalIdentifier: PERSON_STANDARD_FIELD_IDS.position },
|
||||
createdBy: { universalIdentifier: PERSON_STANDARD_FIELD_IDS.createdBy },
|
||||
updatedBy: { universalIdentifier: PERSON_STANDARD_FIELD_IDS.updatedBy },
|
||||
company: { universalIdentifier: PERSON_STANDARD_FIELD_IDS.company },
|
||||
pointOfContactForOpportunities: {
|
||||
universalIdentifier:
|
||||
@@ -1352,6 +1364,7 @@ export const STANDARD_OBJECTS = {
|
||||
dueAt: { universalIdentifier: TASK_STANDARD_FIELD_IDS.dueAt },
|
||||
status: { universalIdentifier: TASK_STANDARD_FIELD_IDS.status },
|
||||
createdBy: { universalIdentifier: TASK_STANDARD_FIELD_IDS.createdBy },
|
||||
updatedBy: { universalIdentifier: TASK_STANDARD_FIELD_IDS.updatedBy },
|
||||
taskTargets: { universalIdentifier: TASK_STANDARD_FIELD_IDS.taskTargets },
|
||||
attachments: { universalIdentifier: TASK_STANDARD_FIELD_IDS.attachments },
|
||||
assignee: { universalIdentifier: TASK_STANDARD_FIELD_IDS.assignee },
|
||||
@@ -1670,6 +1683,7 @@ export const STANDARD_OBJECTS = {
|
||||
universalIdentifier: WORKFLOW_STANDARD_FIELD_IDS.attachments,
|
||||
},
|
||||
createdBy: { universalIdentifier: WORKFLOW_STANDARD_FIELD_IDS.createdBy },
|
||||
updatedBy: { universalIdentifier: WORKFLOW_STANDARD_FIELD_IDS.updatedBy },
|
||||
searchVector: {
|
||||
universalIdentifier: WORKFLOW_STANDARD_FIELD_IDS.searchVector,
|
||||
},
|
||||
@@ -1772,6 +1786,9 @@ export const STANDARD_OBJECTS = {
|
||||
createdBy: {
|
||||
universalIdentifier: WORKFLOW_RUN_STANDARD_FIELD_IDS.createdBy,
|
||||
},
|
||||
updatedBy: {
|
||||
universalIdentifier: WORKFLOW_RUN_STANDARD_FIELD_IDS.updatedBy,
|
||||
},
|
||||
output: { universalIdentifier: WORKFLOW_RUN_STANDARD_FIELD_IDS.output },
|
||||
context: { universalIdentifier: WORKFLOW_RUN_STANDARD_FIELD_IDS.context },
|
||||
state: { universalIdentifier: WORKFLOW_RUN_STANDARD_FIELD_IDS.state },
|
||||
|
||||
+22
@@ -207,6 +207,28 @@ export const buildAttachmentStandardFlatFieldMetadatas = ({
|
||||
twentyStandardApplicationId,
|
||||
now,
|
||||
}),
|
||||
updatedBy: createStandardFieldFlatMetadata({
|
||||
objectName,
|
||||
workspaceId,
|
||||
context: {
|
||||
fieldName: 'updatedBy',
|
||||
type: FieldMetadataType.ACTOR,
|
||||
label: 'Updated by',
|
||||
description: 'The workspace member who last updated the record',
|
||||
icon: 'IconUserCircle',
|
||||
isUIReadOnly: true,
|
||||
isNullable: false,
|
||||
defaultValue: {
|
||||
source: "'MANUAL'",
|
||||
name: "'System'",
|
||||
workspaceMemberId: null,
|
||||
},
|
||||
},
|
||||
standardObjectMetadataRelatedEntityIds,
|
||||
dependencyFlatEntityMaps,
|
||||
twentyStandardApplicationId,
|
||||
now,
|
||||
}),
|
||||
|
||||
// Relation fields
|
||||
task: createStandardRelationFieldFlatMetadata({
|
||||
|
||||
+22
@@ -286,6 +286,28 @@ export const buildCompanyStandardFlatFieldMetadatas = ({
|
||||
twentyStandardApplicationId,
|
||||
now,
|
||||
}),
|
||||
updatedBy: createStandardFieldFlatMetadata({
|
||||
objectName,
|
||||
workspaceId,
|
||||
context: {
|
||||
fieldName: 'updatedBy',
|
||||
type: FieldMetadataType.ACTOR,
|
||||
label: 'Updated by',
|
||||
description: 'The workspace member who last updated the record',
|
||||
icon: 'IconUserCircle',
|
||||
isUIReadOnly: true,
|
||||
isNullable: false,
|
||||
defaultValue: {
|
||||
source: "'MANUAL'",
|
||||
name: "'System'",
|
||||
workspaceMemberId: null,
|
||||
},
|
||||
},
|
||||
standardObjectMetadataRelatedEntityIds,
|
||||
dependencyFlatEntityMaps,
|
||||
twentyStandardApplicationId,
|
||||
now,
|
||||
}),
|
||||
searchVector: createStandardFieldFlatMetadata({
|
||||
objectName,
|
||||
workspaceId,
|
||||
|
||||
+22
@@ -176,6 +176,28 @@ export const buildDashboardStandardFlatFieldMetadatas = ({
|
||||
twentyStandardApplicationId,
|
||||
now,
|
||||
}),
|
||||
updatedBy: createStandardFieldFlatMetadata({
|
||||
objectName,
|
||||
workspaceId,
|
||||
context: {
|
||||
fieldName: 'updatedBy',
|
||||
type: FieldMetadataType.ACTOR,
|
||||
label: 'Updated by',
|
||||
description: 'The workspace member who last updated the record',
|
||||
icon: 'IconUserCircle',
|
||||
isUIReadOnly: true,
|
||||
isNullable: false,
|
||||
defaultValue: {
|
||||
source: "'MANUAL'",
|
||||
name: "'System'",
|
||||
workspaceMemberId: null,
|
||||
},
|
||||
},
|
||||
standardObjectMetadataRelatedEntityIds,
|
||||
dependencyFlatEntityMaps,
|
||||
twentyStandardApplicationId,
|
||||
now,
|
||||
}),
|
||||
searchVector: createStandardFieldFlatMetadata({
|
||||
objectName,
|
||||
workspaceId,
|
||||
|
||||
+22
@@ -181,6 +181,28 @@ export const buildNoteStandardFlatFieldMetadatas = ({
|
||||
twentyStandardApplicationId,
|
||||
now,
|
||||
}),
|
||||
updatedBy: createStandardFieldFlatMetadata({
|
||||
objectName,
|
||||
workspaceId,
|
||||
context: {
|
||||
fieldName: 'updatedBy',
|
||||
type: FieldMetadataType.ACTOR,
|
||||
label: 'Updated by',
|
||||
description: 'The workspace member who last updated the record',
|
||||
icon: 'IconUserCircle',
|
||||
isUIReadOnly: true,
|
||||
isNullable: false,
|
||||
defaultValue: {
|
||||
source: "'MANUAL'",
|
||||
name: "'System'",
|
||||
workspaceMemberId: null,
|
||||
},
|
||||
},
|
||||
standardObjectMetadataRelatedEntityIds,
|
||||
dependencyFlatEntityMaps,
|
||||
twentyStandardApplicationId,
|
||||
now,
|
||||
}),
|
||||
searchVector: createStandardFieldFlatMetadata({
|
||||
objectName,
|
||||
workspaceId,
|
||||
|
||||
+22
@@ -232,6 +232,28 @@ export const buildOpportunityStandardFlatFieldMetadatas = ({
|
||||
twentyStandardApplicationId,
|
||||
now,
|
||||
}),
|
||||
updatedBy: createStandardFieldFlatMetadata({
|
||||
objectName,
|
||||
workspaceId,
|
||||
context: {
|
||||
fieldName: 'updatedBy',
|
||||
type: FieldMetadataType.ACTOR,
|
||||
label: 'Updated by',
|
||||
description: 'The workspace member who last updated the record',
|
||||
icon: 'IconUserCircle',
|
||||
isUIReadOnly: true,
|
||||
isNullable: false,
|
||||
defaultValue: {
|
||||
source: "'MANUAL'",
|
||||
name: "'System'",
|
||||
workspaceMemberId: null,
|
||||
},
|
||||
},
|
||||
standardObjectMetadataRelatedEntityIds,
|
||||
dependencyFlatEntityMaps,
|
||||
twentyStandardApplicationId,
|
||||
now,
|
||||
}),
|
||||
searchVector: createStandardFieldFlatMetadata({
|
||||
objectName,
|
||||
workspaceId,
|
||||
|
||||
+22
@@ -286,6 +286,28 @@ export const buildPersonStandardFlatFieldMetadatas = ({
|
||||
twentyStandardApplicationId,
|
||||
now,
|
||||
}),
|
||||
updatedBy: createStandardFieldFlatMetadata({
|
||||
objectName,
|
||||
workspaceId,
|
||||
context: {
|
||||
fieldName: 'updatedBy',
|
||||
type: FieldMetadataType.ACTOR,
|
||||
label: 'Updated by',
|
||||
description: 'The workspace member who last updated the record',
|
||||
icon: 'IconUserCircle',
|
||||
isUIReadOnly: true,
|
||||
isNullable: false,
|
||||
defaultValue: {
|
||||
source: "'MANUAL'",
|
||||
name: "'System'",
|
||||
workspaceMemberId: null,
|
||||
},
|
||||
},
|
||||
standardObjectMetadataRelatedEntityIds,
|
||||
dependencyFlatEntityMaps,
|
||||
twentyStandardApplicationId,
|
||||
now,
|
||||
}),
|
||||
|
||||
// Relation fields
|
||||
company: createStandardRelationFieldFlatMetadata({
|
||||
|
||||
+22
@@ -225,6 +225,28 @@ export const buildTaskStandardFlatFieldMetadatas = ({
|
||||
twentyStandardApplicationId,
|
||||
now,
|
||||
}),
|
||||
updatedBy: createStandardFieldFlatMetadata({
|
||||
objectName,
|
||||
workspaceId,
|
||||
context: {
|
||||
fieldName: 'updatedBy',
|
||||
type: FieldMetadataType.ACTOR,
|
||||
label: 'Updated by',
|
||||
description: 'The workspace member who last updated the record',
|
||||
icon: 'IconUserCircle',
|
||||
isUIReadOnly: true,
|
||||
isNullable: false,
|
||||
defaultValue: {
|
||||
source: "'MANUAL'",
|
||||
name: "'System'",
|
||||
workspaceMemberId: null,
|
||||
},
|
||||
},
|
||||
standardObjectMetadataRelatedEntityIds,
|
||||
dependencyFlatEntityMaps,
|
||||
twentyStandardApplicationId,
|
||||
now,
|
||||
}),
|
||||
searchVector: createStandardFieldFlatMetadata({
|
||||
objectName,
|
||||
workspaceId,
|
||||
|
||||
+22
@@ -223,6 +223,28 @@ export const buildWorkflowRunStandardFlatFieldMetadatas = ({
|
||||
twentyStandardApplicationId,
|
||||
now,
|
||||
}),
|
||||
updatedBy: createStandardFieldFlatMetadata({
|
||||
objectName,
|
||||
workspaceId,
|
||||
context: {
|
||||
fieldName: 'updatedBy',
|
||||
type: FieldMetadataType.ACTOR,
|
||||
label: 'Updated by',
|
||||
description: 'The workspace member who last updated the record',
|
||||
icon: 'IconUserCircle',
|
||||
isUIReadOnly: true,
|
||||
isNullable: false,
|
||||
defaultValue: {
|
||||
source: "'MANUAL'",
|
||||
name: "'System'",
|
||||
workspaceMemberId: null,
|
||||
},
|
||||
},
|
||||
standardObjectMetadataRelatedEntityIds,
|
||||
dependencyFlatEntityMaps,
|
||||
twentyStandardApplicationId,
|
||||
now,
|
||||
}),
|
||||
state: createStandardFieldFlatMetadata({
|
||||
objectName,
|
||||
workspaceId,
|
||||
|
||||
+22
@@ -200,6 +200,28 @@ export const buildWorkflowStandardFlatFieldMetadatas = ({
|
||||
twentyStandardApplicationId,
|
||||
now,
|
||||
}),
|
||||
updatedBy: createStandardFieldFlatMetadata({
|
||||
objectName,
|
||||
workspaceId,
|
||||
context: {
|
||||
fieldName: 'updatedBy',
|
||||
type: FieldMetadataType.ACTOR,
|
||||
label: 'Updated by',
|
||||
description: 'The workspace member who last updated the record',
|
||||
icon: 'IconUserCircle',
|
||||
isUIReadOnly: true,
|
||||
isNullable: false,
|
||||
defaultValue: {
|
||||
source: "'MANUAL'",
|
||||
name: "'System'",
|
||||
workspaceMemberId: null,
|
||||
},
|
||||
},
|
||||
standardObjectMetadataRelatedEntityIds,
|
||||
dependencyFlatEntityMaps,
|
||||
twentyStandardApplicationId,
|
||||
now,
|
||||
}),
|
||||
searchVector: createStandardFieldFlatMetadata({
|
||||
objectName,
|
||||
workspaceId,
|
||||
|
||||
+10
@@ -35,6 +35,7 @@ export const ATTACHMENT_STANDARD_FIELD_IDS = {
|
||||
type: '20202020-a417-49b8-a40b-f6a7874caa0d',
|
||||
fileCategory: '20202020-8c3f-4d9e-9a1b-2e5f7a8c9d0e',
|
||||
createdBy: '395be3bd-a5c9-463d-aafe-9bc3bbec3f15',
|
||||
updatedBy: '376239d1-3e65-4cb6-b5d8-e0917d43cc93',
|
||||
author: '20202020-6501-4ac5-a4ef-b2f8522ef6cd',
|
||||
activity: '20202020-b569-481b-a13f-9b94e47e54fe',
|
||||
task: '20202020-51e5-4621-9cf8-215487951c4b',
|
||||
@@ -128,6 +129,7 @@ export const COMPANY_STANDARD_FIELD_IDS = {
|
||||
idealCustomerProfile: '20202020-ba6b-438a-8213-2c5ba28d76a2',
|
||||
position: '20202020-9b4e-462b-991d-a0ee33326454',
|
||||
createdBy: '20202020-fabc-451d-ab7d-412170916baa',
|
||||
updatedBy: '7444022e-b38f-4d4f-801b-cd664abc4834',
|
||||
people: '20202020-3213-4ddf-9494-6422bcff8d7c',
|
||||
accountOwner: '20202020-95b8-4e10-9881-edb5d4765f9d',
|
||||
// TODO: check if activityTargets field can be deleted
|
||||
@@ -280,6 +282,7 @@ export const NOTE_STANDARD_FIELD_IDS = {
|
||||
body: '20202020-e63d-4e70-95be-a78cd9abe7ef',
|
||||
bodyV2: '20202020-a7bb-4d94-be51-8f25181502c8',
|
||||
createdBy: '20202020-0d79-4e21-ab77-5a394eff97be',
|
||||
updatedBy: '9b446e89-2484-4044-a3b5-420f6b578c0c',
|
||||
noteTargets: '20202020-1f25-43fe-8b00-af212fdde823',
|
||||
attachments: '20202020-4986-4c92-bf19-39934b149b16',
|
||||
timelineActivities: '20202020-7030-42f8-929c-1a57b25d6bce',
|
||||
@@ -303,6 +306,7 @@ export const OPPORTUNITY_STANDARD_FIELD_IDS = {
|
||||
stage: '20202020-6f76-477d-8551-28cd65b2b4b9',
|
||||
position: '20202020-806d-493a-bbc6-6313e62958e2',
|
||||
createdBy: '20202020-a63e-4a62-8e63-42a51828f831',
|
||||
updatedBy: '3c8a6095-3f64-4e81-a59e-66c2bd181e11',
|
||||
pointOfContact: '20202020-8dfb-42fc-92b6-01afb759ed16',
|
||||
company: '20202020-cbac-457e-b565-adece5fc815f',
|
||||
favorites: '20202020-a1c2-4500-aaae-83ba8a0e827a',
|
||||
@@ -328,6 +332,7 @@ export const PERSON_STANDARD_FIELD_IDS = {
|
||||
avatarUrl: '20202020-b8a6-40df-961c-373dc5d2ec21',
|
||||
position: '20202020-fcd5-4231-aff5-fff583eaa0b1',
|
||||
createdBy: '20202020-f6ab-4d98-af24-a3d5b664148a',
|
||||
updatedBy: 'e9e0dd35-184c-4742-84da-afadf45ce59a',
|
||||
company: '20202020-e2f3-448e-b34c-2d625f0025fd',
|
||||
pointOfContactForOpportunities: '20202020-911b-4a7d-b67b-918aa9a5b33a',
|
||||
// TODO: check if activityTargets field can be deleted
|
||||
@@ -350,6 +355,7 @@ export const TASK_STANDARD_FIELD_IDS = {
|
||||
dueAt: '20202020-fd99-40da-951b-4cb9a352fce3',
|
||||
status: '20202020-70bc-48f9-89c5-6aa730b151e0',
|
||||
createdBy: '20202020-1a04-48ab-a567-576965ae5387',
|
||||
updatedBy: '9e8bf518-f4ab-433e-9674-efb75fba2802',
|
||||
taskTargets: '20202020-de9c-4d0e-a452-713d4a3e5fc7',
|
||||
attachments: '20202020-794d-4783-a8ff-cecdb15be139',
|
||||
assignee: '20202020-065a-4f42-a906-e20422c1753f',
|
||||
@@ -449,6 +455,7 @@ export const WORKFLOW_STANDARD_FIELD_IDS = {
|
||||
timelineActivities: '20202020-906e-486a-a798-131a5f081faf',
|
||||
attachments: '20202020-4a8c-4e2d-9b1c-7e5f3a2b4c6d',
|
||||
createdBy: '20202020-6007-401a-8aa5-e6f48581a6f3',
|
||||
updatedBy: '3559831e-caf2-4eb5-9db1-b47bf968c774',
|
||||
searchVector: '20202020-535d-4ffa-b7f3-4fa0d5da1b7a',
|
||||
} as const;
|
||||
|
||||
@@ -462,6 +469,7 @@ export const WORKFLOW_RUN_STANDARD_FIELD_IDS = {
|
||||
status: '20202020-6b3e-4f9c-8c2b-2e5b8e6d6f3b',
|
||||
position: '20202020-7802-4c40-ae89-1f506fe3365c',
|
||||
createdBy: '20202020-6007-401a-8aa5-e6f38581a6f3',
|
||||
updatedBy: '730dc1c9-34f5-4c22-84a6-bcb55b7604e2',
|
||||
output: '20202020-7be4-4db2-8ac6-3ff0d740843d',
|
||||
context: '20202020-189c-478a-b867-d72feaf5926a',
|
||||
state: '20202020-611f-45f3-9cde-d64927e8ec57',
|
||||
@@ -516,6 +524,7 @@ export const CUSTOM_OBJECT_STANDARD_FIELD_IDS = {
|
||||
name: '20202020-ba07-4ffd-ba63-009491f5749c',
|
||||
position: '20202020-c2bd-4e16-bb9a-c8b0411bf49d',
|
||||
createdBy: '20202020-be0e-4971-865b-32ca87cbb315',
|
||||
updatedBy: 'd047ccb4-9469-4514-a982-29c4ae49317d',
|
||||
// TODO: check if activityTargets field can be deleted
|
||||
activityTargets: '20202020-7f42-40ae-b96c-c8a61acc83bf',
|
||||
noteTargets: '20202020-01fd-4f37-99dc-9427a444018a',
|
||||
@@ -531,6 +540,7 @@ export const DASHBOARD_STANDARD_FIELD_IDS = {
|
||||
position: '20202020-38af-409b-95f0-7f08aa5f420f',
|
||||
pageLayoutId: '20202020-bb53-4648-aa36-1d9d54e6f7f2',
|
||||
createdBy: '20202020-ff32-4fa1-b7ad-407cc6aa0734',
|
||||
updatedBy: '53ee42e7-f157-42b5-b278-a5fa9b378307',
|
||||
timelineActivities: '20202020-9b0c-5d6e-7f8a-9b0c1d2e3f4a',
|
||||
favorites: '20202020-f032-478f-88fa-6426ff6f1e4c',
|
||||
attachments: '20202020-bf6f-4220-8c55-2764f1175870',
|
||||
|
||||
+10
@@ -148,6 +148,16 @@ export class AttachmentWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
createdBy: ActorMetadata;
|
||||
|
||||
@WorkspaceField({
|
||||
standardId: ATTACHMENT_STANDARD_FIELD_IDS.updatedBy,
|
||||
type: FieldMetadataType.ACTOR,
|
||||
label: msg`Updated by`,
|
||||
icon: 'IconUserCircle',
|
||||
description: msg`The workspace member who last updated the record`,
|
||||
})
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
updatedBy: ActorMetadata;
|
||||
|
||||
@WorkspaceRelation({
|
||||
standardId: ATTACHMENT_STANDARD_FIELD_IDS.author,
|
||||
type: RelationType.MANY_TO_ONE,
|
||||
|
||||
+10
@@ -168,6 +168,16 @@ export class CompanyWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
createdBy: ActorMetadata;
|
||||
|
||||
@WorkspaceField({
|
||||
standardId: COMPANY_STANDARD_FIELD_IDS.updatedBy,
|
||||
type: FieldMetadataType.ACTOR,
|
||||
label: msg`Updated by`,
|
||||
icon: 'IconUserCircle',
|
||||
description: msg`The workspace member who last updated the record`,
|
||||
})
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
updatedBy: ActorMetadata;
|
||||
|
||||
// Relations
|
||||
@WorkspaceRelation({
|
||||
standardId: COMPANY_STANDARD_FIELD_IDS.people,
|
||||
|
||||
+10
@@ -91,6 +91,16 @@ export class DashboardWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
createdBy: ActorMetadata;
|
||||
|
||||
@WorkspaceField({
|
||||
standardId: DASHBOARD_STANDARD_FIELD_IDS.updatedBy,
|
||||
type: FieldMetadataType.ACTOR,
|
||||
label: msg`Updated by`,
|
||||
icon: 'IconUserCircle',
|
||||
description: msg`The workspace member who last updated the record`,
|
||||
})
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
updatedBy: ActorMetadata;
|
||||
|
||||
@WorkspaceRelation({
|
||||
standardId: DASHBOARD_STANDARD_FIELD_IDS.timelineActivities,
|
||||
type: RelationType.ONE_TO_MANY,
|
||||
|
||||
@@ -94,6 +94,16 @@ export class NoteWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
createdBy: ActorMetadata;
|
||||
|
||||
@WorkspaceField({
|
||||
standardId: NOTE_STANDARD_FIELD_IDS.updatedBy,
|
||||
type: FieldMetadataType.ACTOR,
|
||||
label: msg`Updated by`,
|
||||
icon: 'IconUserCircle',
|
||||
description: msg`The workspace member who last updated the record`,
|
||||
})
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
updatedBy: ActorMetadata;
|
||||
|
||||
@WorkspaceRelation({
|
||||
standardId: NOTE_STANDARD_FIELD_IDS.noteTargets,
|
||||
label: msg`Relations`,
|
||||
|
||||
+10
@@ -130,6 +130,16 @@ export class OpportunityWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
createdBy: ActorMetadata;
|
||||
|
||||
@WorkspaceField({
|
||||
standardId: OPPORTUNITY_STANDARD_FIELD_IDS.updatedBy,
|
||||
type: FieldMetadataType.ACTOR,
|
||||
label: msg`Updated by`,
|
||||
icon: 'IconUserCircle',
|
||||
description: msg`The workspace member who last updated the record`,
|
||||
})
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
updatedBy: ActorMetadata;
|
||||
|
||||
@WorkspaceRelation({
|
||||
standardId: OPPORTUNITY_STANDARD_FIELD_IDS.pointOfContact,
|
||||
type: RelationType.MANY_TO_ONE,
|
||||
|
||||
@@ -195,6 +195,16 @@ export class PersonWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
createdBy: ActorMetadata;
|
||||
|
||||
@WorkspaceField({
|
||||
standardId: PERSON_STANDARD_FIELD_IDS.updatedBy,
|
||||
type: FieldMetadataType.ACTOR,
|
||||
label: msg`Updated by`,
|
||||
icon: 'IconUserCircle',
|
||||
description: msg`The workspace member who last updated the record`,
|
||||
})
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
updatedBy: ActorMetadata;
|
||||
|
||||
// Relations
|
||||
@WorkspaceRelation({
|
||||
standardId: PERSON_STANDARD_FIELD_IDS.company,
|
||||
|
||||
@@ -133,6 +133,16 @@ export class TaskWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
createdBy: ActorMetadata;
|
||||
|
||||
@WorkspaceField({
|
||||
standardId: TASK_STANDARD_FIELD_IDS.updatedBy,
|
||||
type: FieldMetadataType.ACTOR,
|
||||
label: msg`Updated by`,
|
||||
icon: 'IconUserCircle',
|
||||
description: msg`The workspace member who last updated the record`,
|
||||
})
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
updatedBy: ActorMetadata;
|
||||
|
||||
@WorkspaceRelation({
|
||||
standardId: TASK_STANDARD_FIELD_IDS.taskTargets,
|
||||
label: msg`Relations`,
|
||||
|
||||
+10
@@ -204,6 +204,16 @@ export class WorkflowRunWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
createdBy: ActorMetadata;
|
||||
|
||||
@WorkspaceField({
|
||||
standardId: WORKFLOW_RUN_STANDARD_FIELD_IDS.updatedBy,
|
||||
type: FieldMetadataType.ACTOR,
|
||||
label: msg`Updated by`,
|
||||
icon: 'IconUserCircle',
|
||||
description: msg`The workspace member who last updated the record`,
|
||||
})
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
updatedBy: ActorMetadata;
|
||||
|
||||
@WorkspaceField({
|
||||
standardId: WORKFLOW_RUN_STANDARD_FIELD_IDS.state,
|
||||
type: FieldMetadataType.RAW_JSON,
|
||||
|
||||
+10
@@ -220,4 +220,14 @@ export class WorkflowWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
})
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
createdBy: ActorMetadata;
|
||||
|
||||
@WorkspaceField({
|
||||
standardId: WORKFLOW_STANDARD_FIELD_IDS.updatedBy,
|
||||
type: FieldMetadataType.ACTOR,
|
||||
label: msg`Updated by`,
|
||||
icon: 'IconUserCircle',
|
||||
description: msg`The workspace member who last updated the record`,
|
||||
})
|
||||
@WorkspaceIsFieldUIReadOnly()
|
||||
updatedBy: ActorMetadata;
|
||||
}
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
import { type ActorMetadata, FieldActorSource } from 'twenty-shared/types';
|
||||
|
||||
import { type WorkflowExecutionContext } from 'src/modules/workflow/workflow-executor/types/workflow-execution-context.type';
|
||||
|
||||
export const buildWorkflowActorMetadata = (
|
||||
executionContext: WorkflowExecutionContext,
|
||||
): ActorMetadata => {
|
||||
if (executionContext.isActingOnBehalfOfUser) {
|
||||
return executionContext.initiator;
|
||||
}
|
||||
|
||||
return {
|
||||
source: FieldActorSource.WORKFLOW,
|
||||
name: 'Workflow',
|
||||
workspaceMemberId: null,
|
||||
context: {},
|
||||
};
|
||||
};
|
||||
+2
-18
@@ -1,6 +1,5 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { type ActorMetadata, FieldActorSource } from 'twenty-shared/types';
|
||||
import { resolveInput } from 'twenty-shared/utils';
|
||||
|
||||
import { type WorkflowAction } from 'src/modules/workflow/workflow-executor/interfaces/workflow-action.interface';
|
||||
@@ -14,7 +13,7 @@ import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/work
|
||||
import { WorkflowExecutionContextService } from 'src/modules/workflow/workflow-executor/services/workflow-execution-context.service';
|
||||
import { type WorkflowActionInput } from 'src/modules/workflow/workflow-executor/types/workflow-action-input';
|
||||
import { type WorkflowActionOutput } from 'src/modules/workflow/workflow-executor/types/workflow-action-output.type';
|
||||
import { type WorkflowExecutionContext } from 'src/modules/workflow/workflow-executor/types/workflow-execution-context.type';
|
||||
import { buildWorkflowActorMetadata } from 'src/modules/workflow/workflow-executor/utils/build-workflow-actor-metadata.util';
|
||||
import { findStepOrThrow } from 'src/modules/workflow/workflow-executor/utils/find-step-or-throw.util';
|
||||
import { resolveRichTextFieldsInRecord } from 'src/modules/workflow/workflow-executor/utils/resolve-rich-text-fields-in-record.util';
|
||||
import { type WorkflowCreateRecordActionInput } from 'src/modules/workflow/workflow-executor/workflow-actions/record-crud/types/workflow-record-crud-action-input.type';
|
||||
@@ -65,7 +64,7 @@ export class CreateRecordWorkflowAction implements WorkflowAction {
|
||||
const executionContext =
|
||||
await this.workflowExecutionContextService.getExecutionContext(runInfo);
|
||||
|
||||
const createdBy = this.buildCreatedByActor(executionContext);
|
||||
const createdBy = buildWorkflowActorMetadata(executionContext);
|
||||
|
||||
const toolOutput = await this.createRecordService.execute({
|
||||
objectName: workflowActionInput.objectName,
|
||||
@@ -86,19 +85,4 @@ export class CreateRecordWorkflowAction implements WorkflowAction {
|
||||
result: toolOutput.result,
|
||||
};
|
||||
}
|
||||
|
||||
private buildCreatedByActor(
|
||||
executionContext: WorkflowExecutionContext,
|
||||
): ActorMetadata {
|
||||
if (executionContext.isActingOnBehalfOfUser) {
|
||||
return executionContext.initiator;
|
||||
}
|
||||
|
||||
return {
|
||||
source: FieldActorSource.WORKFLOW,
|
||||
name: 'Workflow',
|
||||
workspaceMemberId: null,
|
||||
context: {},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -17,6 +17,7 @@ import {
|
||||
import { WorkflowExecutionContextService } from 'src/modules/workflow/workflow-executor/services/workflow-execution-context.service';
|
||||
import { type WorkflowActionInput } from 'src/modules/workflow/workflow-executor/types/workflow-action-input';
|
||||
import { type WorkflowActionOutput } from 'src/modules/workflow/workflow-executor/types/workflow-action-output.type';
|
||||
import { buildWorkflowActorMetadata } from 'src/modules/workflow/workflow-executor/utils/build-workflow-actor-metadata.util';
|
||||
import { findStepOrThrow } from 'src/modules/workflow/workflow-executor/utils/find-step-or-throw.util';
|
||||
import { resolveRichTextFieldsInRecord } from 'src/modules/workflow/workflow-executor/utils/resolve-rich-text-fields-in-record.util';
|
||||
import { isWorkflowUpdateRecordAction } from 'src/modules/workflow/workflow-executor/workflow-actions/record-crud/guards/is-workflow-update-record-action.guard';
|
||||
@@ -86,12 +87,15 @@ export class UpdateRecordWorkflowAction implements WorkflowAction {
|
||||
const executionContext =
|
||||
await this.workflowExecutionContextService.getExecutionContext(runInfo);
|
||||
|
||||
const updatedBy = buildWorkflowActorMetadata(executionContext);
|
||||
|
||||
const toolOutput = await this.updateRecordService.execute({
|
||||
objectName: workflowActionInput.objectName,
|
||||
objectRecordId: workflowActionInput.objectRecordId,
|
||||
objectRecord: workflowActionInput.objectRecord,
|
||||
fieldsToUpdate: workflowActionInput.fieldsToUpdate,
|
||||
workspaceId,
|
||||
updatedBy,
|
||||
rolePermissionConfig: executionContext.rolePermissionConfig,
|
||||
});
|
||||
|
||||
|
||||
+629
@@ -73,6 +73,22 @@ exports[`Object metadata creation should fail v2 when labelPlural contains only
|
||||
"status": "fail",
|
||||
"type": "create_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "OBJECT_METADATA_NOT_FOUND",
|
||||
"message": "Object metadata not found",
|
||||
"userFriendlyMessage": "Field to create related object not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"id": Any<String>,
|
||||
"name": "updatedBy",
|
||||
"objectMetadataId": Any<String>,
|
||||
},
|
||||
"status": "fail",
|
||||
"type": "create_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
@@ -594,6 +610,27 @@ exports[`Object metadata creation should fail v2 when labelPlural contains only
|
||||
"status": "fail",
|
||||
"type": "create_view_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "Field metadata not found",
|
||||
"userFriendlyMessage": "Field metadata not found",
|
||||
},
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "View not found",
|
||||
"userFriendlyMessage": "View not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"fieldMetadataId": Any<String>,
|
||||
"id": Any<String>,
|
||||
"viewId": Any<String>,
|
||||
},
|
||||
"status": "fail",
|
||||
"type": "create_view_field",
|
||||
},
|
||||
],
|
||||
"viewFilter": [],
|
||||
"viewGroup": [],
|
||||
@@ -699,6 +736,22 @@ exports[`Object metadata creation should fail v2 when labelPlural exceeds maximu
|
||||
"status": "fail",
|
||||
"type": "create_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "OBJECT_METADATA_NOT_FOUND",
|
||||
"message": "Object metadata not found",
|
||||
"userFriendlyMessage": "Field to create related object not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"id": Any<String>,
|
||||
"name": "updatedBy",
|
||||
"objectMetadataId": Any<String>,
|
||||
},
|
||||
"status": "fail",
|
||||
"type": "create_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
@@ -1220,6 +1273,27 @@ exports[`Object metadata creation should fail v2 when labelPlural exceeds maximu
|
||||
"status": "fail",
|
||||
"type": "create_view_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "Field metadata not found",
|
||||
"userFriendlyMessage": "Field metadata not found",
|
||||
},
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "View not found",
|
||||
"userFriendlyMessage": "View not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"fieldMetadataId": Any<String>,
|
||||
"id": Any<String>,
|
||||
"viewId": Any<String>,
|
||||
},
|
||||
"status": "fail",
|
||||
"type": "create_view_field",
|
||||
},
|
||||
],
|
||||
"viewFilter": [],
|
||||
"viewGroup": [],
|
||||
@@ -1336,6 +1410,22 @@ exports[`Object metadata creation should fail v2 when labelSingular contains onl
|
||||
"status": "fail",
|
||||
"type": "create_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "OBJECT_METADATA_NOT_FOUND",
|
||||
"message": "Object metadata not found",
|
||||
"userFriendlyMessage": "Field to create related object not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"id": Any<String>,
|
||||
"name": "updatedBy",
|
||||
"objectMetadataId": Any<String>,
|
||||
},
|
||||
"status": "fail",
|
||||
"type": "create_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
@@ -1857,6 +1947,27 @@ exports[`Object metadata creation should fail v2 when labelSingular contains onl
|
||||
"status": "fail",
|
||||
"type": "create_view_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "Field metadata not found",
|
||||
"userFriendlyMessage": "Field metadata not found",
|
||||
},
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "View not found",
|
||||
"userFriendlyMessage": "View not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"fieldMetadataId": Any<String>,
|
||||
"id": Any<String>,
|
||||
"viewId": Any<String>,
|
||||
},
|
||||
"status": "fail",
|
||||
"type": "create_view_field",
|
||||
},
|
||||
],
|
||||
"viewFilter": [],
|
||||
"viewGroup": [],
|
||||
@@ -1962,6 +2073,22 @@ exports[`Object metadata creation should fail v2 when labelSingular exceeds maxi
|
||||
"status": "fail",
|
||||
"type": "create_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "OBJECT_METADATA_NOT_FOUND",
|
||||
"message": "Object metadata not found",
|
||||
"userFriendlyMessage": "Field to create related object not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"id": Any<String>,
|
||||
"name": "updatedBy",
|
||||
"objectMetadataId": Any<String>,
|
||||
},
|
||||
"status": "fail",
|
||||
"type": "create_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
@@ -2483,6 +2610,27 @@ exports[`Object metadata creation should fail v2 when labelSingular exceeds maxi
|
||||
"status": "fail",
|
||||
"type": "create_view_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "Field metadata not found",
|
||||
"userFriendlyMessage": "Field metadata not found",
|
||||
},
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "View not found",
|
||||
"userFriendlyMessage": "View not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"fieldMetadataId": Any<String>,
|
||||
"id": Any<String>,
|
||||
"viewId": Any<String>,
|
||||
},
|
||||
"status": "fail",
|
||||
"type": "create_view_field",
|
||||
},
|
||||
],
|
||||
"viewFilter": [],
|
||||
"viewGroup": [],
|
||||
@@ -2599,6 +2747,22 @@ exports[`Object metadata creation should fail v2 when labels are identical 1`] =
|
||||
"status": "fail",
|
||||
"type": "create_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "OBJECT_METADATA_NOT_FOUND",
|
||||
"message": "Object metadata not found",
|
||||
"userFriendlyMessage": "Field to create related object not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"id": Any<String>,
|
||||
"name": "updatedBy",
|
||||
"objectMetadataId": Any<String>,
|
||||
},
|
||||
"status": "fail",
|
||||
"type": "create_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
@@ -3120,6 +3284,27 @@ exports[`Object metadata creation should fail v2 when labels are identical 1`] =
|
||||
"status": "fail",
|
||||
"type": "create_view_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "Field metadata not found",
|
||||
"userFriendlyMessage": "Field metadata not found",
|
||||
},
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "View not found",
|
||||
"userFriendlyMessage": "View not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"fieldMetadataId": Any<String>,
|
||||
"id": Any<String>,
|
||||
"viewId": Any<String>,
|
||||
},
|
||||
"status": "fail",
|
||||
"type": "create_view_field",
|
||||
},
|
||||
],
|
||||
"viewFilter": [],
|
||||
"viewGroup": [],
|
||||
@@ -3225,6 +3410,22 @@ exports[`Object metadata creation should fail v2 when labels with whitespaces re
|
||||
"status": "fail",
|
||||
"type": "create_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "OBJECT_METADATA_NOT_FOUND",
|
||||
"message": "Object metadata not found",
|
||||
"userFriendlyMessage": "Field to create related object not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"id": Any<String>,
|
||||
"name": "updatedBy",
|
||||
"objectMetadataId": Any<String>,
|
||||
},
|
||||
"status": "fail",
|
||||
"type": "create_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
@@ -3746,6 +3947,27 @@ exports[`Object metadata creation should fail v2 when labels with whitespaces re
|
||||
"status": "fail",
|
||||
"type": "create_view_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "Field metadata not found",
|
||||
"userFriendlyMessage": "Field metadata not found",
|
||||
},
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "View not found",
|
||||
"userFriendlyMessage": "View not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"fieldMetadataId": Any<String>,
|
||||
"id": Any<String>,
|
||||
"viewId": Any<String>,
|
||||
},
|
||||
"status": "fail",
|
||||
"type": "create_view_field",
|
||||
},
|
||||
],
|
||||
"viewFilter": [],
|
||||
"viewGroup": [],
|
||||
@@ -3851,6 +4073,22 @@ exports[`Object metadata creation should fail v2 when name exceeds maximum lengt
|
||||
"status": "fail",
|
||||
"type": "create_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "OBJECT_METADATA_NOT_FOUND",
|
||||
"message": "Object metadata not found",
|
||||
"userFriendlyMessage": "Field to create related object not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"id": Any<String>,
|
||||
"name": "updatedBy",
|
||||
"objectMetadataId": Any<String>,
|
||||
},
|
||||
"status": "fail",
|
||||
"type": "create_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
@@ -4402,6 +4640,27 @@ exports[`Object metadata creation should fail v2 when name exceeds maximum lengt
|
||||
"status": "fail",
|
||||
"type": "create_view_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "Field metadata not found",
|
||||
"userFriendlyMessage": "Field metadata not found",
|
||||
},
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "View not found",
|
||||
"userFriendlyMessage": "View not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"fieldMetadataId": Any<String>,
|
||||
"id": Any<String>,
|
||||
"viewId": Any<String>,
|
||||
},
|
||||
"status": "fail",
|
||||
"type": "create_view_field",
|
||||
},
|
||||
],
|
||||
"viewFilter": [],
|
||||
"viewGroup": [],
|
||||
@@ -4507,6 +4766,22 @@ exports[`Object metadata creation should fail v2 when namePlural has invalid cha
|
||||
"status": "fail",
|
||||
"type": "create_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "OBJECT_METADATA_NOT_FOUND",
|
||||
"message": "Object metadata not found",
|
||||
"userFriendlyMessage": "Field to create related object not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"id": Any<String>,
|
||||
"name": "updatedBy",
|
||||
"objectMetadataId": Any<String>,
|
||||
},
|
||||
"status": "fail",
|
||||
"type": "create_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
@@ -5028,6 +5303,27 @@ exports[`Object metadata creation should fail v2 when namePlural has invalid cha
|
||||
"status": "fail",
|
||||
"type": "create_view_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "Field metadata not found",
|
||||
"userFriendlyMessage": "Field metadata not found",
|
||||
},
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "View not found",
|
||||
"userFriendlyMessage": "View not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"fieldMetadataId": Any<String>,
|
||||
"id": Any<String>,
|
||||
"viewId": Any<String>,
|
||||
},
|
||||
"status": "fail",
|
||||
"type": "create_view_field",
|
||||
},
|
||||
],
|
||||
"viewFilter": [],
|
||||
"viewGroup": [],
|
||||
@@ -5133,6 +5429,22 @@ exports[`Object metadata creation should fail v2 when namePlural is a reserved k
|
||||
"status": "fail",
|
||||
"type": "create_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "OBJECT_METADATA_NOT_FOUND",
|
||||
"message": "Object metadata not found",
|
||||
"userFriendlyMessage": "Field to create related object not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"id": Any<String>,
|
||||
"name": "updatedBy",
|
||||
"objectMetadataId": Any<String>,
|
||||
},
|
||||
"status": "fail",
|
||||
"type": "create_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
@@ -5654,6 +5966,27 @@ exports[`Object metadata creation should fail v2 when namePlural is a reserved k
|
||||
"status": "fail",
|
||||
"type": "create_view_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "Field metadata not found",
|
||||
"userFriendlyMessage": "Field metadata not found",
|
||||
},
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "View not found",
|
||||
"userFriendlyMessage": "View not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"fieldMetadataId": Any<String>,
|
||||
"id": Any<String>,
|
||||
"viewId": Any<String>,
|
||||
},
|
||||
"status": "fail",
|
||||
"type": "create_view_field",
|
||||
},
|
||||
],
|
||||
"viewFilter": [],
|
||||
"viewGroup": [],
|
||||
@@ -5770,6 +6103,22 @@ exports[`Object metadata creation should fail v2 when namePlural is not camelCas
|
||||
"status": "fail",
|
||||
"type": "create_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "OBJECT_METADATA_NOT_FOUND",
|
||||
"message": "Object metadata not found",
|
||||
"userFriendlyMessage": "Field to create related object not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"id": Any<String>,
|
||||
"name": "updatedBy",
|
||||
"objectMetadataId": Any<String>,
|
||||
},
|
||||
"status": "fail",
|
||||
"type": "create_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
@@ -6297,6 +6646,27 @@ exports[`Object metadata creation should fail v2 when namePlural is not camelCas
|
||||
"status": "fail",
|
||||
"type": "create_view_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "Field metadata not found",
|
||||
"userFriendlyMessage": "Field metadata not found",
|
||||
},
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "View not found",
|
||||
"userFriendlyMessage": "View not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"fieldMetadataId": Any<String>,
|
||||
"id": Any<String>,
|
||||
"viewId": Any<String>,
|
||||
},
|
||||
"status": "fail",
|
||||
"type": "create_view_field",
|
||||
},
|
||||
],
|
||||
"viewFilter": [],
|
||||
"viewGroup": [],
|
||||
@@ -6402,6 +6772,22 @@ exports[`Object metadata creation should fail v2 when nameSingular contains only
|
||||
"status": "fail",
|
||||
"type": "create_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "OBJECT_METADATA_NOT_FOUND",
|
||||
"message": "Object metadata not found",
|
||||
"userFriendlyMessage": "Field to create related object not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"id": Any<String>,
|
||||
"name": "updatedBy",
|
||||
"objectMetadataId": Any<String>,
|
||||
},
|
||||
"status": "fail",
|
||||
"type": "create_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
@@ -6989,6 +7375,27 @@ exports[`Object metadata creation should fail v2 when nameSingular contains only
|
||||
"status": "fail",
|
||||
"type": "create_view_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "Field metadata not found",
|
||||
"userFriendlyMessage": "Field metadata not found",
|
||||
},
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "View not found",
|
||||
"userFriendlyMessage": "View not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"fieldMetadataId": Any<String>,
|
||||
"id": Any<String>,
|
||||
"viewId": Any<String>,
|
||||
},
|
||||
"status": "fail",
|
||||
"type": "create_view_field",
|
||||
},
|
||||
],
|
||||
"viewFilter": [],
|
||||
"viewGroup": [],
|
||||
@@ -7094,6 +7501,22 @@ exports[`Object metadata creation should fail v2 when nameSingular contains only
|
||||
"status": "fail",
|
||||
"type": "create_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "OBJECT_METADATA_NOT_FOUND",
|
||||
"message": "Object metadata not found",
|
||||
"userFriendlyMessage": "Field to create related object not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"id": Any<String>,
|
||||
"name": "updatedBy",
|
||||
"objectMetadataId": Any<String>,
|
||||
},
|
||||
"status": "fail",
|
||||
"type": "create_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
@@ -7669,6 +8092,27 @@ exports[`Object metadata creation should fail v2 when nameSingular contains only
|
||||
"status": "fail",
|
||||
"type": "create_view_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "Field metadata not found",
|
||||
"userFriendlyMessage": "Field metadata not found",
|
||||
},
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "View not found",
|
||||
"userFriendlyMessage": "View not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"fieldMetadataId": Any<String>,
|
||||
"id": Any<String>,
|
||||
"viewId": Any<String>,
|
||||
},
|
||||
"status": "fail",
|
||||
"type": "create_view_field",
|
||||
},
|
||||
],
|
||||
"viewFilter": [],
|
||||
"viewGroup": [],
|
||||
@@ -7774,6 +8218,22 @@ exports[`Object metadata creation should fail v2 when nameSingular has invalid c
|
||||
"status": "fail",
|
||||
"type": "create_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "OBJECT_METADATA_NOT_FOUND",
|
||||
"message": "Object metadata not found",
|
||||
"userFriendlyMessage": "Field to create related object not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"id": Any<String>,
|
||||
"name": "updatedBy",
|
||||
"objectMetadataId": Any<String>,
|
||||
},
|
||||
"status": "fail",
|
||||
"type": "create_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
@@ -8331,6 +8791,27 @@ exports[`Object metadata creation should fail v2 when nameSingular has invalid c
|
||||
"status": "fail",
|
||||
"type": "create_view_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "Field metadata not found",
|
||||
"userFriendlyMessage": "Field metadata not found",
|
||||
},
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "View not found",
|
||||
"userFriendlyMessage": "View not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"fieldMetadataId": Any<String>,
|
||||
"id": Any<String>,
|
||||
"viewId": Any<String>,
|
||||
},
|
||||
"status": "fail",
|
||||
"type": "create_view_field",
|
||||
},
|
||||
],
|
||||
"viewFilter": [],
|
||||
"viewGroup": [],
|
||||
@@ -8436,6 +8917,22 @@ exports[`Object metadata creation should fail v2 when nameSingular is a reserved
|
||||
"status": "fail",
|
||||
"type": "create_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "OBJECT_METADATA_NOT_FOUND",
|
||||
"message": "Object metadata not found",
|
||||
"userFriendlyMessage": "Field to create related object not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"id": Any<String>,
|
||||
"name": "updatedBy",
|
||||
"objectMetadataId": Any<String>,
|
||||
},
|
||||
"status": "fail",
|
||||
"type": "create_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
@@ -8981,6 +9478,27 @@ exports[`Object metadata creation should fail v2 when nameSingular is a reserved
|
||||
"status": "fail",
|
||||
"type": "create_view_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "Field metadata not found",
|
||||
"userFriendlyMessage": "Field metadata not found",
|
||||
},
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "View not found",
|
||||
"userFriendlyMessage": "View not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"fieldMetadataId": Any<String>,
|
||||
"id": Any<String>,
|
||||
"viewId": Any<String>,
|
||||
},
|
||||
"status": "fail",
|
||||
"type": "create_view_field",
|
||||
},
|
||||
],
|
||||
"viewFilter": [],
|
||||
"viewGroup": [],
|
||||
@@ -9097,6 +9615,22 @@ exports[`Object metadata creation should fail v2 when nameSingular is not camelC
|
||||
"status": "fail",
|
||||
"type": "create_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "OBJECT_METADATA_NOT_FOUND",
|
||||
"message": "Object metadata not found",
|
||||
"userFriendlyMessage": "Field to create related object not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"id": Any<String>,
|
||||
"name": "updatedBy",
|
||||
"objectMetadataId": Any<String>,
|
||||
},
|
||||
"status": "fail",
|
||||
"type": "create_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
@@ -9684,6 +10218,27 @@ exports[`Object metadata creation should fail v2 when nameSingular is not camelC
|
||||
"status": "fail",
|
||||
"type": "create_view_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "Field metadata not found",
|
||||
"userFriendlyMessage": "Field metadata not found",
|
||||
},
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "View not found",
|
||||
"userFriendlyMessage": "View not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"fieldMetadataId": Any<String>,
|
||||
"id": Any<String>,
|
||||
"viewId": Any<String>,
|
||||
},
|
||||
"status": "fail",
|
||||
"type": "create_view_field",
|
||||
},
|
||||
],
|
||||
"viewFilter": [],
|
||||
"viewGroup": [],
|
||||
@@ -9789,6 +10344,22 @@ exports[`Object metadata creation should fail v2 when names are identical 1`] =
|
||||
"status": "fail",
|
||||
"type": "create_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "OBJECT_METADATA_NOT_FOUND",
|
||||
"message": "Object metadata not found",
|
||||
"userFriendlyMessage": "Field to create related object not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"id": Any<String>,
|
||||
"name": "updatedBy",
|
||||
"objectMetadataId": Any<String>,
|
||||
},
|
||||
"status": "fail",
|
||||
"type": "create_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
@@ -10310,6 +10881,27 @@ exports[`Object metadata creation should fail v2 when names are identical 1`] =
|
||||
"status": "fail",
|
||||
"type": "create_view_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "Field metadata not found",
|
||||
"userFriendlyMessage": "Field metadata not found",
|
||||
},
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "View not found",
|
||||
"userFriendlyMessage": "View not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"fieldMetadataId": Any<String>,
|
||||
"id": Any<String>,
|
||||
"viewId": Any<String>,
|
||||
},
|
||||
"status": "fail",
|
||||
"type": "create_view_field",
|
||||
},
|
||||
],
|
||||
"viewFilter": [],
|
||||
"viewGroup": [],
|
||||
@@ -10415,6 +11007,22 @@ exports[`Object metadata creation should fail v2 when names with whitespaces res
|
||||
"status": "fail",
|
||||
"type": "create_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "OBJECT_METADATA_NOT_FOUND",
|
||||
"message": "Object metadata not found",
|
||||
"userFriendlyMessage": "Field to create related object not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"id": Any<String>,
|
||||
"name": "updatedBy",
|
||||
"objectMetadataId": Any<String>,
|
||||
},
|
||||
"status": "fail",
|
||||
"type": "create_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
@@ -10936,6 +11544,27 @@ exports[`Object metadata creation should fail v2 when names with whitespaces res
|
||||
"status": "fail",
|
||||
"type": "create_view_field",
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "Field metadata not found",
|
||||
"userFriendlyMessage": "Field metadata not found",
|
||||
},
|
||||
{
|
||||
"code": "INVALID_VIEW_DATA",
|
||||
"message": "View not found",
|
||||
"userFriendlyMessage": "View not found",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"fieldMetadataId": Any<String>,
|
||||
"id": Any<String>,
|
||||
"viewId": Any<String>,
|
||||
},
|
||||
"status": "fail",
|
||||
"type": "create_view_field",
|
||||
},
|
||||
],
|
||||
"viewFilter": [],
|
||||
"viewGroup": [],
|
||||
|
||||
+1
-1
@@ -93,6 +93,6 @@ describe('View side effect on object creation', () => {
|
||||
expectToFail: false,
|
||||
});
|
||||
|
||||
expect(createdViewFields.length).toBe(11);
|
||||
expect(createdViewFields.length).toBe(12);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user