36 lines
2.6 KiB
TypeScript
36 lines
2.6 KiB
TypeScript
// полный снимок доски: все задачи и связи, обе раскладки относительно дорожек (layout — обычная, layoutByDate — «по датам»; h только если задана вручную),
|
||
// порядок и свёртка дорожек, фильтры. Текущую раскладку компонент сохраняет в хранилище (saveLayout) перед вызовом
|
||
import { JIRA_URL } from "./constants.ts";
|
||
import { colWidths, foldedSet, laneOrder, savedLayout } from "./storage.ts";
|
||
import type { BoardModel, Filters, Visible } from "./types.ts";
|
||
|
||
type Saved = Record<string, { x: number; ry: number; w?: number; h?: number }>;
|
||
|
||
export function exportJson(model: BoardModel, vis: Visible, f: Filters, now: string): unknown {
|
||
const savedPos = (savedLayout(false) || {}) as Saved, savedDate = (savedLayout(true) || {}) as Saved;
|
||
const shown = new Set(vis.nodes.map((n) => n.key));
|
||
const fromSaved = (saved: Saved, k: string) => {
|
||
const r = saved[k]; if (!r) return null;
|
||
const o: { x: number; ry: number; w?: number; h?: number } = { x: r.x, ry: r.ry };
|
||
if (typeof r.w === "number") o.w = r.w; // запись без w допустима (как в эталоне)
|
||
if (typeof r.h === "number") o.h = r.h;
|
||
return o;
|
||
};
|
||
const nodes = model.nodes.filter((n) => !n.stub).map((n) => ({
|
||
key: n.key, title: n.title, status: n.status, priority: n.prio, kind: n.kind, due: n.due || null, assignee: n.who || null, sprint: n.sprint || null, epic: n.epic,
|
||
url: `${JIRA_URL}/browse/${n.key}`, visible: shown.has(n.key), layout: fromSaved(savedPos, n.key), layoutByDate: fromSaved(savedDate, n.key),
|
||
}));
|
||
const order = laneOrder();
|
||
return {
|
||
format: "arm-ka-links/1", exportedAt: now, source: model.fileName,
|
||
filters: { sprints: [...f.sprints], assignees: [...f.who], neighbors: f.neighbors, onlyLinked: f.onlyLinked, onlyHand: f.onlyHand, criticalPath: f.crit, byDate: f.byDate,
|
||
hiddenKinds: [...f.hideKind], hiddenEdges: [...f.hideEdge] },
|
||
laneOrder: order.length ? order : vis.lanes.map((l) => l.name), collapsedLanes: [...foldedSet()], dateColumns: colWidths(),
|
||
nodes, links: model.links.map((l) => ({ from: l.src, to: l.dst, type: l.type })),
|
||
};
|
||
}
|
||
// имя файла выгрузки: links-<имя исходного файла без .csv>-<дата>.json
|
||
export function exportFileName(model: BoardModel, now: string): string {
|
||
return `links-${(model.fileName || "board").replace(/[^\wА-Яа-яЁё.-]+/g, "_").replace(/\.csv$/i, "")}-${now.slice(0, 10)}.json`;
|
||
}
|