Add queue management dashboard (#15202)

Adds a comprehensive queue management interface to the admin panel for
viewing and managing background jobs.

**Features:**
- Queue detail pages showing paginated job lists (50 per page)
- Filter jobs by state: completed, failed, active, waiting, delayed,
paused
- Checkbox selection with bulk actions (delete jobs, retry failed jobs)
- Per-job dropdown menu for individual retry/delete
- Expandable rows showing error messages, stack traces, and job data
- Relative timestamps with hover tooltips
- Display attempt counts on failed jobs
- Dynamic retention policy info from backend

**Changes:**
- Backend: New AdminPanelQueueService with GraphQL endpoints for job
listing, retry, and delete
- Frontend: Queue detail page with QueueJobsTable component
- Updated retention policy: completed jobs kept 4 hours, failed jobs
kept 7 days (max 1000 each)
- Added JobState enum for type safety

<img width="634" height="696" alt="Screenshot_2025-10-20_at_11 45 25"
src="https://github.com/user-attachments/assets/c67bcd27-26cf-47f5-9575-3cd5684d006b"
/>
<img width="484" height="680" alt="Screenshot_2025-10-20_at_11 45 14"
src="https://github.com/user-attachments/assets/68725cc6-b3ec-4098-99ca-f9a717d6f8f1"
/>
<img width="490" height="643" alt="Screenshot_2025-10-20_at_11 45 05"
src="https://github.com/user-attachments/assets/b68a5809-33ff-4452-b48b-741aff7f1dd6"
/>



<img width="685" height="662" alt="Screenshot 2025-10-20 at 13 15 01"
src="https://github.com/user-attachments/assets/eeb5207b-de5c-4b18-bdde-392892053dab"
/>
This commit is contained in:
Félix Malfait
2025-10-21 16:02:50 +02:00
committed by GitHub
parent 27f50c4f4e
commit f7421c5fc0
144 changed files with 2914 additions and 955 deletions
@@ -4,7 +4,7 @@ import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/
import { AgentDTO } from './agent.dto';
@ObjectType()
@ObjectType('AgentHandoff')
export class AgentHandoffDTO {
@Field(() => UUIDScalarType)
id: string;
@@ -3,7 +3,7 @@ import { Field, HideField, ObjectType } from '@nestjs/graphql';
import { Relation } from 'typeorm';
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
import { WorkspaceMember } from 'src/engine/core-modules/user/dtos/workspace-member.dto';
import { WorkspaceMemberDTO } from 'src/engine/core-modules/user/dtos/workspace-member.dto';
import { AgentDTO } from 'src/engine/metadata-modules/agent/dtos/agent.dto';
import { FieldPermissionDTO } from 'src/engine/metadata-modules/object-permission/dtos/field-permission.dto';
import { ObjectPermissionDTO } from 'src/engine/metadata-modules/object-permission/dtos/object-permission.dto';
@@ -57,8 +57,8 @@ export class RoleDTO {
@HideField()
roleTargets: Relation<RoleTargetsEntity[]>;
@Field(() => [WorkspaceMember], { nullable: true })
workspaceMembers?: WorkspaceMember[];
@Field(() => [WorkspaceMemberDTO], { nullable: true })
workspaceMembers?: WorkspaceMemberDTO[];
@Field(() => [AgentDTO], { nullable: true })
agents?: AgentDTO[];
@@ -16,7 +16,7 @@ import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/featu
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service';
import { WorkspaceMember } from 'src/engine/core-modules/user/dtos/workspace-member.dto';
import { WorkspaceMemberDTO } from 'src/engine/core-modules/user/dtos/workspace-member.dto';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { AuthWorkspaceMemberId } from 'src/engine/decorators/auth/auth-workspace-member-id.decorator';
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
@@ -79,7 +79,7 @@ export class RoleResolver {
return this.roleService.getWorkspaceRoles(workspace.id);
}
@Mutation(() => WorkspaceMember)
@Mutation(() => WorkspaceMemberDTO)
@UseGuards(UserAuthGuard)
async updateWorkspaceMemberRole(
@AuthWorkspace() workspace: Workspace,
@@ -88,7 +88,7 @@ export class RoleResolver {
@Args('roleId', { type: () => UUIDScalarType }) roleId: string,
@AuthWorkspaceMemberId()
updatorWorkspaceMemberId: string,
): Promise<WorkspaceMember> {
): Promise<WorkspaceMemberDTO> {
if (updatorWorkspaceMemberId === workspaceMemberId) {
throw new PermissionsException(
PermissionsExceptionMessage.CANNOT_UPDATE_SELF_ROLE,
@@ -131,7 +131,7 @@ export class RoleResolver {
...workspaceMember,
userWorkspaceId: userWorkspace.id,
roles,
} as WorkspaceMember;
} as WorkspaceMemberDTO;
}
@Mutation(() => RoleDTO)
@@ -237,7 +237,7 @@ export class RoleResolver {
return true;
}
@ResolveField('workspaceMembers', () => [WorkspaceMember])
@ResolveField('workspaceMembers', () => [WorkspaceMemberDTO])
async getWorkspaceMembersAssignedToRole(
@Parent() role: RoleDTO,
@AuthWorkspace() workspace: Workspace,