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:
2026-10-15 14:39:24 +02:00
parent 5b0396bc10
commit e598f76e1c
25 changed files with 285 additions and 4 deletions

View File

@@ -231,6 +231,12 @@ a.ts-key {
white-space: nowrap;
}
.ts-checklist__rule {
margin: 0 0 0.5rem;
color: var(--ts-muted);
font-size: 0.8125rem;
}
.ts-checklist,
.ts-children {
display: grid;

View File

@@ -268,6 +268,14 @@ const MAX_FILE_BYTES = 25 * 1024 * 1024;
>
}
</h2>
@if (
project.workflow().settings.checklistBeforeDone &&
facade.checklistProgress().done < facade.checklistProgress().total
) {
<p class="ts-checklist__rule">
Este proyecto pide marcarla entera antes de darlo por hecho.
</p>
}
@if (issue.checklist.length) {
<ul class="ts-checklist">
@for (item of issue.checklist; track item.id) {

View File

@@ -530,6 +530,33 @@ function idFrom(name: string): string {
</ol>
</section>
<!-- Definition of done -->
<section class="ts-panel ts-block" aria-labelledby="dod-title">
<header class="ts-block__head">
<div>
<h3 id="dod-title">Definición de «Hecho»</h3>
<p class="ts-muted">
Un ticket no pasa a un estado «Hecho» con su checklist a
medias. El propietario y los admins sí pueden cerrarlo.
</p>
</div>
<label class="ts-switch">
<input
type="checkbox"
role="switch"
[checked]="!!d.checklistBeforeDone"
(change)="
setChecklistBeforeDone($any($event.target).checked)
"
/>
<span class="ts-switch__track" aria-hidden="true"></span>
<span>{{
d.checklistBeforeDone ? 'Activada' : 'Desactivada'
}}</span>
</label>
</header>
</section>
<!-- Custom fields -->
<section class="ts-panel ts-block" aria-labelledby="cf-title">
<header class="ts-block__head">
@@ -1396,6 +1423,12 @@ export class SettingsPage {
);
}
protected setChecklistBeforeDone(on: boolean): void {
this.patch((d) => {
d.checklistBeforeDone = on;
});
}
protected addField(): void {
this.patch((d) =>
d.customFields.push({