feat: custom fields per project

Text, number, date or option-list fields defined in the project settings
(archived, never removed; their type is fixed once saved). Tickets hold
them, edited in the side panel, listed under the title and filtered by
option in the list view; also over GraphQL, REST (?field=ID:value) and MCP.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-15 09:31:12 +02:00
parent 233c46e9fa
commit f7e850068b
44 changed files with 1909 additions and 96 deletions

View File

@@ -1,5 +1,6 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import {
CustomFieldType,
IssueLinkType,
IssuePriority,
NotificationKind,
@@ -78,6 +79,20 @@ export class AreaOptionDto {
@ApiProperty() archived!: boolean;
}
export class CustomFieldDefinitionDto {
@ApiProperty({ example: 'BROWSER' }) id!: string;
@ApiProperty({ example: 'Navegador' }) name!: string;
@ApiProperty({
enum: CustomFieldType,
enumName: 'CustomFieldType',
description: 'DATE values are YYYY-MM-DD',
})
type!: CustomFieldType;
@ApiProperty({ type: [String], description: 'The choices of a SELECT field' })
options!: string[];
@ApiProperty() archived!: boolean;
}
export class ProjectSettingsDto {
@ApiProperty({ type: [WorkflowStatusDto], description: 'In board order' })
statuses!: WorkflowStatusDto[];
@@ -86,6 +101,8 @@ export class ProjectSettingsDto {
@ApiProperty({ type: [IssueTypeOptionDto] })
issueTypes!: IssueTypeOptionDto[];
@ApiProperty({ type: [AreaOptionDto] }) areas!: AreaOptionDto[];
@ApiProperty({ type: [CustomFieldDefinitionDto] })
customFields!: CustomFieldDefinitionDto[];
}
export class ProjectDto {
@@ -426,6 +443,13 @@ export class IssueDto {
startDate!: string | null;
@ApiProperty({ type: String, nullable: true, format: 'date' })
dueDate!: string | null;
@ApiProperty({
type: 'object',
additionalProperties: { type: 'string' },
example: { BROWSER: 'Safari' },
description: 'Custom field id → value (only those set)',
})
customFields!: Record<string, string>;
@ApiProperty({ type: [IssueLinkDto] }) links!: IssueLinkDto[];
@ApiProperty({ type: [AttachmentDto] }) attachments!: AttachmentDto[];
@ApiProperty({ type: [UserRefDto], description: 'People following it' })