Files
kandev/apps/web/lib/kanban/task-order.ts
T
José Almeida 5105ac224c feat: cmd+click and shift+click multi-select for kanban and sidebar (#1518)
* feat: add anchored range selection to multi-select reducer

* feat: cmd+click and shift+click multi-select on kanban board

* feat: add cmd/shift multi-select to sidebar task list

* test: e2e coverage for cmd/shift multi-select

* fix: harden multi-select selection lifecycle from review feedback

* test: scope multi-select e2e helpers to active containers

* fix: add sidebar multi-select hook tests and tighten bulk-action lifecycle

* fix: prune hidden sidebar selections and order bulk moves by view

* test: cover visible-order bulk move and anchor realignment

* fix: harden sidebar bulk-move scope and keyboard selection parity

* fix: order kanban bulk moves by board position

* test: cover multi-select helpers and fix stale-id sort fallback

* fix: order kanban card context-menu moves by board position

* feat: sidebar multi-select shows only bulk-valid actions with bulk pin and delete

* fix: harden multi-select bulk ordering, selection clearing, and a11y

* fix: gate kanban card move-to-step for mixed-workflow selections

* fix: unpin fully pinned sidebar selections

* refactor: keep sidebar task components under limits

* test: restore sidebar selection console spy safely
2026-07-06 17:16:14 +01:00

33 lines
1.2 KiB
TypeScript

type CreatedTask = {
createdAt?: string;
};
function createdAtTime(task: CreatedTask): number {
if (!task.createdAt) return Number.NEGATIVE_INFINITY;
const time = Date.parse(task.createdAt);
return Number.isNaN(time) ? Number.NEGATIVE_INFINITY : time;
}
export function compareTasksByCreatedDesc(a: CreatedTask, b: CreatedTask): number {
const aTime = createdAtTime(a);
const bTime = createdAtTime(b);
if (bTime > aTime) return 1;
if (bTime < aTime) return -1;
return 0;
}
/**
* Sort `ids` into the board's visible created-desc order using `taskById` for
* lookups. Ids without a known task keep their relative order. Used before a
* kanban bulk move so a backward range selection doesn't land scrambled when
* sequential positions are assigned.
*/
export function sortIdsByCreatedDesc(ids: string[], taskById: Map<string, CreatedTask>): string[] {
// Missing ids fall back to `{}`, which `compareTasksByCreatedDesc` treats as
// the oldest (sorts last) — keeping the comparator transitive rather than
// returning 0 whenever either side is unknown.
return [...ids].sort((a, b) =>
compareTasksByCreatedDesc(taskById.get(a) ?? {}, taskById.get(b) ?? {}),
);
}