feat: import and export tickets as CSV

Every ticket of a project can be downloaded as CSV, and a CSV exported
from TaskStream or from Jira can be imported: types, statuses, priorities
and people are matched by id or name, the rest falls back with a warning,
and parents are rebuilt. The settings page previews an import before it
creates anything.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 15:43:02 +02:00
parent d43fc620e9
commit 1076205acc
24 changed files with 1666 additions and 31 deletions

View File

@@ -754,6 +754,17 @@ export class UpdateWebhookDto extends PartialType(CreateWebhookDto) {
active?: boolean;
}
export class ImportQueryDto {
@ApiPropertyOptional({
default: false,
description: 'Only tell what would be created',
})
@IsOptional()
@Transform(toBoolean)
@IsBoolean()
dryRun = false;
}
export class RankIssueDto {
@ApiPropertyOptional({
type: String,

View File

@@ -194,6 +194,25 @@ export class WebhookCreatedDto {
secret!: string;
}
export class ImportLineDto {
@ApiProperty({ description: 'Line of the file (the header is 1)' })
line!: number;
@ApiPropertyOptional() reason?: string;
@ApiPropertyOptional() message?: string;
}
export class ImportReportDto {
@ApiProperty({ enum: ['taskstream', 'jira'] }) format!: string;
@ApiProperty({ description: 'Nothing was created: a preview' })
dryRun!: boolean;
@ApiProperty({ description: 'Rows that become tickets' }) rows!: number;
@ApiProperty() created!: number;
@ApiProperty({ type: [String], example: ['WEB-41', 'WEB-42'] })
keys!: string[];
@ApiProperty({ type: [ImportLineDto] }) skipped!: ImportLineDto[];
@ApiProperty({ type: [ImportLineDto] }) warnings!: ImportLineDto[];
}
export class GitDeliveryResultDto {
@ApiProperty({ description: 'Tickets that got something new' })
recorded!: number;