feat: work-in-progress limits and swimlanes on the board

Each status can carry a WIP limit in the project settings; the board shows
it next to the count, marks a column that goes over it and says so when a
card is dropped there. The board can also be grouped in rows by person,
epic, priority or type, remembered per browser.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 15:09:21 +02:00
parent 6aec774c92
commit 09bd8c19a3
23 changed files with 563 additions and 74 deletions

View File

@@ -135,7 +135,8 @@ function idFrom(name: string): string {
</header>
<div class="ts-rows-head ts-status-grid" aria-hidden="true">
<span></span><span>Nombre</span><span>Categoría</span
><span>Color</span><span>Pide motivo</span><span></span>
><span>Color</span><span>Límite WIP</span><span>Pide motivo</span
><span></span>
</div>
<ol
class="ts-rows"
@@ -198,6 +199,21 @@ function idFrom(name: string): string {
</option>
}
</select>
<input
class="ts-input"
type="number"
min="1"
max="999"
placeholder="—"
[attr.aria-label]="'Límite WIP de ' + status.name"
title="Cuántos tickets debería tener la columna como mucho (vacío: sin límite)"
[value]="status.wipLimit ?? ''"
(change)="
edit('statuses', i, {
wipLimit: wipFrom($any($event.target).value),
})
"
/>
<label class="ts-check">
<input
type="checkbox"
@@ -693,7 +709,10 @@ function idFrom(name: string): string {
}
.ts-status-grid {
display: grid;
grid-template-columns: 1.25rem minmax(10rem, 1fr) 9rem 8rem 5.5rem 6.5rem;
grid-template-columns: 1.25rem minmax(
10rem,
1fr
) 9rem 8rem 5.5rem 5.5rem 6.5rem;
align-items: center;
gap: 0.5rem;
}
@@ -996,6 +1015,12 @@ export class SettingsPage {
?.to.includes(to);
}
/** '' (or anything below 1) clears the limit. */
protected wipFrom(value: string): number | null {
const limit = Math.round(Number(value));
return Number.isFinite(limit) && limit >= 1 ? Math.min(limit, 999) : null;
}
protected edit(section: Section, index: number, changes: object): void {
this.patch((d) => Object.assign(d[section][index], changes));
}