first commit
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
import {
|
||||
BoardColumn,
|
||||
BoardFilter,
|
||||
IssueStatus,
|
||||
IssueSummary,
|
||||
} from '@task-stream/web/tracker/domain';
|
||||
|
||||
/** Pure board transformations (unit tested). */
|
||||
|
||||
export function findIssue(
|
||||
columns: BoardColumn[],
|
||||
issueId: string,
|
||||
): IssueSummary | undefined {
|
||||
for (const column of columns) {
|
||||
const issue = column.issues.find((i) => i.id === issueId);
|
||||
if (issue) return issue;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function matchesFilter(
|
||||
issue: IssueSummary,
|
||||
filter: BoardFilter | null,
|
||||
): boolean {
|
||||
if (!filter) return true;
|
||||
if (filter.assigneeId && issue.assignee?.id !== filter.assigneeId)
|
||||
return false;
|
||||
if (filter.releaseId && issue.release?.id !== filter.releaseId) return false;
|
||||
if (filter.area && issue.area !== filter.area) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Removes the issue wherever it is and puts `next` (if any) on top of its status column. */
|
||||
export function placeIssue(
|
||||
columns: BoardColumn[],
|
||||
issueId: string,
|
||||
next: IssueSummary | null,
|
||||
): BoardColumn[] {
|
||||
return columns.map((column) => {
|
||||
const had = column.issues.some((i) => i.id === issueId);
|
||||
let issues = had
|
||||
? column.issues.filter((i) => i.id !== issueId)
|
||||
: column.issues;
|
||||
let total = column.total - (had ? 1 : 0);
|
||||
if (next && next.status === column.status) {
|
||||
issues = [next, ...issues];
|
||||
total += 1;
|
||||
}
|
||||
return had || issues !== column.issues
|
||||
? { ...column, issues, total }
|
||||
: column;
|
||||
});
|
||||
}
|
||||
|
||||
/** Optimistic move. */
|
||||
export function moveIssue(
|
||||
columns: BoardColumn[],
|
||||
issueId: string,
|
||||
to: IssueStatus,
|
||||
): BoardColumn[] {
|
||||
const issue = findIssue(columns, issueId);
|
||||
return issue
|
||||
? placeIssue(columns, issueId, { ...issue, status: to })
|
||||
: columns;
|
||||
}
|
||||
|
||||
/** Merges a realtime change, ignoring stale versions and issues outside the filter. */
|
||||
export function applyIssueChange(
|
||||
columns: BoardColumn[],
|
||||
issue: IssueSummary,
|
||||
filter: BoardFilter | null,
|
||||
): BoardColumn[] {
|
||||
const current = findIssue(columns, issue.id);
|
||||
if (current && current.version > issue.version) return columns;
|
||||
return placeIssue(
|
||||
columns,
|
||||
issue.id,
|
||||
matchesFilter(issue, filter) ? issue : null,
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user