feat: a trash for tickets
Deleting a ticket now sends it to the trash, for whoever opened it or an admin: it disappears from boards, searches and statistics, cannot change, and comes back from the ticket page or the trash page for 30 days. After that it is deleted for good with the usual cascade. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -290,6 +290,36 @@ export class IssueResolver {
|
||||
);
|
||||
}
|
||||
|
||||
@Mutation(() => CommandResultGql, {
|
||||
description:
|
||||
'To the trash (whoever opened it, or an owner/admin): hidden everywhere, deleted for good after 30 days',
|
||||
})
|
||||
trashIssue(
|
||||
@CurrentUser() me: User,
|
||||
@Args('issueId', { type: () => ID }) issueId: string,
|
||||
) {
|
||||
return this.issuesService.trash(me.id, issueId);
|
||||
}
|
||||
|
||||
@Mutation(() => CommandResultGql, { description: 'Back from the trash' })
|
||||
restoreIssue(
|
||||
@CurrentUser() me: User,
|
||||
@Args('issueId', { type: () => ID }) issueId: string,
|
||||
) {
|
||||
return this.issuesService.restore(me.id, issueId);
|
||||
}
|
||||
|
||||
@OptionalAuth()
|
||||
@Query(() => [IssueGql], {
|
||||
description: "A project's tickets in the trash, newest first",
|
||||
})
|
||||
trash(
|
||||
@CurrentUser() me: User | undefined,
|
||||
@Args('projectId', { type: () => ID }) projectId: string,
|
||||
) {
|
||||
return this.issuesService.trashed(viewerOf(me), projectId);
|
||||
}
|
||||
|
||||
@Mutation(() => BulkResultGql, {
|
||||
description:
|
||||
'The same change on up to 100 tickets; each goes through the normal rules and may refuse on its own',
|
||||
|
||||
@@ -342,6 +342,11 @@ export class IssueGql {
|
||||
})
|
||||
rank!: string;
|
||||
@Field(() => [ChecklistItemGql]) checklist!: ChecklistItemGql[];
|
||||
@Field(() => String, {
|
||||
nullable: true,
|
||||
description: 'In the trash since then; null when it is not',
|
||||
})
|
||||
trashedAt!: string | null;
|
||||
@Field(() => [DevLinkGql], {
|
||||
description: 'Commits, branches and pull requests that mention it',
|
||||
})
|
||||
|
||||
@@ -309,6 +309,13 @@ export class IssueDto {
|
||||
})
|
||||
rank!: string;
|
||||
@ApiProperty({ type: [ChecklistItemDto] }) checklist!: ChecklistItemDto[];
|
||||
@ApiProperty({
|
||||
type: String,
|
||||
nullable: true,
|
||||
format: 'date-time',
|
||||
description: 'In the trash since then; null when it is not',
|
||||
})
|
||||
trashedAt!: string | null;
|
||||
@ApiProperty({
|
||||
type: [DevLinkDto],
|
||||
description: 'Commits, branches and pull requests that mention it',
|
||||
|
||||
@@ -311,6 +311,47 @@ export class IssuesController {
|
||||
);
|
||||
}
|
||||
|
||||
@Delete('issues/:issue')
|
||||
@ISSUE
|
||||
@ApiOperation({
|
||||
summary: 'Move the ticket to the trash',
|
||||
description:
|
||||
'Whoever opened it, or an owner/admin. Hidden everywhere; restore it within 30 days or it is deleted for good.',
|
||||
})
|
||||
@ApiOkResponse({ type: CommandResultDto })
|
||||
@ApiCommandErrors()
|
||||
async trash(@CurrentUser() me: User, @Param('issue') issue: string) {
|
||||
return this.issues.trash(me.id, await this.refs.issueId(me.id, issue));
|
||||
}
|
||||
|
||||
@Post('issues/:issue/restore')
|
||||
@HttpCode(200)
|
||||
@ISSUE
|
||||
@ApiOperation({ summary: 'Bring the ticket back from the trash' })
|
||||
@ApiOkResponse({ type: CommandResultDto })
|
||||
@ApiCommandErrors()
|
||||
async restore(@CurrentUser() me: User, @Param('issue') issue: string) {
|
||||
return this.issues.restore(me.id, await this.refs.issueId(me.id, issue));
|
||||
}
|
||||
|
||||
@Get('projects/:project/trash')
|
||||
@ApiOptionalPireonAuth()
|
||||
@PROJECT
|
||||
@ApiOperation({ summary: "The project's tickets in the trash, newest first" })
|
||||
@ApiOkResponse({ type: [IssueDto] })
|
||||
@ApiReadErrors()
|
||||
async trashed(
|
||||
@CurrentUser() me: User | undefined,
|
||||
@Param('project') project: string,
|
||||
) {
|
||||
return this.refs.issueDtos(
|
||||
await this.issues.trashed(
|
||||
viewerOf(me),
|
||||
await this.refs.projectId(viewerOf(me), project),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@Post('issues/bulk')
|
||||
@HttpCode(200)
|
||||
@ApiOperation({
|
||||
|
||||
Reference in New Issue
Block a user