import { Link, useSearchParams } from "react-router"; import type { Project } from "../../../api/types.ts"; import { PageHeader, Panel } from "../../../ui/index.ts"; import type { AgileSprint } from "../api/types.ts"; import { RefreshButton } from "../RefreshButton.tsx"; import { AgileGate } from "./AgileGate.tsx"; import { BoardColumns } from "./BoardColumns.tsx"; import { AgileToolbar } from "./AgileToolbar.tsx"; import { ColumnsMenu } from "./ColumnsMenu.tsx"; import { columnsOf } from "./columns.ts"; import { assigneeOptions, matches, parseSprintIds, selectableSprints, sprintIssues } from "./filters.ts"; import { SprintPicker } from "./SprintPicker.tsx"; import { useAgileView } from "./useAgileView.ts"; import { daysLeft, fmtRange, fmtSp, tasksWord } from "./model.ts"; import "./agile.css"; function SprintHead({ s }: { s: AgileSprint }) { const left = s.state === "active" ? daysLeft(s.end_date, new Date()) : null; return (

{s.name}

{fmtRange(s.start_date, s.end_date)} {left !== null && {left >= 0 ? `осталось ${left} дн.` : "срок прошёл"}} {s.goal && {s.goal}} {`${s.count_done} из ${s.count} ${tasksWord(s.count)}`} {`${fmtSp(s.points_done)} из ${fmtSp(s.points)} SP`}
); } // «Спринт» (spec web-app): колонки доски выбранных спринтов (по умолчанию все активные); только просмотр export function SprintPage({ project }: { project: Project }) { const [params, setParams] = useSearchParams(); const { view, set, setQ, filter, reset } = useAgileView(project.label, "sprint"); return (
} /> {(d) => { const selectable = selectableSprints(d.sprints); const ids = parseSprintIds(params.get("sprint"), d.sprints); const chosen = selectable.filter((s) => ids.includes(s.id)); const issues = sprintIssues(chosen); const shown = issues.filter((i) => matches(i, filter)); const cols = columnsOf(d.board?.columns ?? null, shown); const allNames = columnsOf(d.board?.columns ?? null, issues).map((c) => c.name); // меню — по задачам без фильтров (T7.2) // выбор спринтов — в адресе, без новой записи истории const pick = (next: number[]) => setParams((p) => { const n = new URLSearchParams(p); n.set("sprint", next.join(",")); return n; }, { replace: true }); return ( <> {selectable.length > 0 && } {chosen.length > 0 && {chosen.length === 0 ? (

Нет активного спринта

Бэклог
) : ( <> {chosen.map((s) => )}
); }