feat: workflow agent node permissions tab (#16092)
This commit is contained in:
+76
@@ -1,8 +1,11 @@
|
||||
import { Test, type TestingModule } from '@nestjs/testing';
|
||||
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||
|
||||
import { AiAgentRoleService } from 'src/engine/metadata-modules/ai/ai-agent-role/ai-agent-role.service';
|
||||
import { AgentEntity } from 'src/engine/metadata-modules/ai/ai-agent/entities/agent.entity';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { RoleTargetsEntity } from 'src/engine/metadata-modules/role/role-targets.entity';
|
||||
import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity';
|
||||
import { type ServerlessFunctionEntity } from 'src/engine/metadata-modules/serverless-function/serverless-function.entity';
|
||||
import { ServerlessFunctionService } from 'src/engine/metadata-modules/serverless-function/serverless-function.service';
|
||||
import { ScopedWorkspaceContextFactory } from 'src/engine/twenty-orm/factories/scoped-workspace-context.factory';
|
||||
@@ -21,8 +24,11 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => {
|
||||
let twentyORMGlobalManager: jest.Mocked<TwentyORMGlobalManager>;
|
||||
let serverlessFunctionService: jest.Mocked<ServerlessFunctionService>;
|
||||
let agentRepository: jest.Mocked<any>;
|
||||
let roleTargetsRepository: jest.Mocked<any>;
|
||||
let roleRepository: jest.Mocked<any>;
|
||||
let objectMetadataRepository: jest.Mocked<any>;
|
||||
let workflowCommonWorkspaceService: jest.Mocked<WorkflowCommonWorkspaceService>;
|
||||
let aiAgentRoleService: jest.Mocked<AiAgentRoleService>;
|
||||
|
||||
beforeEach(async () => {
|
||||
serverlessFunctionService = {
|
||||
@@ -38,6 +44,16 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => {
|
||||
delete: jest.fn(),
|
||||
};
|
||||
|
||||
roleTargetsRepository = {
|
||||
findOne: jest.fn(),
|
||||
count: jest.fn(),
|
||||
};
|
||||
|
||||
roleRepository = {
|
||||
findOne: jest.fn(),
|
||||
delete: jest.fn(),
|
||||
};
|
||||
|
||||
objectMetadataRepository = {
|
||||
findOne: jest.fn(),
|
||||
};
|
||||
@@ -46,6 +62,10 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => {
|
||||
getObjectMetadataItemWithFieldsMaps: jest.fn(),
|
||||
} as unknown as jest.Mocked<WorkflowCommonWorkspaceService>;
|
||||
|
||||
aiAgentRoleService = {
|
||||
deleteAgentOnlyRoleIfUnused: jest.fn(),
|
||||
} as unknown as jest.Mocked<AiAgentRoleService>;
|
||||
|
||||
twentyORMGlobalManager = {
|
||||
getRepositoryForWorkspace: jest.fn(),
|
||||
} as unknown as jest.Mocked<TwentyORMGlobalManager>;
|
||||
@@ -65,6 +85,14 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => {
|
||||
provide: getRepositoryToken(AgentEntity),
|
||||
useValue: agentRepository,
|
||||
},
|
||||
{
|
||||
provide: getRepositoryToken(RoleTargetsEntity),
|
||||
useValue: roleTargetsRepository,
|
||||
},
|
||||
{
|
||||
provide: getRepositoryToken(RoleEntity),
|
||||
useValue: roleRepository,
|
||||
},
|
||||
{
|
||||
provide: getRepositoryToken(ObjectMetadataEntity),
|
||||
useValue: objectMetadataRepository,
|
||||
@@ -73,6 +101,10 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => {
|
||||
provide: WorkflowCommonWorkspaceService,
|
||||
useValue: workflowCommonWorkspaceService,
|
||||
},
|
||||
{
|
||||
provide: AiAgentRoleService,
|
||||
useValue: aiAgentRoleService,
|
||||
},
|
||||
{
|
||||
provide: ScopedWorkspaceContextFactory,
|
||||
useValue: {},
|
||||
@@ -154,6 +186,50 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => {
|
||||
workspaceId: mockWorkspaceId,
|
||||
});
|
||||
});
|
||||
|
||||
it('should delete attached role when it is agent-only and unassigned elsewhere', async () => {
|
||||
const step = {
|
||||
id: 'step-id',
|
||||
name: 'AI Agent Step',
|
||||
type: WorkflowActionType.AI_AGENT,
|
||||
valid: true,
|
||||
nextStepIds: [],
|
||||
settings: {
|
||||
input: {
|
||||
agentId: 'agent-id',
|
||||
prompt: '',
|
||||
},
|
||||
outputSchema: {},
|
||||
errorHandlingOptions: {
|
||||
continueOnFailure: { value: false },
|
||||
retryOnFailure: { value: false },
|
||||
},
|
||||
},
|
||||
} as unknown as WorkflowAction;
|
||||
|
||||
agentRepository.findOne.mockResolvedValue({ id: 'agent-id' });
|
||||
roleTargetsRepository.findOne.mockResolvedValue({
|
||||
id: 'role-target-id',
|
||||
roleId: 'role-id',
|
||||
});
|
||||
|
||||
await service.runWorkflowVersionStepDeletionSideEffects({
|
||||
step,
|
||||
workspaceId: mockWorkspaceId,
|
||||
});
|
||||
|
||||
expect(agentRepository.delete).toHaveBeenCalledWith({
|
||||
id: 'agent-id',
|
||||
workspaceId: mockWorkspaceId,
|
||||
});
|
||||
expect(
|
||||
aiAgentRoleService.deleteAgentOnlyRoleIfUnused,
|
||||
).toHaveBeenCalledWith({
|
||||
roleId: 'role-id',
|
||||
roleTargetId: 'role-target-id',
|
||||
workspaceId: mockWorkspaceId,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('runStepCreationSideEffectsAndBuildStep', () => {
|
||||
|
||||
+20
@@ -9,9 +9,11 @@ import { v4 } from 'uuid';
|
||||
import { getFlatFieldsFromFlatObjectMetadata } from 'src/engine/api/graphql/workspace-schema-builder/utils/get-flat-fields-for-flat-object-metadata.util';
|
||||
import { BASE_TYPESCRIPT_PROJECT_INPUT_SCHEMA } from 'src/engine/core-modules/serverless/drivers/constants/base-typescript-project-input-schema';
|
||||
import { type WorkflowStepPositionInput } from 'src/engine/core-modules/workflow/dtos/update-workflow-step-position-input.dto';
|
||||
import { AiAgentRoleService } from 'src/engine/metadata-modules/ai/ai-agent-role/ai-agent-role.service';
|
||||
import { AgentEntity } from 'src/engine/metadata-modules/ai/ai-agent/entities/agent.entity';
|
||||
import { DEFAULT_SMART_MODEL } from 'src/engine/metadata-modules/ai/ai-models/constants/ai-models.const';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { RoleTargetsEntity } from 'src/engine/metadata-modules/role/role-targets.entity';
|
||||
import { ServerlessFunctionService } from 'src/engine/metadata-modules/serverless-function/serverless-function.service';
|
||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
||||
import {
|
||||
@@ -53,9 +55,12 @@ export class WorkflowVersionStepOperationsWorkspaceService {
|
||||
private readonly serverlessFunctionService: ServerlessFunctionService,
|
||||
@InjectRepository(AgentEntity)
|
||||
private readonly agentRepository: Repository<AgentEntity>,
|
||||
@InjectRepository(RoleTargetsEntity)
|
||||
private readonly roleTargetsRepository: Repository<RoleTargetsEntity>,
|
||||
@InjectRepository(ObjectMetadataEntity)
|
||||
private readonly objectMetadataRepository: Repository<ObjectMetadataEntity>,
|
||||
private readonly workflowCommonWorkspaceService: WorkflowCommonWorkspaceService,
|
||||
private readonly aiAgentRoleService: AiAgentRoleService,
|
||||
) {}
|
||||
|
||||
async runWorkflowVersionStepDeletionSideEffects({
|
||||
@@ -90,7 +95,22 @@ export class WorkflowVersionStepOperationsWorkspaceService {
|
||||
});
|
||||
|
||||
if (isDefined(agent)) {
|
||||
const roleTarget = await this.roleTargetsRepository.findOne({
|
||||
where: {
|
||||
agentId: agent.id,
|
||||
workspaceId,
|
||||
},
|
||||
});
|
||||
|
||||
await this.agentRepository.delete({ id: agent.id, workspaceId });
|
||||
|
||||
if (isDefined(roleTarget?.roleId) && isDefined(roleTarget?.id)) {
|
||||
await this.aiAgentRoleService.deleteAgentOnlyRoleIfUnused({
|
||||
roleId: roleTarget.roleId,
|
||||
roleTargetId: roleTarget.id,
|
||||
workspaceId,
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
+10
-1
@@ -2,8 +2,11 @@ import { Module } from '@nestjs/common';
|
||||
|
||||
import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm';
|
||||
|
||||
import { AiAgentRoleModule } from 'src/engine/metadata-modules/ai/ai-agent-role/ai-agent-role.module';
|
||||
import { AgentEntity } from 'src/engine/metadata-modules/ai/ai-agent/entities/agent.entity';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { RoleTargetsEntity } from 'src/engine/metadata-modules/role/role-targets.entity';
|
||||
import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity';
|
||||
import { ServerlessFunctionModule } from 'src/engine/metadata-modules/serverless-function/serverless-function.module';
|
||||
import { WorkflowCommonModule } from 'src/modules/workflow/common/workflow-common.module';
|
||||
import { WorkflowSchemaModule } from 'src/modules/workflow/workflow-builder/workflow-schema/workflow-schema.module';
|
||||
@@ -19,7 +22,13 @@ import { WorkflowVersionStepWorkspaceService } from 'src/modules/workflow/workfl
|
||||
WorkflowSchemaModule,
|
||||
ServerlessFunctionModule,
|
||||
WorkflowCommonModule,
|
||||
NestjsQueryTypeOrmModule.forFeature([ObjectMetadataEntity, AgentEntity]),
|
||||
AiAgentRoleModule,
|
||||
NestjsQueryTypeOrmModule.forFeature([
|
||||
ObjectMetadataEntity,
|
||||
AgentEntity,
|
||||
RoleTargetsEntity,
|
||||
RoleEntity,
|
||||
]),
|
||||
],
|
||||
providers: [
|
||||
WorkflowVersionStepWorkspaceService,
|
||||
|
||||
Reference in New Issue
Block a user