feat: bulk edit tickets
Select several tickets in the backlog and change their status, assignee, sprint, priority or labels at once. Each ticket goes through the normal rules and may refuse on its own; the result says which did. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -279,6 +279,49 @@ export class SaveFilterInput {
|
||||
criteria!: SavedFilterCriteriaInput;
|
||||
}
|
||||
|
||||
@InputType()
|
||||
export class BulkUpdateIssuesInput {
|
||||
@Field(() => [ID])
|
||||
@IsArray()
|
||||
@ArrayMaxSize(100)
|
||||
@IsUUID('all', { each: true })
|
||||
issueIds!: string[];
|
||||
@Field({ nullable: true }) @IsOptional() @Matches(SETTING_ID) status?: string;
|
||||
@Field({ nullable: true, description: 'Unassign everything' })
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
unassign?: boolean;
|
||||
@Field(() => ID, { nullable: true })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
assigneeId?: string;
|
||||
@Field({ nullable: true, description: 'Back to the backlog' })
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
noSprint?: boolean;
|
||||
@Field(() => ID, { nullable: true })
|
||||
@IsOptional()
|
||||
@IsUUID()
|
||||
sprintId?: string;
|
||||
@Field({ nullable: true, description: 'Out of their release' })
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
noRelease?: boolean;
|
||||
@Field(() => ID, { nullable: true })
|
||||
@IsOptional()
|
||||
@IsUUID()
|
||||
releaseId?: string;
|
||||
@Field(() => IssuePriority, { nullable: true })
|
||||
@IsOptional()
|
||||
@IsEnum(IssuePriority)
|
||||
priority?: IssuePriority;
|
||||
@Field(() => [String], { nullable: true })
|
||||
@IsOptional()
|
||||
@ArrayMaxSize(10)
|
||||
@IsString({ each: true })
|
||||
addLabels?: string[];
|
||||
}
|
||||
|
||||
@InputType()
|
||||
export class AutomationTriggerInput {
|
||||
@Field(() => AutomationTriggerKind)
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
} from '@task-stream/api/tracker/domain';
|
||||
import {
|
||||
AddChecklistItemInput,
|
||||
BulkUpdateIssuesInput,
|
||||
ChangeIssueStatusInput,
|
||||
CreateIssueInput,
|
||||
IssueFilterInput,
|
||||
@@ -34,8 +35,10 @@ import {
|
||||
} from './inputs';
|
||||
import { withoutNulls } from '../common/issue-input';
|
||||
import { viewerOf } from '../common/viewer';
|
||||
import { toBulkChange } from '../common/bulk';
|
||||
import {
|
||||
ActivityGql,
|
||||
BulkResultGql,
|
||||
CommandResultGql,
|
||||
CommentPageGql,
|
||||
EpicGql,
|
||||
@@ -280,6 +283,21 @@ export class IssueResolver {
|
||||
);
|
||||
}
|
||||
|
||||
@Mutation(() => BulkResultGql, {
|
||||
description:
|
||||
'The same change on up to 100 tickets; each goes through the normal rules and may refuse on its own',
|
||||
})
|
||||
bulkUpdateIssues(
|
||||
@CurrentUser() me: User,
|
||||
@Args('input') input: BulkUpdateIssuesInput,
|
||||
) {
|
||||
return this.issuesService.bulkUpdate(
|
||||
me.id,
|
||||
input.issueIds,
|
||||
toBulkChange(input),
|
||||
);
|
||||
}
|
||||
|
||||
@Mutation(() => CommandResultGql, {
|
||||
description: "Add a step to a ticket's checklist",
|
||||
})
|
||||
|
||||
@@ -240,6 +240,19 @@ export class AutomationGql {
|
||||
lastError!: string | null;
|
||||
}
|
||||
|
||||
@ObjectType('BulkIssueResult')
|
||||
export class BulkIssueResultGql {
|
||||
@Field(() => ID) issueId!: string;
|
||||
@Field() ok!: boolean;
|
||||
@Field(() => String, { nullable: true }) error!: string | null;
|
||||
}
|
||||
|
||||
@ObjectType('BulkResult')
|
||||
export class BulkResultGql {
|
||||
@Field(() => Int) updated!: number;
|
||||
@Field(() => [BulkIssueResultGql]) results!: BulkIssueResultGql[];
|
||||
}
|
||||
|
||||
@ObjectType('WebhookDelivery')
|
||||
export class WebhookDeliveryGql {
|
||||
@Field() at!: string;
|
||||
|
||||
Reference in New Issue
Block a user