feat: saved board views and richer board filters
The board now filters by text, type, priority and unassigned tickets as well. Any combination can be saved as a named view, private or shared with the project, and opened again with one click. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -251,6 +251,40 @@ export class BoardQueryDto {
|
||||
@Matches(SETTING_ID)
|
||||
area?: string;
|
||||
|
||||
@ApiPropertyOptional({ type: [String], description: 'Ticket type ids' })
|
||||
@IsOptional()
|
||||
@Transform(toList)
|
||||
@Matches(SETTING_ID, { each: true })
|
||||
type?: string[];
|
||||
|
||||
@ApiPropertyOptional({
|
||||
enum: IssuePriority,
|
||||
enumName: 'IssuePriority',
|
||||
isArray: true,
|
||||
})
|
||||
@IsOptional()
|
||||
@Transform(toList)
|
||||
@IsEnum(IssuePriority, { each: true })
|
||||
priority?: IssuePriority[];
|
||||
|
||||
@ApiPropertyOptional({ type: [String] })
|
||||
@IsOptional()
|
||||
@Transform(toList)
|
||||
@IsString({ each: true })
|
||||
label?: string[];
|
||||
|
||||
@ApiPropertyOptional({ description: 'Matches key, title or description' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MaxLength(200)
|
||||
search?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: 'Only tickets without assignee' })
|
||||
@IsOptional()
|
||||
@Transform(toBoolean)
|
||||
@IsBoolean()
|
||||
unassigned?: boolean;
|
||||
|
||||
@ApiPropertyOptional({ type: Number, default: 50, minimum: 1, maximum: 200 })
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@@ -589,6 +623,76 @@ export class SetIssueReleaseDto {
|
||||
releaseId!: string | null;
|
||||
}
|
||||
|
||||
export class SavedFilterCriteriaDto {
|
||||
@ApiPropertyOptional({ type: [String], description: 'Ticket type ids' })
|
||||
@IsOptional()
|
||||
@Matches(SETTING_ID, { each: true })
|
||||
types?: string[];
|
||||
|
||||
@ApiPropertyOptional({ type: [String], description: 'Area ids' })
|
||||
@IsOptional()
|
||||
@Matches(SETTING_ID, { each: true })
|
||||
areas?: string[];
|
||||
|
||||
@ApiPropertyOptional({
|
||||
enum: IssuePriority,
|
||||
enumName: 'IssuePriority',
|
||||
isArray: true,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsEnum(IssuePriority, { each: true })
|
||||
priorities?: IssuePriority[];
|
||||
|
||||
@ApiPropertyOptional({
|
||||
type: String,
|
||||
nullable: true,
|
||||
description: 'Pireon user id',
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
assigneeId?: string | null;
|
||||
|
||||
@ApiPropertyOptional() @IsOptional() @IsBoolean() unassigned?: boolean;
|
||||
|
||||
@ApiPropertyOptional({ type: String, nullable: true, format: 'uuid' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
releaseId?: string | null;
|
||||
|
||||
@ApiPropertyOptional({ type: [String] })
|
||||
@IsOptional()
|
||||
@ArrayMaxSize(20)
|
||||
@IsString({ each: true })
|
||||
labels?: string[];
|
||||
|
||||
@ApiPropertyOptional({ type: String, nullable: true, maxLength: 200 })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MaxLength(200)
|
||||
search?: string | null;
|
||||
}
|
||||
|
||||
export class SaveFilterDto {
|
||||
@ApiProperty({ example: 'Bugs críticos de frontend', maxLength: 60 })
|
||||
@IsString()
|
||||
@MinLength(1)
|
||||
@MaxLength(60)
|
||||
name!: string;
|
||||
|
||||
@ApiPropertyOptional({
|
||||
default: false,
|
||||
description: 'Visible to the whole project (members, not viewers, share)',
|
||||
})
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
shared = false;
|
||||
|
||||
@ApiProperty({ type: SavedFilterCriteriaDto })
|
||||
@ValidateNested()
|
||||
@Type(() => SavedFilterCriteriaDto)
|
||||
criteria!: SavedFilterCriteriaDto;
|
||||
}
|
||||
|
||||
export class RankIssueDto {
|
||||
@ApiPropertyOptional({
|
||||
type: String,
|
||||
|
||||
@@ -191,6 +191,41 @@ export class IssueDto {
|
||||
@ApiProperty() version!: number;
|
||||
}
|
||||
|
||||
export class SavedFilterCriteriaResponseDto {
|
||||
@ApiPropertyOptional({ type: [String] }) types?: string[];
|
||||
@ApiPropertyOptional({ type: [String] }) areas?: string[];
|
||||
@ApiPropertyOptional({
|
||||
enum: IssuePriority,
|
||||
enumName: 'IssuePriority',
|
||||
isArray: true,
|
||||
})
|
||||
priorities?: IssuePriority[];
|
||||
@ApiPropertyOptional({ type: String, nullable: true })
|
||||
assigneeId?: string | null;
|
||||
@ApiPropertyOptional() unassigned?: boolean;
|
||||
@ApiPropertyOptional({ type: String, nullable: true, format: 'uuid' })
|
||||
releaseId?: string | null;
|
||||
@ApiPropertyOptional({ type: [String] }) labels?: string[];
|
||||
@ApiPropertyOptional({ type: String, nullable: true })
|
||||
search?: string | null;
|
||||
}
|
||||
|
||||
export class SavedFilterDto {
|
||||
@ApiProperty({ format: 'uuid' }) id!: string;
|
||||
@ApiProperty({ format: 'uuid' }) projectId!: string;
|
||||
@ApiProperty({ type: UserRefDto }) owner!: UserRefDto;
|
||||
@ApiProperty({ example: 'Bugs críticos de frontend' }) name!: string;
|
||||
@ApiProperty({ description: 'Visible to the whole project' })
|
||||
shared!: boolean;
|
||||
@ApiProperty({ type: SavedFilterCriteriaResponseDto })
|
||||
criteria!: SavedFilterCriteriaResponseDto;
|
||||
@ApiProperty({ format: 'date-time' }) createdAt!: string;
|
||||
}
|
||||
|
||||
export class SavedFilterIdDto {
|
||||
@ApiProperty({ format: 'uuid' }) id!: string;
|
||||
}
|
||||
|
||||
export class IssuePageDto {
|
||||
@ApiProperty({ type: [IssueDto] }) items!: IssueDto[];
|
||||
@ApiProperty({ description: 'Total matches (for pagination)' })
|
||||
|
||||
Reference in New Issue
Block a user