feat: definition of done per project
A project can ask that tickets reach a DONE status only with their checklist ticked (settings.checklistBeforeDone, off by default; absent when saving means unchanged). Members get a 422 telling how many steps are left; owners and admins may still close it. Settings has the switch and the ticket's checklist says when the project asks for it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -27,6 +27,8 @@ export interface SettingsPayload {
|
||||
template?: { description?: string | null; checklist?: string[] } | null;
|
||||
}[];
|
||||
areas: { id: string; name: string; archived: boolean }[];
|
||||
/** Definition of done. Absent when saving: unchanged. */
|
||||
checklistBeforeDone?: boolean;
|
||||
/** Absent when saving: unchanged. */
|
||||
customFields?: {
|
||||
id: string;
|
||||
@@ -41,6 +43,7 @@ export function toSettingsPayload(settings: ProjectSettings): SettingsPayload {
|
||||
return {
|
||||
...settings,
|
||||
customFields: settings.customFields ?? [],
|
||||
checklistBeforeDone: !!settings.checklistBeforeDone,
|
||||
transitions: settings.statuses.map((s) => ({
|
||||
from: s.id,
|
||||
to: settings.transitions[s.id] ?? [],
|
||||
@@ -72,6 +75,9 @@ export function fromSettingsPayload(payload: SettingsPayload): ProjectSettings {
|
||||
: {}),
|
||||
})),
|
||||
areas: payload.areas,
|
||||
...(payload.checklistBeforeDone != null
|
||||
? { checklistBeforeDone: payload.checklistBeforeDone }
|
||||
: {}),
|
||||
...(payload.customFields
|
||||
? {
|
||||
customFields: payload.customFields.map((f) => ({
|
||||
|
||||
@@ -772,6 +772,15 @@ export class ProjectSettingsInput {
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => CustomFieldDefinitionInput)
|
||||
customFields?: CustomFieldDefinitionInput[];
|
||||
|
||||
@Field({
|
||||
nullable: true,
|
||||
description:
|
||||
'Definition of done: DONE only with the checklist ticked. Absent: unchanged',
|
||||
})
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
checklistBeforeDone?: boolean;
|
||||
}
|
||||
|
||||
@InputType({
|
||||
|
||||
@@ -115,6 +115,11 @@ export class ProjectSettingsGql {
|
||||
@Field(() => [AreaOptionGql]) areas!: AreaOptionGql[];
|
||||
@Field(() => [CustomFieldDefinitionGql])
|
||||
customFields!: CustomFieldDefinitionGql[];
|
||||
@Field({
|
||||
description:
|
||||
'Definition of done: tickets reach DONE only with their checklist ticked (owners and admins may override)',
|
||||
})
|
||||
checklistBeforeDone!: boolean;
|
||||
}
|
||||
|
||||
@ObjectType('Project')
|
||||
|
||||
@@ -318,6 +318,14 @@ export class ProjectSettingsBodyDto {
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => CustomFieldDefinitionBodyDto)
|
||||
customFields?: CustomFieldDefinitionBodyDto[];
|
||||
|
||||
@ApiPropertyOptional({
|
||||
description:
|
||||
'Definition of done: tickets reach a DONE status only with their checklist ticked (owners and admins may override). Absent: unchanged',
|
||||
})
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
checklistBeforeDone?: boolean;
|
||||
}
|
||||
|
||||
export class AnalyticsQueryDto {
|
||||
|
||||
@@ -103,6 +103,11 @@ export class ProjectSettingsDto {
|
||||
@ApiProperty({ type: [AreaOptionDto] }) areas!: AreaOptionDto[];
|
||||
@ApiProperty({ type: [CustomFieldDefinitionDto] })
|
||||
customFields!: CustomFieldDefinitionDto[];
|
||||
@ApiProperty({
|
||||
description:
|
||||
'Definition of done: tickets reach DONE only with their checklist ticked',
|
||||
})
|
||||
checklistBeforeDone!: boolean;
|
||||
}
|
||||
|
||||
export class ProjectDto {
|
||||
|
||||
Reference in New Issue
Block a user