From 8065fe4d15174a29cc943700a1485e62e6b907b7 Mon Sep 17 00:00:00 2001 From: GloireMutaliko21 Date: Fri, 10 Jan 2025 18:20:49 +0200 Subject: [PATCH 1/4] fix: improve task model by advanced filters --- packages/contracts/src/lib/task.model.ts | 33 ++++++++++++++---------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/packages/contracts/src/lib/task.model.ts b/packages/contracts/src/lib/task.model.ts index 2663e85fc5d..effc4d1ff6e 100644 --- a/packages/contracts/src/lib/task.model.ts +++ b/packages/contracts/src/lib/task.model.ts @@ -89,26 +89,13 @@ export interface IGetTaskById { includeRootEpic?: boolean; } -export interface IGetTasksByViewFilters extends IBasePerTenantAndOrganizationEntityModel { - projects?: ID[]; - teams?: ID[]; - modules?: ID[]; - sprints?: ID[]; - members?: ID[]; - tags?: ID[]; - statusIds?: ID[]; +export interface IGetTasksByViewFilters extends IBasePerTenantAndOrganizationEntityModel, ITaskAdvancedFilter { statuses?: TaskStatusEnum[]; - priorityIds?: ID[]; priorities?: TaskPriorityEnum[]; - sizeIds?: ID[]; sizes?: TaskSizeEnum[]; types?: TaskTypeEnum[]; startDates?: Date[]; dueDates?: Date[]; - creators?: ID[]; - - // Relations - relations?: string[]; } export interface ITaskDateFilterInput @@ -122,3 +109,21 @@ export interface ITaskDateFilterInput dueDateFrom?: Date; dueDateTo?: Date; } + +export interface ITaskAdvancedFilter { + projects?: ID[]; + teams?: ID[]; + modules?: ID[]; + sprints?: ID[]; + members?: ID[]; + tags?: ID[]; + statusIds?: ID[]; + priorityIds?: ID[]; + sizeIds?: ID[]; + parentIds?: ID[]; + creators?: ID[]; + dailyPlans?: ID[]; + + // Relations + relations?: string[]; +} From 5325bdd65b514e0a1b6bd51065c491fc6b058980 Mon Sep 17 00:00:00 2001 From: GloireMutaliko21 Date: Fri, 10 Jan 2025 18:25:37 +0200 Subject: [PATCH 2/4] feat: add advanced filters to task service --- packages/contracts/src/lib/task.model.ts | 4 + packages/core/src/lib/tasks/task.service.ts | 170 +++++++++++++++----- 2 files changed, 137 insertions(+), 37 deletions(-) diff --git a/packages/contracts/src/lib/task.model.ts b/packages/contracts/src/lib/task.model.ts index effc4d1ff6e..14a1a64266f 100644 --- a/packages/contracts/src/lib/task.model.ts +++ b/packages/contracts/src/lib/task.model.ts @@ -127,3 +127,7 @@ export interface ITaskAdvancedFilter { // Relations relations?: string[]; } + +export interface IAdvancedTaskFiltering { + filters?: ITaskAdvancedFilter; +} diff --git a/packages/core/src/lib/tasks/task.service.ts b/packages/core/src/lib/tasks/task.service.ts index 90dbd9da3a6..a40d62c5bb0 100644 --- a/packages/core/src/lib/tasks/task.service.ts +++ b/packages/core/src/lib/tasks/task.service.ts @@ -26,7 +26,9 @@ import { PermissionsEnum, ActionTypeEnum, ITaskDateFilterInput, - SubscriptionTypeEnum + SubscriptionTypeEnum, + ITaskAdvancedFilter, + IAdvancedTaskFiltering } from '@gauzy/contracts'; import { isEmpty, isNotEmpty } from '@gauzy/common'; import { isPostgres, isSqlite } from '@gauzy/config'; @@ -228,6 +230,29 @@ export class TaskService extends TenantAwareCrudService { return task; } + /** + * Retrieves a paginated list of tasks, with optional advanced filters applied. + * + * @param options - Pagination options including limit, page, and sorting. + * @param filters - Optional filters for advanced task filtering. + * @returns A promise that resolves to a paginated list of tasks. + * @throws If an error occurs during the retrieval process. + */ + async findAll(options: PaginationParams & IAdvancedTaskFiltering): Promise> { + try { + const { filters } = options; + let advancedFilters: FindOptionsWhere = {}; + if (filters) { + advancedFilters = this.buildAdvancedWhereCondition(filters, options.where); + } + + return super.findAll({ ...options, where: { ...advancedFilters, ...options.where } }); + } catch (error) { + console.log(error); + throw new BadRequestException(error); + } + } + /** * Recursively searches for the parent epic of a given task (issue) using a SQL recursive query. * @@ -272,12 +297,13 @@ export class TaskService extends TenantAwareCrudService { /** * Find employee tasks * - * @param options + * @param options - Pagination options including limit, page, and sorting. + * @param filters - Optional filters for advanced task filtering. * @returns */ - async getEmployeeTasks(options: PaginationParams) { + async getEmployeeTasks(options: PaginationParams & IAdvancedTaskFiltering) { try { - const { where } = options; + const { where, filters } = options; const { status, title, prefix, isDraft, isScreeningTask = false, organizationSprintId = null } = where; const { organizationId, projectId, members } = where; const likeOperator = isPostgres() ? 'ILIKE' : 'LIKE'; @@ -298,6 +324,13 @@ export class TaskService extends TenantAwareCrudService { ...(options.relations ? { relations: options.relations } : {}) }); } + + // Apply advanced filters + if (filters) { + const advancedWhere = this.buildAdvancedWhereCondition(filters, where); + query.setFindOptions({ where: advancedWhere }); + } + query.andWhere((qb: SelectQueryBuilder) => { const subQuery = qb.subQuery(); subQuery.select(p('"task_employee"."taskId"')).from(p('task_employee'), p('task_employee')); @@ -371,16 +404,25 @@ export class TaskService extends TenantAwareCrudService { /** * GET all tasks by employee * - * @param employeeId - * @param filter + * @param employeeId - The employee ID for whom retrieve tasks + * @param options - Pagination options including limit, page, and sorting. + * @param filters - Optional filters for advanced task filtering. * @returns */ - async getAllTasksByEmployee(employeeId: IEmployee['id'], options: PaginationParams) { + async getAllTasksByEmployee(employeeId: IEmployee['id'], options: PaginationParams & IAdvancedTaskFiltering) { try { const query = this.typeOrmRepository.createQueryBuilder(this.tableName); query.leftJoin(`${query.alias}.members`, 'members'); query.leftJoin(`${query.alias}.teams`, 'teams'); const { isScreeningTask = false } = options.where; + const { filters } = options; + + // Apply advanced filters + if (filters) { + const advancedWhere = this.buildAdvancedWhereCondition(filters, options.where); + query.setFindOptions({ where: advancedWhere }); + } + /** * If additional options found */ @@ -394,6 +436,7 @@ export class TaskService extends TenantAwareCrudService { relations: options.relations }) }); + query.andWhere( new Brackets((qb: WhereExpressionBuilder) => { const tenantId = RequestContext.currentTenantId(); @@ -437,12 +480,13 @@ export class TaskService extends TenantAwareCrudService { /** * GET team tasks * - * @param options + * @param options - Pagination options including limit, page, and sorting. + * @param filters - Optional filters for advanced task filtering. * @returns */ - async findTeamTasks(options: PaginationParams): Promise> { + async findTeamTasks(options: PaginationParams & IAdvancedTaskFiltering): Promise> { try { - const { where } = options; + const { where, filters } = options; const { status, @@ -475,6 +519,13 @@ export class TaskService extends TenantAwareCrudService { ...(options.order ? { order: options.order } : {}) }); } + + // Apply advanced filters + if (filters) { + const advancedWhere = this.buildAdvancedWhereCondition(filters, options.where); + query.setFindOptions({ where: advancedWhere }); + } + query.andWhere((qb: SelectQueryBuilder) => { const subQuery = qb.subQuery(); subQuery.select(p('"task_team"."taskId"')).from(p('task_team'), p('task_team')); @@ -558,12 +609,15 @@ export class TaskService extends TenantAwareCrudService { * GET tasks by pagination with filtering options. * * @param options The pagination and filtering parameters. + * @param filters - Optional filters for advanced task filtering. * @returns A Promise that resolves to a paginated list of tasks. */ - public async pagination(options: PaginationParams): Promise> { + public async pagination(options: PaginationParams & IAdvancedTaskFiltering): Promise> { // Define the like operator based on the database type const likeOperator = isPostgres() ? 'ILIKE' : 'LIKE'; + const filters = options?.filters; + // Check if there are any filters in the options if (options?.where) { const { where } = options; @@ -600,8 +654,14 @@ export class TaskService extends TenantAwareCrudService { where.isScreeningTask = isScreeningTask; } + // Apply Advanced filters + let advancedFilters: FindOptionsWhere = {}; + if (filters) { + advancedFilters = this.buildAdvancedWhereCondition(filters, options?.where); + } + // Call the base paginate method - return await super.paginate(options); + return await super.paginate({ ...options, where: { ...advancedFilters, ...options?.where } }); } /** @@ -741,12 +801,13 @@ export class TaskService extends TenantAwareCrudService { /** * Retrieves module tasks based on the provided options. * - * @param {PaginationParams} options - The pagination options and filters for querying tasks. - * @returns {Promise>} A promise that resolves with pagination task items and total count. + * @param options - The pagination options and filters for querying tasks. + * @param filters - Optional filters for advanced task filtering. + * @returns A promise that resolves with pagination task items and total count. */ - async findModuleTasks(options: PaginationParams): Promise> { + async findModuleTasks(options: PaginationParams & IAdvancedTaskFiltering): Promise> { try { - const { where } = options; + const { where, filters } = options; const { status, modules = [], @@ -775,6 +836,12 @@ export class TaskService extends TenantAwareCrudService { }); } + // Apply advanced filters + if (filters) { + const advancedWhere = this.buildAdvancedWhereCondition(filters, where); + query.setFindOptions({ where: advancedWhere }); + } + // Filter by project_module_task with a sub query query.andWhere((qb: SelectQueryBuilder) => { const subQuery = qb @@ -831,7 +898,9 @@ export class TaskService extends TenantAwareCrudService { qb.andWhere(p(`"${query.alias}"."prefix" ${likeOperator} :prefix`), { prefix: `%${prefix}%` }); } if (isUUID(organizationSprintId)) { - qb.andWhere(p(`"${query.alias}"."organizationSprintId" = :organizationSprintId`), { organizationSprintId }); + qb.andWhere(p(`"${query.alias}"."organizationSprintId" = :organizationSprintId`), { + organizationSprintId + }); } else { qb.andWhere(p(`"${query.alias}"."organizationSprintId" IS NULL`)); } @@ -876,20 +945,10 @@ export class TaskService extends TenantAwareCrudService { // Extract filters const { - projects = [], - teams = [], - members = [], - modules = [], - sprints = [], - statusIds = [], statuses = [], - priorityIds = [], priorities = [], - sizeIds = [], sizes = [], - tags = [], types = [], - creators = [], startDates = [], dueDates = [], organizationId, @@ -921,21 +980,13 @@ export class TaskService extends TenantAwareCrudService { const [minDueDate, maxDueDate] = getMinMaxDates(dueDates); // Build the 'where' condition + const mainWhereCondition = this.buildAdvancedWhereCondition(viewFilters); const where: FindOptionsWhere = { - ...(projects.length && { projectId: In(projects) }), - ...(teams.length && { teams: { id: In(teams) } }), - ...(members.length && { members: { id: In(members) } }), - ...(modules.length && { modules: { id: In(modules) } }), - ...(sprints.length && { organizationSprintId: In(sprints) }), - ...(statusIds.length && { taskStatusId: In(statusIds) }), + ...mainWhereCondition, ...(statuses.length && { status: In(statuses) }), - ...(priorityIds.length && { taskPriorityId: In(priorityIds) }), ...(priorities.length && { priority: In(priorities) }), - ...(sizeIds.length && { taskSizeId: In(sizeIds) }), ...(sizes.length && { size: In(sizes) }), - ...(tags.length && { tags: { id: In(tags) } }), ...(types.length && { issueType: In(types) }), - ...(creators.length && { creatorId: In(creators) }), ...(minStartDate && maxStartDate && { startDate: Between(minStartDate, maxStartDate) }), ...(minDueDate && maxDueDate && { dueDate: Between(minDueDate, maxDueDate) }), organizationId: taskView.organizationId || organizationId, @@ -1049,4 +1100,49 @@ export class TaskService extends TenantAwareCrudService { throw new BadRequestException(error); } } + + /** + * Constructs advanced `where` conditions for filtering tasks based on the provided filters and existing conditions. + * + * @private + * @param {ITaskAdvancedFilter | IGetTasksByViewFilters} [filters] - Advanced filtering criteria for tasks, including projects, teams, sprints, and more. + * @param {FindOptionsWhere} [where] - Existing `where` conditions to be merged with the filters. + * @returns {FindOptionsWhere} A `where` condition object to be used in database queries. + */ + private buildAdvancedWhereCondition( + filters?: ITaskAdvancedFilter | IGetTasksByViewFilters, + where?: FindOptionsWhere + ): FindOptionsWhere { + // Destructuring filter params + const { + projects = [], + teams = [], + modules = [], + sprints = [], + members = [], + tags = [], + statusIds = [], + priorityIds = [], + sizeIds = [], + parentIds = [], + creators = [], + dailyPlans = [] + } = filters; + + // Build the 'where' condition + return { + ...(projects.length && !where.projectId ? { projectId: In(projects) } : {}), + ...(teams.length && !where.teams ? { teams: { id: In(teams) } } : {}), + ...(modules.length && !where.modules ? { modules: { id: In(modules) } } : {}), + ...(sprints.length && !where.organizationSprintId ? { organizationSprintId: In(sprints) } : {}), + ...(members.length && !where.members ? { members: { id: In(members) } } : {}), + ...(tags.length && !where.tags ? { tags: { id: In(tags) } } : {}), + ...(statusIds.length && !where.taskStatusId ? { taskStatusId: In(statusIds) } : {}), + ...(priorityIds.length && !where.taskPriorityId ? { taskPriorityId: In(priorityIds) } : {}), + ...(sizeIds.length && !where.taskSizeId ? { taskSizeId: In(sizeIds) } : {}), + ...(parentIds.length && !where.parentId ? { parentId: In(parentIds) } : {}), + ...(creators.length && !where.creatorId ? { creatorId: In(creators) } : {}), + ...(dailyPlans.length && !where.dailyPlans ? { dailyPlans: { id: In(dailyPlans) } } : {}) + }; + } } From a930c5041bdd8ddb170dd2076ca2cc89fcd7743e Mon Sep 17 00:00:00 2001 From: GloireMutaliko21 Date: Fri, 10 Jan 2025 18:31:39 +0200 Subject: [PATCH 3/4] feat: improve task controller with advanced filters --- packages/core/src/lib/tasks/dto/index.ts | 1 + .../lib/tasks/dto/task-advanced-filter.dto.ts | 71 +++++++++++++++++++ .../core/src/lib/tasks/task.controller.ts | 31 ++++++-- 3 files changed, 96 insertions(+), 7 deletions(-) create mode 100644 packages/core/src/lib/tasks/dto/task-advanced-filter.dto.ts diff --git a/packages/core/src/lib/tasks/dto/index.ts b/packages/core/src/lib/tasks/dto/index.ts index 2b3f44d04d1..ac27bc90d14 100644 --- a/packages/core/src/lib/tasks/dto/index.ts +++ b/packages/core/src/lib/tasks/dto/index.ts @@ -3,3 +3,4 @@ export * from './task-max-number-query.dto'; export * from './update-task.dto'; export * from './get-task-by-id.dto'; export * from './get-task-by-date-filter.dto'; +export * from './task-advanced-filter.dto'; diff --git a/packages/core/src/lib/tasks/dto/task-advanced-filter.dto.ts b/packages/core/src/lib/tasks/dto/task-advanced-filter.dto.ts new file mode 100644 index 00000000000..e853341aa2e --- /dev/null +++ b/packages/core/src/lib/tasks/dto/task-advanced-filter.dto.ts @@ -0,0 +1,71 @@ +import { ApiPropertyOptional } from '@nestjs/swagger'; +import { IsArray, IsOptional, IsUUID } from 'class-validator'; +import { ID, ITaskAdvancedFilter } from '@gauzy/contracts'; + +export class TaskAdvancedFilterDTO implements ITaskAdvancedFilter { + @ApiPropertyOptional({ type: Array }) + @IsOptional() + @IsArray() + @IsUUID('all', { each: true }) + projects?: ID[] = []; + + @ApiPropertyOptional({ type: Array }) + @IsOptional() + @IsArray() + @IsUUID('all', { each: true }) + teams?: ID[] = []; + + @ApiPropertyOptional({ type: Array }) + @IsOptional() + @IsArray() + @IsUUID('all', { each: true }) + modules?: ID[] = []; + + @ApiPropertyOptional({ type: Array }) + @IsOptional() + @IsArray() + @IsUUID('all', { each: true }) + sprints?: ID[] = []; + + @ApiPropertyOptional({ type: Array }) + @IsOptional() + @IsArray() + @IsUUID('all', { each: true }) + members?: ID[] = []; + + @ApiPropertyOptional({ type: Array }) + @IsOptional() + @IsArray() + @IsUUID('all', { each: true }) + tags?: ID[] = []; + + @ApiPropertyOptional({ type: Array }) + @IsOptional() + @IsArray() + @IsUUID('all', { each: true }) + statusIds?: ID[] = []; + + @ApiPropertyOptional({ type: Array }) + @IsOptional() + @IsArray() + @IsUUID('all', { each: true }) + priorityIds?: ID[] = []; + + @ApiPropertyOptional({ type: Array }) + @IsOptional() + @IsArray() + @IsUUID('all', { each: true }) + sizeIds?: ID[] = []; + + @ApiPropertyOptional({ type: Array }) + @IsOptional() + @IsArray() + @IsUUID('all', { each: true }) + parentIds?: ID[] = []; + + @ApiPropertyOptional({ type: Array }) + @IsOptional() + @IsArray() + @IsUUID('all', { each: true }) + creators?: ID[] = []; +} diff --git a/packages/core/src/lib/tasks/task.controller.ts b/packages/core/src/lib/tasks/task.controller.ts index 8616151ce58..96ee16015df 100644 --- a/packages/core/src/lib/tasks/task.controller.ts +++ b/packages/core/src/lib/tasks/task.controller.ts @@ -23,7 +23,14 @@ import { CrudController, PaginationParams } from './../core/crud'; import { Task } from './task.entity'; import { TaskService } from './task.service'; import { TaskCreateCommand, TaskUpdateCommand } from './commands'; -import { CreateTaskDTO, GetTaskByIdDTO, TaskDateFilterInputDTO, TaskMaxNumberQueryDTO, UpdateTaskDTO } from './dto'; +import { + CreateTaskDTO, + GetTaskByIdDTO, + TaskAdvancedFilterDTO, + TaskDateFilterInputDTO, + TaskMaxNumberQueryDTO, + UpdateTaskDTO +} from './dto'; @ApiTags('Tasks') @UseGuards(TenantPermissionGuard, PermissionGuard) @@ -62,7 +69,9 @@ export class TaskController extends CrudController { @ApiOperation({ summary: 'Get tasks by pagination.' }) @ApiResponse({ status: HttpStatus.OK, description: 'Tasks retrieved successfully.' }) @ApiResponse({ status: HttpStatus.BAD_REQUEST, description: 'Invalid input.' }) - async pagination(@Query() params: PaginationParams): Promise> { + async pagination( + @Query() params: PaginationParams & { filters?: TaskAdvancedFilterDTO } + ): Promise> { return this.taskService.pagination(params); } @@ -110,7 +119,9 @@ export class TaskController extends CrudController { @Permissions(PermissionsEnum.ALL_ORG_VIEW, PermissionsEnum.ORG_TASK_VIEW) @Get('/employee') @UseValidationPipe({ transform: true }) - async findEmployeeTask(@Query() params: PaginationParams): Promise> { + async findEmployeeTask( + @Query() params: PaginationParams & { filters?: TaskAdvancedFilterDTO } + ): Promise> { return this.taskService.getEmployeeTasks(params); } @@ -126,7 +137,9 @@ export class TaskController extends CrudController { @Permissions(PermissionsEnum.ALL_ORG_VIEW, PermissionsEnum.ORG_TASK_VIEW) @Get('/team') @UseValidationPipe({ transform: true }) - async findTeamTasks(@Query() params: PaginationParams): Promise> { + async findTeamTasks( + @Query() params: PaginationParams & { filters?: TaskAdvancedFilterDTO } + ): Promise> { return this.taskService.findTeamTasks(params); } @@ -142,7 +155,9 @@ export class TaskController extends CrudController { @Permissions(PermissionsEnum.ALL_ORG_VIEW, PermissionsEnum.ORG_TASK_VIEW) @Get('/module') @UseValidationPipe({ transform: true }) - async findModuleTasks(@Query() params: PaginationParams): Promise> { + async findModuleTasks( + @Query() params: PaginationParams & { filters?: TaskAdvancedFilterDTO } + ): Promise> { return this.taskService.findModuleTasks(params); } @@ -209,7 +224,7 @@ export class TaskController extends CrudController { @UseValidationPipe() async getAllTasksByEmployee( @Param('id') employeeId: ID, - @Query() params: PaginationParams + @Query() params: PaginationParams & { filters?: TaskAdvancedFilterDTO } ): Promise { return this.taskService.getAllTasksByEmployee(employeeId, params); } @@ -226,7 +241,9 @@ export class TaskController extends CrudController { @Permissions(PermissionsEnum.ALL_ORG_VIEW, PermissionsEnum.ORG_TASK_VIEW) @Get('/') @UseValidationPipe() - async findAll(@Query() params: PaginationParams): Promise> { + async findAll( + @Query() params: PaginationParams & { filters?: TaskAdvancedFilterDTO } + ): Promise> { return this.taskService.findAll(params); } From 10b7a30b2d7072f2a5dc7ad45561cac536d84cdc Mon Sep 17 00:00:00 2001 From: GloireMutaliko21 Date: Fri, 10 Jan 2025 18:49:41 +0200 Subject: [PATCH 4/4] fix: added coderabbit suggests --- .../src/lib/tasks/dto/task-advanced-filter.dto.ts | 13 ++++++++++++- packages/core/src/lib/tasks/task.service.ts | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/core/src/lib/tasks/dto/task-advanced-filter.dto.ts b/packages/core/src/lib/tasks/dto/task-advanced-filter.dto.ts index e853341aa2e..297748eae6e 100644 --- a/packages/core/src/lib/tasks/dto/task-advanced-filter.dto.ts +++ b/packages/core/src/lib/tasks/dto/task-advanced-filter.dto.ts @@ -1,71 +1,82 @@ import { ApiPropertyOptional } from '@nestjs/swagger'; -import { IsArray, IsOptional, IsUUID } from 'class-validator'; +import { ArrayMaxSize, IsArray, IsOptional, IsUUID } from 'class-validator'; import { ID, ITaskAdvancedFilter } from '@gauzy/contracts'; export class TaskAdvancedFilterDTO implements ITaskAdvancedFilter { @ApiPropertyOptional({ type: Array }) @IsOptional() @IsArray() + @ArrayMaxSize(25) @IsUUID('all', { each: true }) projects?: ID[] = []; @ApiPropertyOptional({ type: Array }) @IsOptional() @IsArray() + @ArrayMaxSize(25) @IsUUID('all', { each: true }) teams?: ID[] = []; @ApiPropertyOptional({ type: Array }) @IsOptional() @IsArray() + @ArrayMaxSize(25) @IsUUID('all', { each: true }) modules?: ID[] = []; @ApiPropertyOptional({ type: Array }) @IsOptional() @IsArray() + @ArrayMaxSize(25) @IsUUID('all', { each: true }) sprints?: ID[] = []; @ApiPropertyOptional({ type: Array }) @IsOptional() @IsArray() + @ArrayMaxSize(25) @IsUUID('all', { each: true }) members?: ID[] = []; @ApiPropertyOptional({ type: Array }) @IsOptional() @IsArray() + @ArrayMaxSize(25) @IsUUID('all', { each: true }) tags?: ID[] = []; @ApiPropertyOptional({ type: Array }) @IsOptional() @IsArray() + @ArrayMaxSize(25) @IsUUID('all', { each: true }) statusIds?: ID[] = []; @ApiPropertyOptional({ type: Array }) @IsOptional() @IsArray() + @ArrayMaxSize(25) @IsUUID('all', { each: true }) priorityIds?: ID[] = []; @ApiPropertyOptional({ type: Array }) @IsOptional() @IsArray() + @ArrayMaxSize(25) @IsUUID('all', { each: true }) sizeIds?: ID[] = []; @ApiPropertyOptional({ type: Array }) @IsOptional() @IsArray() + @ArrayMaxSize(25) @IsUUID('all', { each: true }) parentIds?: ID[] = []; @ApiPropertyOptional({ type: Array }) @IsOptional() @IsArray() + @ArrayMaxSize(25) @IsUUID('all', { each: true }) creators?: ID[] = []; } diff --git a/packages/core/src/lib/tasks/task.service.ts b/packages/core/src/lib/tasks/task.service.ts index a40d62c5bb0..ced68d331d0 100644 --- a/packages/core/src/lib/tasks/task.service.ts +++ b/packages/core/src/lib/tasks/task.service.ts @@ -1111,7 +1111,7 @@ export class TaskService extends TenantAwareCrudService { */ private buildAdvancedWhereCondition( filters?: ITaskAdvancedFilter | IGetTasksByViewFilters, - where?: FindOptionsWhere + where: FindOptionsWhere = {} ): FindOptionsWhere { // Destructuring filter params const {