Виджеты
Gantt
Диаграмма Ганта с зависимостями и критическим путём.
Диаграмма Ганта: элементы с датами как полосы, которые можно двигать и растягивать за края. Зависимости рисуются стрелками, критический путь подсвечивается.
Установка
npx @toimetdev/pathlogs-ui add ganttПример
<Gantt
items={tasks}
edges={links.filter((l) => l.type === "BLOCKS")}
locale="ru-RU"
renderLabel={(task) => (
<>
<span className="font-mono text-[11px] text-muted">UI-{task.number}</span>
<span className="truncate">{task.title}</span>
</>
)}
barColor={(task) => STATUS_COLORS[task.status]}
onChangeDates={(id, dates) => updateTaskAction(id, dates)}
onOpenItem={(task) => router.push(`/tasks/${task.id}`)}
/>Потяните полосу целиком или за её край. Полотно листается протяжкой по обеим осям, стрелки прокручивают, Home и End прыгают к краям.
Пропсы
| Проп | Тип | По умолчанию | Описание |
|---|---|---|---|
items* | I[] | — | Элементы. Нужны id, startDate и dueDate — строки вида 2026-02-14. |
renderLabel* | (item: I) => ReactNode | — | Подпись строки в левой колонке. |
edges | { fromId, toId }[] | [] | Связи «from блокирует to»: стрелки и критический путь. |
onChangeDates | (itemId, { startDate, dueDate }) => void | Promise | — | Новые даты после перетаскивания. Без него диаграмма только для чтения. |
onOpenItem | (item: I) => void | — | Клик по полосе. |
barColor | (item: I) => string | — | Цвет полосы — обычно по статусу. Перебивается полем item.color. |
locale | string | — | Локаль подписей шкалы. По умолчанию — локаль браузера. |
labels | GanttLabels | — | Подписи. По умолчанию английские. |
items*I[]Элементы. Нужны id, startDate и dueDate — строки вида 2026-02-14.
renderLabel*(item: I) => ReactNodeПодпись строки в левой колонке.
edges{ fromId, toId }[]по умолчанию: []
Связи «from блокирует to»: стрелки и критический путь.
onChangeDates(itemId, { startDate, dueDate }) => void | PromiseНовые даты после перетаскивания. Без него диаграмма только для чтения.
onOpenItem(item: I) => voidКлик по полосе.
barColor(item: I) => stringЦвет полосы — обычно по статусу. Перебивается полем item.color.
localestringЛокаль подписей шкалы. По умолчанию — локаль браузера.
labelsGanttLabelsПодписи. По умолчанию английские.
Критический путь
Самая длинная по суммарной длительности цепочка зависимостей. Подсвечивается янтарным — и сами полосы, и стрелки между ними.
Одиночный элемент путём тоже не считается: «критический путь из одной задачи» ничего не сообщает о плане.
Перетаскивание
- Полоса целиком едет обоими концами, сохраняя длительность.
- Края двигают только свой конец и упираются в противоположный — вывернуть полосу и получить срок раньше начала нельзя.
- Сдвиг округляется до дня. Полоса встаёт на целый день, а не между днями.
- Нулевой сдвиг ничего не сохраняет — это был клик, а не перетаскивание.
Раскладка отдельно
import {
datedRows, // что вообще попадает на диаграмму, в порядке начала
buildScale, // шкала дат: ширина дня подбирается по длине плана
layoutBars, // положение каждой полосы
criticalPath, // самая длинная цепочка зависимостей
applyDrag, // даты после перетаскивания
toISODate,
} from "@/components/ui/gantt/ganttLayout";Ширина дня подбирается автоматически: 32 px при плане до полутора месяцев, 20 px до трёх и 12 px дальше. На годовом горизонте 32 px на день дали бы полотно, по которому невозможно листать.