33 lines
3.0 KiB
TypeScript
33 lines
3.0 KiB
TypeScript
import type { BoardIssue, BoardSnapshot } from "../../../../api/types.ts";
|
||
import { EPICS, KEY_RE, NO_EPIC, NOT_IN_HUB } from "../constants.ts";
|
||
import type { BoardModel, BoardNode, Dicts, Link } from "../types.ts";
|
||
import { addLink, addStubs } from "./links.ts";
|
||
import { sortableDate } from "./util.ts";
|
||
|
||
// снимок хаба (GET /board) → модель доски. Эпики («Фича»/Epic) — имена дорожек, не карточки; соседи по связям — обычные карточки;
|
||
// вид работы — первая метка kind-*, иначе тип задачи; срок — плановая дата окончания, иначе срок исполнения; связи — только известных
|
||
// типов (dicts.linkTypes), между ключами вида AURORA-1234 (ключ идёт в разметку карточки) и не с эпиками; ключи из связей, которых нет в зеркале, — заглушки на дорожке «Нет в зеркале»
|
||
export function fromHub(snap: BoardSnapshot, dicts: Dicts): BoardModel {
|
||
const isEpic = (it: BoardIssue) => /^(Фича|Epic|Эпик)$/i.test(it.issue_type || "");
|
||
const epicNames: Record<string, string> = { ...EPICS }, epics = new Set<string>();
|
||
snap.issues.forEach((it) => { if (isEpic(it)) { epics.add(it.key); epicNames[it.key] = it.summary || it.key; } });
|
||
const nodes: BoardNode[] = [], links: Link[] = [], seen = new Set<string>(), sprints: Record<string, number> = {};
|
||
snap.issues.forEach((it) => {
|
||
if (isEpic(it) || !KEY_RE.test(it.key)) return;
|
||
const label = (it.labels || []).find((l) => dicts.kindLabels[l]), sprint = it.sprint || "";
|
||
if (sprint) sprints[sprint] = (sprints[sprint] || 0) + 1;
|
||
nodes.push({ key: it.key, title: it.summary || "", kind: label ? dicts.kindLabels[label] : (it.issue_type || ""), prio: it.priority || "",
|
||
due: sortableDate(it.planned_end || it.duedate || ""), status: it.status || "",
|
||
epic: it.epic_key ? (epicNames[it.epic_key] || it.epic_key) : NO_EPIC, sprint, who: it.assignee || "", stub: false });
|
||
});
|
||
snap.links.forEach((l) => {
|
||
const type = dicts.linkTypes[l.link_type];
|
||
if (type && KEY_RE.test(l.source) && KEY_RE.test(l.target) && !epics.has(l.source) && !epics.has(l.target)) addLink(links, seen, l.source, l.target, type);
|
||
});
|
||
const missing = addStubs(nodes, links, NOT_IN_HUB);
|
||
const problems = snap.last_sync ? [] : ["в хабе ещё не было полного обновления из Jira — нажмите «Обновить из Jira»"];
|
||
// фильтр спринтов — только по своим задачам: спринт соседа из другого проекта не делает канбан-проект «спринтовым»
|
||
const hasSprint = snap.issues.some((it) => !it.neighbor && !!it.sprint);
|
||
return { nodes, links, sprints, fileName: "Хаб", problems, hasSprint, missing, stubLane: NOT_IN_HUB };
|
||
}
|