feat: sprints with burndown and carry-over
Plan sprints with dates and a goal, run one at a time per project, and put tickets in them from the ticket page. The Sprints tab follows the one under way with its progress and a burndown in tickets or points against the ideal line. Closing a sprint sends what was left to the next one or back to the backlog; the board can be filtered by sprint. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -594,6 +594,14 @@ const MAX_FILE_BYTES = 25 * 1024 * 1024;
|
||||
>
|
||||
<pi-label>Release</pi-label>
|
||||
</pi-select-field>
|
||||
<pi-select-field
|
||||
[options]="sprintOptions()"
|
||||
[disabled]="!project.canContribute() || sprintLocked()"
|
||||
[value]="issue.sprint?.id ?? ''"
|
||||
(valueChange)="facade.setSprint($event || null)"
|
||||
>
|
||||
<pi-label>Sprint</pi-label>
|
||||
</pi-select-field>
|
||||
<pi-select-field
|
||||
[options]="typeOptions()"
|
||||
[disabled]="!project.canContribute()"
|
||||
@@ -768,6 +776,30 @@ export class IssuePage {
|
||||
.map((r) => ({ value: r.id, label: r.name })),
|
||||
],
|
||||
);
|
||||
/** Open sprints, plus the ticket's own even if it closed since. */
|
||||
protected readonly sprintOptions = computed<PiSelectFieldOption<string>[]>(
|
||||
() => {
|
||||
const current = this.facade.issue()?.sprint;
|
||||
const open = this.project.openSprints();
|
||||
return [
|
||||
{ value: NONE, label: 'Backlog (sin sprint)' },
|
||||
...open.map((s) => ({
|
||||
value: s.id,
|
||||
label: s.status === 'ACTIVE' ? `${s.name} · en curso` : s.name,
|
||||
})),
|
||||
...(current && !open.some((s) => s.id === current.id)
|
||||
? [{ value: current.id, label: `${current.name} · cerrado` }]
|
||||
: []),
|
||||
];
|
||||
},
|
||||
);
|
||||
/** A closed sprint keeps its tickets. */
|
||||
protected readonly sprintLocked = computed(() => {
|
||||
const current = this.facade.issue()?.sprint;
|
||||
return (
|
||||
!!current && !this.project.openSprints().some((s) => s.id === current.id)
|
||||
);
|
||||
});
|
||||
protected readonly priorityOptions = options(PRIORITY);
|
||||
/** Active values, plus the ticket's own even if archived since. */
|
||||
protected readonly typeOptions = computed<PiSelectFieldOption<string>[]>(
|
||||
|
||||
Reference in New Issue
Block a user