gantt-lib 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +36 -8
- package/dist/index.d.ts +36 -8
- package/dist/index.js +632 -191
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +648 -208
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +272 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -55,6 +55,7 @@ __export(index_exports, {
|
|
|
55
55
|
calculateTaskBar: () => calculateTaskBar,
|
|
56
56
|
calculateWeekendBlocks: () => calculateWeekendBlocks,
|
|
57
57
|
cascadeByLinks: () => cascadeByLinks,
|
|
58
|
+
computeLagFromDates: () => computeLagFromDates,
|
|
58
59
|
detectCycles: () => detectCycles,
|
|
59
60
|
detectEdgeZone: () => detectEdgeZone,
|
|
60
61
|
formatDateLabel: () => formatDateLabel,
|
|
@@ -271,11 +272,35 @@ function detectCycles(tasks) {
|
|
|
271
272
|
}
|
|
272
273
|
return { hasCycle: false };
|
|
273
274
|
}
|
|
275
|
+
function computeLagFromDates(linkType, predStart, predEnd, succStart, succEnd) {
|
|
276
|
+
const DAY_MS = 24 * 60 * 60 * 1e3;
|
|
277
|
+
const pS = Date.UTC(predStart.getUTCFullYear(), predStart.getUTCMonth(), predStart.getUTCDate());
|
|
278
|
+
const pE = Date.UTC(predEnd.getUTCFullYear(), predEnd.getUTCMonth(), predEnd.getUTCDate());
|
|
279
|
+
const sS = Date.UTC(succStart.getUTCFullYear(), succStart.getUTCMonth(), succStart.getUTCDate());
|
|
280
|
+
const sE = Date.UTC(succEnd.getUTCFullYear(), succEnd.getUTCMonth(), succEnd.getUTCDate());
|
|
281
|
+
switch (linkType) {
|
|
282
|
+
case "FS":
|
|
283
|
+
return Math.round((sS - pE) / DAY_MS) - 1;
|
|
284
|
+
case "SS":
|
|
285
|
+
return Math.round((sS - pS) / DAY_MS);
|
|
286
|
+
case "FF":
|
|
287
|
+
return Math.round((sE - pE) / DAY_MS);
|
|
288
|
+
case "SF":
|
|
289
|
+
return Math.round((sE - pS) / DAY_MS) + 1;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
274
292
|
function calculateSuccessorDate(predecessorStart, predecessorEnd, linkType, lag = 0) {
|
|
275
|
-
const
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
293
|
+
const DAY_MS = 24 * 60 * 60 * 1e3;
|
|
294
|
+
switch (linkType) {
|
|
295
|
+
case "FS":
|
|
296
|
+
return new Date(predecessorEnd.getTime() + (lag + 1) * DAY_MS);
|
|
297
|
+
case "SS":
|
|
298
|
+
return new Date(predecessorStart.getTime() + lag * DAY_MS);
|
|
299
|
+
case "FF":
|
|
300
|
+
return new Date(predecessorEnd.getTime() + lag * DAY_MS);
|
|
301
|
+
case "SF":
|
|
302
|
+
return new Date(predecessorStart.getTime() + (lag - 1) * DAY_MS);
|
|
303
|
+
}
|
|
279
304
|
}
|
|
280
305
|
function validateDependencies(tasks) {
|
|
281
306
|
const errors = [];
|
|
@@ -422,35 +447,10 @@ function recalculateIncomingLags(task, newStartDate, newEndDate, allTasks) {
|
|
|
422
447
|
return task.dependencies.map((dep) => {
|
|
423
448
|
const predecessor = taskById.get(dep.taskId);
|
|
424
449
|
if (!predecessor) return dep;
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
);
|
|
430
|
-
return { ...dep, lag: lagDays };
|
|
431
|
-
}
|
|
432
|
-
if (dep.type === "SS") {
|
|
433
|
-
const predStart = new Date(predecessor.startDate);
|
|
434
|
-
const lagDays = Math.max(0, Math.round(
|
|
435
|
-
(Date.UTC(newStartDate.getUTCFullYear(), newStartDate.getUTCMonth(), newStartDate.getUTCDate()) - Date.UTC(predStart.getUTCFullYear(), predStart.getUTCMonth(), predStart.getUTCDate())) / (24 * 60 * 60 * 1e3)
|
|
436
|
-
));
|
|
437
|
-
return { ...dep, lag: lagDays };
|
|
438
|
-
}
|
|
439
|
-
if (dep.type === "FF") {
|
|
440
|
-
const predEnd = new Date(predecessor.endDate);
|
|
441
|
-
const lagDays = Math.round(
|
|
442
|
-
(Date.UTC(newEndDate.getUTCFullYear(), newEndDate.getUTCMonth(), newEndDate.getUTCDate()) - Date.UTC(predEnd.getUTCFullYear(), predEnd.getUTCMonth(), predEnd.getUTCDate())) / (24 * 60 * 60 * 1e3)
|
|
443
|
-
);
|
|
444
|
-
return { ...dep, lag: lagDays };
|
|
445
|
-
}
|
|
446
|
-
if (dep.type === "SF") {
|
|
447
|
-
const predStart = new Date(predecessor.startDate);
|
|
448
|
-
const lagDays = Math.min(0, Math.round(
|
|
449
|
-
(Date.UTC(newEndDate.getUTCFullYear(), newEndDate.getUTCMonth(), newEndDate.getUTCDate()) - Date.UTC(predStart.getUTCFullYear(), predStart.getUTCMonth(), predStart.getUTCDate()) + 24 * 60 * 60 * 1e3) / (24 * 60 * 60 * 1e3)
|
|
450
|
-
));
|
|
451
|
-
return { ...dep, lag: lagDays };
|
|
452
|
-
}
|
|
453
|
-
return dep;
|
|
450
|
+
const predStart = new Date(predecessor.startDate);
|
|
451
|
+
const predEnd = new Date(predecessor.endDate);
|
|
452
|
+
const lagDays = computeLagFromDates(dep.type, predStart, predEnd, newStartDate, newEndDate);
|
|
453
|
+
return { ...dep, lag: lagDays };
|
|
454
454
|
});
|
|
455
455
|
}
|
|
456
456
|
function getAllDependencyEdges(tasks) {
|
|
@@ -1477,60 +1477,11 @@ var DragGuideLines_default = DragGuideLines;
|
|
|
1477
1477
|
var import_react6 = __toESM(require("react"));
|
|
1478
1478
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1479
1479
|
function calculateEffectiveLag(edge, predPosition, succPosition, monthStart, dayWidth) {
|
|
1480
|
-
const
|
|
1481
|
-
const
|
|
1482
|
-
const
|
|
1483
|
-
const
|
|
1484
|
-
|
|
1485
|
-
switch (edge.type) {
|
|
1486
|
-
case "FS":
|
|
1487
|
-
lagMs = Date.UTC(
|
|
1488
|
-
succStartDate.getUTCFullYear(),
|
|
1489
|
-
succStartDate.getUTCMonth(),
|
|
1490
|
-
succStartDate.getUTCDate()
|
|
1491
|
-
) - Date.UTC(
|
|
1492
|
-
predEndDate.getUTCFullYear(),
|
|
1493
|
-
predEndDate.getUTCMonth(),
|
|
1494
|
-
predEndDate.getUTCDate()
|
|
1495
|
-
) - 24 * 60 * 60 * 1e3;
|
|
1496
|
-
break;
|
|
1497
|
-
case "SS":
|
|
1498
|
-
lagMs = Date.UTC(
|
|
1499
|
-
succStartDate.getUTCFullYear(),
|
|
1500
|
-
succStartDate.getUTCMonth(),
|
|
1501
|
-
succStartDate.getUTCDate()
|
|
1502
|
-
) - Date.UTC(
|
|
1503
|
-
predStartDate.getUTCFullYear(),
|
|
1504
|
-
predStartDate.getUTCMonth(),
|
|
1505
|
-
predStartDate.getUTCDate()
|
|
1506
|
-
);
|
|
1507
|
-
break;
|
|
1508
|
-
case "FF":
|
|
1509
|
-
lagMs = Date.UTC(
|
|
1510
|
-
succEndDate.getUTCFullYear(),
|
|
1511
|
-
succEndDate.getUTCMonth(),
|
|
1512
|
-
succEndDate.getUTCDate()
|
|
1513
|
-
) - Date.UTC(
|
|
1514
|
-
predEndDate.getUTCFullYear(),
|
|
1515
|
-
predEndDate.getUTCMonth(),
|
|
1516
|
-
predEndDate.getUTCDate()
|
|
1517
|
-
);
|
|
1518
|
-
break;
|
|
1519
|
-
case "SF":
|
|
1520
|
-
lagMs = Date.UTC(
|
|
1521
|
-
succEndDate.getUTCFullYear(),
|
|
1522
|
-
succEndDate.getUTCMonth(),
|
|
1523
|
-
succEndDate.getUTCDate()
|
|
1524
|
-
) - Date.UTC(
|
|
1525
|
-
predStartDate.getUTCFullYear(),
|
|
1526
|
-
predStartDate.getUTCMonth(),
|
|
1527
|
-
predStartDate.getUTCDate()
|
|
1528
|
-
) + 24 * 60 * 60 * 1e3;
|
|
1529
|
-
break;
|
|
1530
|
-
default:
|
|
1531
|
-
return 0;
|
|
1532
|
-
}
|
|
1533
|
-
return Math.round(lagMs / (24 * 60 * 60 * 1e3));
|
|
1480
|
+
const predStart = pixelsToDate(predPosition.left, monthStart, dayWidth);
|
|
1481
|
+
const predEnd = pixelsToDate(predPosition.right - dayWidth, monthStart, dayWidth);
|
|
1482
|
+
const succStart = pixelsToDate(succPosition.left, monthStart, dayWidth);
|
|
1483
|
+
const succEnd = pixelsToDate(succPosition.right - dayWidth, monthStart, dayWidth);
|
|
1484
|
+
return computeLagFromDates(edge.type, predStart, predEnd, succStart, succEnd);
|
|
1534
1485
|
}
|
|
1535
1486
|
var DependencyLines = import_react6.default.memo(({
|
|
1536
1487
|
tasks,
|
|
@@ -1538,7 +1489,8 @@ var DependencyLines = import_react6.default.memo(({
|
|
|
1538
1489
|
dayWidth,
|
|
1539
1490
|
rowHeight,
|
|
1540
1491
|
gridWidth,
|
|
1541
|
-
dragOverrides
|
|
1492
|
+
dragOverrides,
|
|
1493
|
+
selectedDep
|
|
1542
1494
|
}) => {
|
|
1543
1495
|
const { taskPositions, taskIndices } = (0, import_react6.useMemo)(() => {
|
|
1544
1496
|
const positions = /* @__PURE__ */ new Map();
|
|
@@ -1652,30 +1604,60 @@ var DependencyLines = import_react6.default.memo(({
|
|
|
1652
1604
|
}
|
|
1653
1605
|
)
|
|
1654
1606
|
}
|
|
1655
|
-
)
|
|
1656
|
-
] }),
|
|
1657
|
-
lines.map(({ id, path, hasCycle, lag, fromX, toX, fromY, reverseOrder }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react6.default.Fragment, { children: [
|
|
1658
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1659
|
-
"path",
|
|
1660
|
-
{
|
|
1661
|
-
d: path,
|
|
1662
|
-
className: hasCycle ? "gantt-dependency-path gantt-dependency-cycle" : "gantt-dependency-path",
|
|
1663
|
-
markerEnd: hasCycle ? "url(#arrowhead-cycle)" : "url(#arrowhead)"
|
|
1664
|
-
}
|
|
1665
1607
|
),
|
|
1666
|
-
|
|
1667
|
-
"
|
|
1608
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1609
|
+
"marker",
|
|
1668
1610
|
{
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1611
|
+
id: "arrowhead-selected",
|
|
1612
|
+
markerWidth: "8",
|
|
1613
|
+
markerHeight: "6",
|
|
1614
|
+
markerUnits: "userSpaceOnUse",
|
|
1615
|
+
refX: "7",
|
|
1616
|
+
refY: "3",
|
|
1617
|
+
orient: "auto",
|
|
1618
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1619
|
+
"polygon",
|
|
1620
|
+
{
|
|
1621
|
+
points: "0 0, 8 3, 0 6",
|
|
1622
|
+
fill: "#ef4444"
|
|
1623
|
+
}
|
|
1624
|
+
)
|
|
1676
1625
|
}
|
|
1677
1626
|
)
|
|
1678
|
-
] },
|
|
1627
|
+
] }),
|
|
1628
|
+
lines.map(({ id, path, hasCycle, lag, fromX, toX, fromY, reverseOrder }) => {
|
|
1629
|
+
const isSelected = selectedDep != null && id === `${selectedDep.predecessorId}-${selectedDep.successorId}-${selectedDep.linkType}`;
|
|
1630
|
+
let pathClassName = "gantt-dependency-path";
|
|
1631
|
+
if (isSelected) pathClassName += " gantt-dependency-selected";
|
|
1632
|
+
else if (hasCycle) pathClassName += " gantt-dependency-cycle";
|
|
1633
|
+
let markerEnd;
|
|
1634
|
+
if (isSelected) markerEnd = "url(#arrowhead-selected)";
|
|
1635
|
+
else if (hasCycle) markerEnd = "url(#arrowhead-cycle)";
|
|
1636
|
+
else markerEnd = "url(#arrowhead)";
|
|
1637
|
+
const lagColor = isSelected ? "#ef4444" : hasCycle ? "var(--gantt-dependency-cycle-color, #ef4444)" : "var(--gantt-dependency-line-color, #666666)";
|
|
1638
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react6.default.Fragment, { children: [
|
|
1639
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1640
|
+
"path",
|
|
1641
|
+
{
|
|
1642
|
+
d: path,
|
|
1643
|
+
className: pathClassName,
|
|
1644
|
+
markerEnd
|
|
1645
|
+
}
|
|
1646
|
+
),
|
|
1647
|
+
lag !== 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1648
|
+
"text",
|
|
1649
|
+
{
|
|
1650
|
+
className: "gantt-dependency-lag-label",
|
|
1651
|
+
x: lag < 0 ? toX + 14 : toX - 14,
|
|
1652
|
+
y: reverseOrder ? fromY - 4 : fromY + 12,
|
|
1653
|
+
textAnchor: "middle",
|
|
1654
|
+
fontSize: "10",
|
|
1655
|
+
fill: lagColor,
|
|
1656
|
+
children: lag > 0 ? `+${lag}` : `${lag}`
|
|
1657
|
+
}
|
|
1658
|
+
)
|
|
1659
|
+
] }, id);
|
|
1660
|
+
})
|
|
1679
1661
|
]
|
|
1680
1662
|
}
|
|
1681
1663
|
);
|
|
@@ -1684,17 +1666,49 @@ DependencyLines.displayName = "DependencyLines";
|
|
|
1684
1666
|
var DependencyLines_default = DependencyLines;
|
|
1685
1667
|
|
|
1686
1668
|
// src/components/TaskList/TaskList.tsx
|
|
1687
|
-
var import_react11 = require("react");
|
|
1669
|
+
var import_react11 = __toESM(require("react"));
|
|
1670
|
+
|
|
1671
|
+
// src/components/ui/Popover.tsx
|
|
1672
|
+
var RadixPopover = __toESM(require("@radix-ui/react-popover"));
|
|
1673
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1674
|
+
var Popover = ({ open, onOpenChange, children }) => {
|
|
1675
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(RadixPopover.Root, { open, onOpenChange, children });
|
|
1676
|
+
};
|
|
1677
|
+
var PopoverTrigger = RadixPopover.Trigger;
|
|
1678
|
+
var PopoverContent = ({
|
|
1679
|
+
children,
|
|
1680
|
+
className,
|
|
1681
|
+
align = "start",
|
|
1682
|
+
side = "bottom",
|
|
1683
|
+
portal = true,
|
|
1684
|
+
collisionPadding = 8
|
|
1685
|
+
}) => {
|
|
1686
|
+
const content = /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1687
|
+
RadixPopover.Content,
|
|
1688
|
+
{
|
|
1689
|
+
className: `gantt-popover${className ? ` ${className}` : ""}`,
|
|
1690
|
+
align,
|
|
1691
|
+
side,
|
|
1692
|
+
collisionPadding,
|
|
1693
|
+
sideOffset: 4,
|
|
1694
|
+
children
|
|
1695
|
+
}
|
|
1696
|
+
);
|
|
1697
|
+
if (portal) {
|
|
1698
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(RadixPopover.Portal, { children: content });
|
|
1699
|
+
}
|
|
1700
|
+
return content;
|
|
1701
|
+
};
|
|
1688
1702
|
|
|
1689
1703
|
// src/components/TaskList/TaskListRow.tsx
|
|
1690
1704
|
var import_react10 = __toESM(require("react"));
|
|
1691
1705
|
|
|
1692
1706
|
// src/components/ui/Input.tsx
|
|
1693
1707
|
var import_react7 = __toESM(require("react"));
|
|
1694
|
-
var
|
|
1708
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1695
1709
|
var Input = import_react7.default.forwardRef(
|
|
1696
1710
|
({ className, ...props }, ref) => {
|
|
1697
|
-
return /* @__PURE__ */ (0,
|
|
1711
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1698
1712
|
"input",
|
|
1699
1713
|
{
|
|
1700
1714
|
ref,
|
|
@@ -1714,7 +1728,7 @@ var import_date_fns3 = require("date-fns");
|
|
|
1714
1728
|
var import_react8 = require("react");
|
|
1715
1729
|
var import_date_fns2 = require("date-fns");
|
|
1716
1730
|
var import_locale2 = require("date-fns/locale");
|
|
1717
|
-
var
|
|
1731
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1718
1732
|
function getDayClassName(day, selected) {
|
|
1719
1733
|
const classes = ["gantt-day-btn"];
|
|
1720
1734
|
if (selected && (0, import_date_fns2.isSameDay)(day, selected)) classes.push("selected");
|
|
@@ -1784,12 +1798,12 @@ var Calendar = ({
|
|
|
1784
1798
|
const emptyDays = ((0, import_date_fns2.getDay)(firstDay) + 6) % 7;
|
|
1785
1799
|
const monthKey = (0, import_date_fns2.format)(month, "yyyy-MM");
|
|
1786
1800
|
const monthLabel = (0, import_date_fns2.format)(month, "LLLL yyyy", { locale: import_locale2.ru });
|
|
1787
|
-
const emptyCells = Array.from({ length: emptyDays }, (_, i) => /* @__PURE__ */ (0,
|
|
1801
|
+
const emptyCells = Array.from({ length: emptyDays }, (_, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "gantt-cal-empty-day" }, `e-${i}`));
|
|
1788
1802
|
const dayCells = Array.from({ length: totalDays }, (_, i) => {
|
|
1789
1803
|
const dayNum = i + 1;
|
|
1790
1804
|
const day = new Date(month.getFullYear(), month.getMonth(), dayNum);
|
|
1791
1805
|
const className = getDayClassName(day, selected);
|
|
1792
|
-
return /* @__PURE__ */ (0,
|
|
1806
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1793
1807
|
"button",
|
|
1794
1808
|
{
|
|
1795
1809
|
type: "button",
|
|
@@ -1805,9 +1819,9 @@ var Calendar = ({
|
|
|
1805
1819
|
dayNum
|
|
1806
1820
|
);
|
|
1807
1821
|
});
|
|
1808
|
-
return /* @__PURE__ */ (0,
|
|
1809
|
-
/* @__PURE__ */ (0,
|
|
1810
|
-
/* @__PURE__ */ (0,
|
|
1822
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "gantt-cal-month", "data-month": monthKey, children: [
|
|
1823
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "gantt-cal-month-header", children: monthLabel }),
|
|
1824
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "gantt-cal-month-days", children: [
|
|
1811
1825
|
emptyCells,
|
|
1812
1826
|
dayCells
|
|
1813
1827
|
] })
|
|
@@ -1819,42 +1833,10 @@ var Calendar = ({
|
|
|
1819
1833
|
() => months.map(renderMonth),
|
|
1820
1834
|
[months, renderMonth]
|
|
1821
1835
|
);
|
|
1822
|
-
return /* @__PURE__ */ (0,
|
|
1836
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { ref: scrollRef, className: "gantt-cal-container", children: renderedMonths });
|
|
1823
1837
|
};
|
|
1824
1838
|
Calendar.displayName = "Calendar";
|
|
1825
1839
|
|
|
1826
|
-
// src/components/ui/Popover.tsx
|
|
1827
|
-
var RadixPopover = __toESM(require("@radix-ui/react-popover"));
|
|
1828
|
-
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1829
|
-
var Popover = ({ open, onOpenChange, children }) => {
|
|
1830
|
-
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(RadixPopover.Root, { open, onOpenChange, children });
|
|
1831
|
-
};
|
|
1832
|
-
var PopoverTrigger = RadixPopover.Trigger;
|
|
1833
|
-
var PopoverContent = ({
|
|
1834
|
-
children,
|
|
1835
|
-
className,
|
|
1836
|
-
align = "start",
|
|
1837
|
-
side = "bottom",
|
|
1838
|
-
portal = true,
|
|
1839
|
-
collisionPadding = 8
|
|
1840
|
-
}) => {
|
|
1841
|
-
const content = /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1842
|
-
RadixPopover.Content,
|
|
1843
|
-
{
|
|
1844
|
-
className: `gantt-popover${className ? ` ${className}` : ""}`,
|
|
1845
|
-
align,
|
|
1846
|
-
side,
|
|
1847
|
-
collisionPadding,
|
|
1848
|
-
sideOffset: 4,
|
|
1849
|
-
children
|
|
1850
|
-
}
|
|
1851
|
-
);
|
|
1852
|
-
if (portal) {
|
|
1853
|
-
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(RadixPopover.Portal, { children: content });
|
|
1854
|
-
}
|
|
1855
|
-
return content;
|
|
1856
|
-
};
|
|
1857
|
-
|
|
1858
1840
|
// src/components/ui/DatePicker.tsx
|
|
1859
1841
|
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1860
1842
|
var DatePicker = ({
|
|
@@ -1919,19 +1901,182 @@ var DatePicker = ({
|
|
|
1919
1901
|
};
|
|
1920
1902
|
DatePicker.displayName = "DatePicker";
|
|
1921
1903
|
|
|
1922
|
-
// src/components/TaskList/
|
|
1904
|
+
// src/components/TaskList/DepIcons.tsx
|
|
1923
1905
|
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
1906
|
+
var DepIconFS = () => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1907
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "m10 15 5 5 5-5" }),
|
|
1908
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M4 4h7a4 4 0 0 1 4 4v12" })
|
|
1909
|
+
] });
|
|
1910
|
+
var DepIconSS = () => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1911
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M3 5v14" }),
|
|
1912
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M21 12H7" }),
|
|
1913
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "m15 18 6-6-6-6" })
|
|
1914
|
+
] });
|
|
1915
|
+
var DepIconFF = () => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1916
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M17 12H3" }),
|
|
1917
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "m11 18 6-6-6-6" }),
|
|
1918
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M21 5v14" })
|
|
1919
|
+
] });
|
|
1920
|
+
var DepIconSF = () => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1921
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "m14 15-5 5-5-5" }),
|
|
1922
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M20 4h-7a4 4 0 0 0-4 4v12" })
|
|
1923
|
+
] });
|
|
1924
|
+
var LINK_TYPE_ICONS = {
|
|
1925
|
+
FS: DepIconFS,
|
|
1926
|
+
SS: DepIconSS,
|
|
1927
|
+
FF: DepIconFF,
|
|
1928
|
+
SF: DepIconSF
|
|
1929
|
+
};
|
|
1930
|
+
var LINK_TYPE_LABELS = {
|
|
1931
|
+
FS: "\u041E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u0435-\u043D\u0430\u0447\u0430\u043B\u043E",
|
|
1932
|
+
SS: "\u041D\u0430\u0447\u0430\u043B\u043E-\u043D\u0430\u0447\u0430\u043B\u043E",
|
|
1933
|
+
FF: "\u041E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u0435-\u043E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u0435",
|
|
1934
|
+
SF: "\u041D\u0430\u0447\u0430\u043B\u043E-\u043E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u0435"
|
|
1935
|
+
};
|
|
1936
|
+
|
|
1937
|
+
// src/components/TaskList/TaskListRow.tsx
|
|
1938
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1939
|
+
var TrashIcon = () => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("svg", { xmlns: "http://www.w3.org/2000/svg", width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1940
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6" }),
|
|
1941
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M3 6h18" }),
|
|
1942
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" })
|
|
1943
|
+
] });
|
|
1944
|
+
function formatDepDescription(type, lag) {
|
|
1945
|
+
const effectiveLag = lag ?? 0;
|
|
1946
|
+
if (type === "FS") {
|
|
1947
|
+
if (effectiveLag > 0) return `\u041D\u0430\u0447\u0430\u0442\u044C \u0447\u0435\u0440\u0435\u0437 ${effectiveLag} \u0434\u043D. \u043F\u043E\u0441\u043B\u0435 \u043E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u044F`;
|
|
1948
|
+
if (effectiveLag < 0) return `\u041D\u0430\u0447\u0430\u0442\u044C \u0437\u0430 ${Math.abs(effectiveLag)} \u0434\u043D. \u0434\u043E \u043E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u044F`;
|
|
1949
|
+
return `\u041D\u0430\u0447\u0430\u0442\u044C \u0441\u0440\u0430\u0437\u0443 \u043F\u043E\u0441\u043B\u0435 \u043E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u044F`;
|
|
1950
|
+
}
|
|
1951
|
+
if (type === "FF") {
|
|
1952
|
+
if (effectiveLag > 0) return `\u0417\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044C \u0447\u0435\u0440\u0435\u0437 ${effectiveLag} \u0434\u043D. \u043F\u043E\u0441\u043B\u0435 \u043E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u044F`;
|
|
1953
|
+
if (effectiveLag < 0) return `\u0417\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044C \u0437\u0430 ${Math.abs(effectiveLag)} \u0434\u043D. \u0434\u043E \u043E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u044F`;
|
|
1954
|
+
return `\u0417\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044C \u043F\u043E\u0441\u043B\u0435 \u043E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u044F`;
|
|
1955
|
+
}
|
|
1956
|
+
if (type === "SS") {
|
|
1957
|
+
if (effectiveLag > 0) return `\u041D\u0430\u0447\u0430\u0442\u044C \u0447\u0435\u0440\u0435\u0437 ${effectiveLag} \u0434\u043D. \u043F\u043E\u0441\u043B\u0435 \u043D\u0430\u0447\u0430\u043B\u0430`;
|
|
1958
|
+
if (effectiveLag < 0) return `\u041D\u0430\u0447\u0430\u0442\u044C \u0437\u0430 ${Math.abs(effectiveLag)} \u0434\u043D. \u0434\u043E \u043D\u0430\u0447\u0430\u043B\u0430`;
|
|
1959
|
+
return `\u041D\u0430\u0447\u0430\u0442\u044C \u0432\u043C\u0435\u0441\u0442\u0435 \u0441 \u043D\u0430\u0447\u0430\u043B\u043E\u043C`;
|
|
1960
|
+
}
|
|
1961
|
+
if (type === "SF") {
|
|
1962
|
+
if (effectiveLag > 0) return `\u0417\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044C \u0447\u0435\u0440\u0435\u0437 ${effectiveLag} \u0434\u043D. \u043F\u043E\u0441\u043B\u0435 \u043D\u0430\u0447\u0430\u043B\u0430`;
|
|
1963
|
+
if (effectiveLag < 0) return `\u0417\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044C \u0437\u0430 ${Math.abs(effectiveLag)} \u0434\u043D. \u0434\u043E \u043D\u0430\u0447\u0430\u043B\u0430`;
|
|
1964
|
+
return `\u0417\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044C \u0434\u043E \u043D\u0430\u0447\u0430\u043B\u0430`;
|
|
1965
|
+
}
|
|
1966
|
+
return "";
|
|
1967
|
+
}
|
|
1968
|
+
var DepChip = ({
|
|
1969
|
+
lag,
|
|
1970
|
+
dep,
|
|
1971
|
+
taskId,
|
|
1972
|
+
predecessorName,
|
|
1973
|
+
selectedChip,
|
|
1974
|
+
disableDependencyEditing,
|
|
1975
|
+
onChipSelect,
|
|
1976
|
+
onRowClick,
|
|
1977
|
+
onScrollToTask,
|
|
1978
|
+
onRemoveDependency,
|
|
1979
|
+
onChipSelectClear
|
|
1980
|
+
}) => {
|
|
1981
|
+
const isSelected = selectedChip?.successorId === taskId && selectedChip?.predecessorId === dep.taskId && selectedChip?.linkType === dep.type;
|
|
1982
|
+
const handleClick = (e) => {
|
|
1983
|
+
e.stopPropagation();
|
|
1984
|
+
if (disableDependencyEditing) return;
|
|
1985
|
+
onChipSelect?.(isSelected ? null : { successorId: taskId, predecessorId: dep.taskId, linkType: dep.type });
|
|
1986
|
+
if (!isSelected) {
|
|
1987
|
+
onRowClick?.(taskId);
|
|
1988
|
+
onScrollToTask?.(taskId);
|
|
1989
|
+
}
|
|
1990
|
+
};
|
|
1991
|
+
const handleTrashClick = (e) => {
|
|
1992
|
+
e.stopPropagation();
|
|
1993
|
+
onRemoveDependency?.(taskId, dep.taskId, dep.type);
|
|
1994
|
+
onChipSelectClear();
|
|
1995
|
+
};
|
|
1996
|
+
const Icon = LINK_TYPE_ICONS[dep.type];
|
|
1997
|
+
const depPrefix = formatDepDescription(dep.type, lag);
|
|
1998
|
+
const depName = predecessorName ?? dep.taskId;
|
|
1999
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Popover, { open: isSelected, onOpenChange: (open) => {
|
|
2000
|
+
if (!open) onChipSelectClear();
|
|
2001
|
+
}, children: [
|
|
2002
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "gantt-tl-dep-chip-wrapper", children: [
|
|
2003
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2004
|
+
"span",
|
|
2005
|
+
{
|
|
2006
|
+
className: `gantt-tl-dep-chip${isSelected ? " gantt-tl-dep-chip-selected" : ""}`,
|
|
2007
|
+
onClick: handleClick,
|
|
2008
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
|
|
2009
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Icon, {}),
|
|
2010
|
+
lag != null && lag !== 0 ? lag > 0 ? `+${lag}` : `${lag}` : ""
|
|
2011
|
+
] })
|
|
2012
|
+
}
|
|
2013
|
+
) }),
|
|
2014
|
+
!disableDependencyEditing && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2015
|
+
"button",
|
|
2016
|
+
{
|
|
2017
|
+
type: "button",
|
|
2018
|
+
className: "gantt-tl-dep-chip-trash",
|
|
2019
|
+
"aria-label": "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0441\u0432\u044F\u0437\u044C",
|
|
2020
|
+
onClick: handleTrashClick,
|
|
2021
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(TrashIcon, {})
|
|
2022
|
+
}
|
|
2023
|
+
)
|
|
2024
|
+
] }),
|
|
2025
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(PopoverContent, { portal: true, side: "bottom", align: "start", className: "gantt-tl-dep-info-popover", children: [
|
|
2026
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "gantt-tl-dep-info-prefix", children: depPrefix }),
|
|
2027
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "gantt-tl-dep-info-name", children: depName })
|
|
2028
|
+
] })
|
|
2029
|
+
] });
|
|
2030
|
+
};
|
|
1924
2031
|
var toISODate = (value) => {
|
|
1925
2032
|
if (value instanceof Date) return value.toISOString().split("T")[0];
|
|
1926
2033
|
if (typeof value === "string" && value.includes("T")) return value.split("T")[0];
|
|
1927
2034
|
return value;
|
|
1928
2035
|
};
|
|
1929
2036
|
var TaskListRow = import_react10.default.memo(
|
|
1930
|
-
({
|
|
2037
|
+
({
|
|
2038
|
+
task,
|
|
2039
|
+
rowIndex,
|
|
2040
|
+
rowHeight,
|
|
2041
|
+
onTaskChange,
|
|
2042
|
+
selectedTaskId,
|
|
2043
|
+
onRowClick,
|
|
2044
|
+
disableTaskNameEditing = false,
|
|
2045
|
+
disableDependencyEditing = false,
|
|
2046
|
+
allTasks = [],
|
|
2047
|
+
activeLinkType,
|
|
2048
|
+
selectingPredecessorFor,
|
|
2049
|
+
onSetSelectingPredecessorFor,
|
|
2050
|
+
onAddDependency,
|
|
2051
|
+
onRemoveDependency,
|
|
2052
|
+
selectedChip,
|
|
2053
|
+
onChipSelect,
|
|
2054
|
+
onScrollToTask
|
|
2055
|
+
}) => {
|
|
1931
2056
|
const [editingName, setEditingName] = (0, import_react10.useState)(false);
|
|
1932
2057
|
const [nameValue, setNameValue] = (0, import_react10.useState)("");
|
|
1933
2058
|
const nameInputRef = (0, import_react10.useRef)(null);
|
|
2059
|
+
const [overflowOpen, setOverflowOpen] = (0, import_react10.useState)(false);
|
|
1934
2060
|
const isSelected = selectedTaskId === task.id;
|
|
2061
|
+
const isPicking = selectingPredecessorFor != null;
|
|
2062
|
+
const isSourceRow = isPicking && selectingPredecessorFor === task.id;
|
|
2063
|
+
const chips = (0, import_react10.useMemo)(() => {
|
|
2064
|
+
const succStart = new Date(task.startDate);
|
|
2065
|
+
const succEnd = new Date(task.endDate);
|
|
2066
|
+
const taskById = new Map((allTasks ?? []).map((t) => [t.id, t]));
|
|
2067
|
+
return (task.dependencies ?? []).map((dep) => {
|
|
2068
|
+
const pred = taskById.get(dep.taskId);
|
|
2069
|
+
const lag = pred ? computeLagFromDates(
|
|
2070
|
+
dep.type,
|
|
2071
|
+
new Date(pred.startDate),
|
|
2072
|
+
new Date(pred.endDate),
|
|
2073
|
+
succStart,
|
|
2074
|
+
succEnd
|
|
2075
|
+
) : dep.lag ?? 0;
|
|
2076
|
+
return { dep, lag, predecessorName: pred?.name ?? dep.taskId };
|
|
2077
|
+
});
|
|
2078
|
+
}, [task.dependencies, task.startDate, task.endDate, allTasks]);
|
|
2079
|
+
const linkWord = chips.length <= 4 ? "\u0441\u0432\u044F\u0437\u0438" : "\u0441\u0432\u044F\u0437\u0435\u0439";
|
|
1935
2080
|
(0, import_react10.useEffect)(() => {
|
|
1936
2081
|
if (editingName && nameInputRef.current) {
|
|
1937
2082
|
nameInputRef.current.focus();
|
|
@@ -1977,18 +2122,60 @@ var TaskListRow = import_react10.default.memo(
|
|
|
1977
2122
|
const handleRowClickInternal = (0, import_react10.useCallback)(() => {
|
|
1978
2123
|
onRowClick?.(task.id);
|
|
1979
2124
|
}, [task.id, onRowClick]);
|
|
2125
|
+
const handleNumberClick = (0, import_react10.useCallback)((e) => {
|
|
2126
|
+
e.stopPropagation();
|
|
2127
|
+
onRowClick?.(task.id);
|
|
2128
|
+
onScrollToTask?.(task.id);
|
|
2129
|
+
}, [task.id, onRowClick, onScrollToTask]);
|
|
2130
|
+
const handleAddClick = (0, import_react10.useCallback)((e) => {
|
|
2131
|
+
e.stopPropagation();
|
|
2132
|
+
onSetSelectingPredecessorFor?.(task.id);
|
|
2133
|
+
}, [task.id, onSetSelectingPredecessorFor]);
|
|
2134
|
+
const handlePredecessorPick = (0, import_react10.useCallback)((e) => {
|
|
2135
|
+
e.stopPropagation();
|
|
2136
|
+
if (!isPicking || isSourceRow) return;
|
|
2137
|
+
if (!selectingPredecessorFor || !activeLinkType) return;
|
|
2138
|
+
onAddDependency?.(task.id, selectingPredecessorFor, activeLinkType);
|
|
2139
|
+
}, [isPicking, isSourceRow, selectingPredecessorFor, task.id, activeLinkType, onAddDependency]);
|
|
2140
|
+
const isSelectedPredecessor = selectedChip != null && selectedChip.predecessorId === task.id;
|
|
2141
|
+
const handleDeleteSelected = (0, import_react10.useCallback)((e) => {
|
|
2142
|
+
e.stopPropagation();
|
|
2143
|
+
if (!selectedChip) return;
|
|
2144
|
+
onRemoveDependency?.(selectedChip.successorId, selectedChip.predecessorId, selectedChip.linkType);
|
|
2145
|
+
onChipSelect?.(null);
|
|
2146
|
+
}, [selectedChip, onRemoveDependency, onChipSelect]);
|
|
1980
2147
|
const startDateISO = toISODate(task.startDate);
|
|
1981
2148
|
const endDateISO = toISODate(task.endDate);
|
|
1982
|
-
return /* @__PURE__ */ (0,
|
|
2149
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
1983
2150
|
"div",
|
|
1984
2151
|
{
|
|
1985
|
-
className:
|
|
2152
|
+
className: [
|
|
2153
|
+
"gantt-tl-row",
|
|
2154
|
+
isSelected ? "gantt-tl-row-selected" : "",
|
|
2155
|
+
isPicking && !isSourceRow ? "gantt-tl-row-picking" : "",
|
|
2156
|
+
isSourceRow ? "gantt-tl-row-picking-self" : ""
|
|
2157
|
+
].filter(Boolean).join(" "),
|
|
1986
2158
|
style: { minHeight: `${rowHeight}px` },
|
|
1987
2159
|
onClick: handleRowClickInternal,
|
|
1988
2160
|
children: [
|
|
1989
|
-
/* @__PURE__ */ (0,
|
|
1990
|
-
|
|
1991
|
-
|
|
2161
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
2162
|
+
"div",
|
|
2163
|
+
{
|
|
2164
|
+
className: "gantt-tl-cell gantt-tl-cell-number",
|
|
2165
|
+
onClick: handleNumberClick,
|
|
2166
|
+
title: "\u041F\u0435\u0440\u0435\u0439\u0442\u0438 \u043A \u0440\u0430\u0431\u043E\u0442\u0435",
|
|
2167
|
+
children: [
|
|
2168
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "gantt-tl-num-label", children: rowIndex + 1 }),
|
|
2169
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("svg", { className: "gantt-tl-num-icon", xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
2170
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M17 12H3" }),
|
|
2171
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "m11 18 6-6-6-6" }),
|
|
2172
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M21 5v14" })
|
|
2173
|
+
] })
|
|
2174
|
+
]
|
|
2175
|
+
}
|
|
2176
|
+
),
|
|
2177
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "gantt-tl-cell gantt-tl-cell-name", children: [
|
|
2178
|
+
editingName && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1992
2179
|
Input,
|
|
1993
2180
|
{
|
|
1994
2181
|
ref: nameInputRef,
|
|
@@ -2001,7 +2188,7 @@ var TaskListRow = import_react10.default.memo(
|
|
|
2001
2188
|
onClick: (e) => e.stopPropagation()
|
|
2002
2189
|
}
|
|
2003
2190
|
),
|
|
2004
|
-
/* @__PURE__ */ (0,
|
|
2191
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2005
2192
|
"button",
|
|
2006
2193
|
{
|
|
2007
2194
|
type: "button",
|
|
@@ -2012,7 +2199,7 @@ var TaskListRow = import_react10.default.memo(
|
|
|
2012
2199
|
}
|
|
2013
2200
|
)
|
|
2014
2201
|
] }),
|
|
2015
|
-
/* @__PURE__ */ (0,
|
|
2202
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "gantt-tl-cell gantt-tl-cell-date", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2016
2203
|
DatePicker,
|
|
2017
2204
|
{
|
|
2018
2205
|
value: startDateISO,
|
|
@@ -2022,7 +2209,7 @@ var TaskListRow = import_react10.default.memo(
|
|
|
2022
2209
|
disabled: task.locked
|
|
2023
2210
|
}
|
|
2024
2211
|
) }),
|
|
2025
|
-
/* @__PURE__ */ (0,
|
|
2212
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "gantt-tl-cell gantt-tl-cell-date", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2026
2213
|
DatePicker,
|
|
2027
2214
|
{
|
|
2028
2215
|
value: endDateISO,
|
|
@@ -2031,7 +2218,97 @@ var TaskListRow = import_react10.default.memo(
|
|
|
2031
2218
|
portal: true,
|
|
2032
2219
|
disabled: task.locked
|
|
2033
2220
|
}
|
|
2034
|
-
) })
|
|
2221
|
+
) }),
|
|
2222
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2223
|
+
"div",
|
|
2224
|
+
{
|
|
2225
|
+
className: "gantt-tl-cell gantt-tl-cell-deps",
|
|
2226
|
+
onClick: isPicking && !isSourceRow ? handlePredecessorPick : void 0,
|
|
2227
|
+
children: isSourceRow ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "gantt-tl-dep-source-hint", children: "\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0437\u0430\u0434\u0430\u0447\u0443" }) : isSelectedPredecessor && !disableDependencyEditing ? (
|
|
2228
|
+
/* Full-replacement: "Зависит от [name]" → hover → "Удалить" */
|
|
2229
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
2230
|
+
"button",
|
|
2231
|
+
{
|
|
2232
|
+
type: "button",
|
|
2233
|
+
className: "gantt-tl-dep-delete-label",
|
|
2234
|
+
onClick: handleDeleteSelected,
|
|
2235
|
+
"aria-label": "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0441\u0432\u044F\u0437\u044C",
|
|
2236
|
+
children: [
|
|
2237
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "gantt-tl-dep-delete-label-default", children: "\u0421\u0432\u044F\u0437\u0430\u043D\u043E \u0441" }),
|
|
2238
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "gantt-tl-dep-delete-label-hover", children: "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0441\u0432\u044F\u0437\u044C" })
|
|
2239
|
+
]
|
|
2240
|
+
}
|
|
2241
|
+
)
|
|
2242
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
|
|
2243
|
+
chips.length >= 2 ? (
|
|
2244
|
+
/* 2+ deps — show only "N связей" summary chip that opens a popover */
|
|
2245
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Popover, { open: overflowOpen, onOpenChange: setOverflowOpen, children: [
|
|
2246
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
2247
|
+
"button",
|
|
2248
|
+
{
|
|
2249
|
+
type: "button",
|
|
2250
|
+
className: "gantt-tl-dep-summary-chip",
|
|
2251
|
+
onClick: (e) => {
|
|
2252
|
+
e.stopPropagation();
|
|
2253
|
+
setOverflowOpen((v) => !v);
|
|
2254
|
+
},
|
|
2255
|
+
children: [
|
|
2256
|
+
chips.length,
|
|
2257
|
+
" ",
|
|
2258
|
+
linkWord
|
|
2259
|
+
]
|
|
2260
|
+
}
|
|
2261
|
+
) }),
|
|
2262
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(PopoverContent, { portal: true, align: "start", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "gantt-tl-dep-overflow-list", onClick: (e) => e.stopPropagation(), children: chips.map(({ dep, lag, predecessorName }) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2263
|
+
DepChip,
|
|
2264
|
+
{
|
|
2265
|
+
lag,
|
|
2266
|
+
dep,
|
|
2267
|
+
taskId: task.id,
|
|
2268
|
+
predecessorName,
|
|
2269
|
+
selectedChip,
|
|
2270
|
+
disableDependencyEditing,
|
|
2271
|
+
onChipSelect,
|
|
2272
|
+
onRowClick,
|
|
2273
|
+
onScrollToTask,
|
|
2274
|
+
onRemoveDependency,
|
|
2275
|
+
onChipSelectClear: () => onChipSelect?.(null)
|
|
2276
|
+
},
|
|
2277
|
+
`${dep.taskId}-${dep.type}`
|
|
2278
|
+
)) }) })
|
|
2279
|
+
] })
|
|
2280
|
+
) : chips.length === 1 ? (
|
|
2281
|
+
/* Single chip — unified DepChip */
|
|
2282
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2283
|
+
DepChip,
|
|
2284
|
+
{
|
|
2285
|
+
lag: chips[0].lag,
|
|
2286
|
+
dep: chips[0].dep,
|
|
2287
|
+
taskId: task.id,
|
|
2288
|
+
predecessorName: chips[0].predecessorName,
|
|
2289
|
+
selectedChip,
|
|
2290
|
+
disableDependencyEditing,
|
|
2291
|
+
onChipSelect,
|
|
2292
|
+
onRowClick,
|
|
2293
|
+
onScrollToTask,
|
|
2294
|
+
onRemoveDependency,
|
|
2295
|
+
onChipSelectClear: () => onChipSelect?.(null)
|
|
2296
|
+
}
|
|
2297
|
+
)
|
|
2298
|
+
) : null,
|
|
2299
|
+
!disableDependencyEditing && !isPicking && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2300
|
+
"button",
|
|
2301
|
+
{
|
|
2302
|
+
type: "button",
|
|
2303
|
+
className: "gantt-tl-dep-add",
|
|
2304
|
+
onClick: handleAddClick,
|
|
2305
|
+
"aria-label": "\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0441\u0432\u044F\u0437\u044C",
|
|
2306
|
+
children: "+"
|
|
2307
|
+
}
|
|
2308
|
+
)
|
|
2309
|
+
] })
|
|
2310
|
+
}
|
|
2311
|
+
)
|
|
2035
2312
|
]
|
|
2036
2313
|
}
|
|
2037
2314
|
);
|
|
@@ -2040,7 +2317,8 @@ var TaskListRow = import_react10.default.memo(
|
|
|
2040
2317
|
TaskListRow.displayName = "TaskListRow";
|
|
2041
2318
|
|
|
2042
2319
|
// src/components/TaskList/TaskList.tsx
|
|
2043
|
-
var
|
|
2320
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
2321
|
+
var LINK_TYPE_ORDER = ["FS", "SS", "FF", "SF"];
|
|
2044
2322
|
var TaskList = ({
|
|
2045
2323
|
tasks,
|
|
2046
2324
|
rowHeight,
|
|
@@ -2050,7 +2328,10 @@ var TaskList = ({
|
|
|
2050
2328
|
selectedTaskId,
|
|
2051
2329
|
onTaskSelect,
|
|
2052
2330
|
show = true,
|
|
2053
|
-
disableTaskNameEditing = false
|
|
2331
|
+
disableTaskNameEditing = false,
|
|
2332
|
+
disableDependencyEditing = false,
|
|
2333
|
+
onScrollToTask,
|
|
2334
|
+
onSelectedChipChange
|
|
2054
2335
|
}) => {
|
|
2055
2336
|
const totalHeight = (0, import_react11.useMemo)(
|
|
2056
2337
|
() => tasks.length * rowHeight,
|
|
@@ -2059,19 +2340,144 @@ var TaskList = ({
|
|
|
2059
2340
|
const handleRowClick = (0, import_react11.useCallback)((taskId) => {
|
|
2060
2341
|
onTaskSelect?.(taskId);
|
|
2061
2342
|
}, [onTaskSelect]);
|
|
2062
|
-
|
|
2343
|
+
const [activeLinkType, setActiveLinkType] = (0, import_react11.useState)("FS");
|
|
2344
|
+
const [selectingPredecessorFor, setSelectingPredecessorFor] = (0, import_react11.useState)(null);
|
|
2345
|
+
const [typeMenuOpen, setTypeMenuOpen] = (0, import_react11.useState)(false);
|
|
2346
|
+
const [cycleError, setCycleError] = (0, import_react11.useState)(false);
|
|
2347
|
+
const overlayRef = (0, import_react11.useRef)(null);
|
|
2348
|
+
const [selectedChip, setSelectedChip] = (0, import_react11.useState)(null);
|
|
2349
|
+
const handleChipSelect = (0, import_react11.useCallback)((chip) => {
|
|
2350
|
+
setSelectedChip(chip);
|
|
2351
|
+
onSelectedChipChange?.(chip);
|
|
2352
|
+
}, [onSelectedChipChange]);
|
|
2353
|
+
(0, import_react11.useEffect)(() => {
|
|
2354
|
+
if (!selectingPredecessorFor && !selectedChip) return;
|
|
2355
|
+
const handleKeyDown = (e) => {
|
|
2356
|
+
if (e.key === "Escape") {
|
|
2357
|
+
setSelectingPredecessorFor(null);
|
|
2358
|
+
setSelectedChip(null);
|
|
2359
|
+
onSelectedChipChange?.(null);
|
|
2360
|
+
}
|
|
2361
|
+
};
|
|
2362
|
+
const handleMouseDown = (e) => {
|
|
2363
|
+
const target = e.target;
|
|
2364
|
+
if (overlayRef.current?.contains(target)) return;
|
|
2365
|
+
if (target.closest?.(".gantt-popover")) return;
|
|
2366
|
+
setSelectingPredecessorFor(null);
|
|
2367
|
+
setSelectedChip(null);
|
|
2368
|
+
onSelectedChipChange?.(null);
|
|
2369
|
+
};
|
|
2370
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
2371
|
+
document.addEventListener("mousedown", handleMouseDown, true);
|
|
2372
|
+
return () => {
|
|
2373
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
2374
|
+
document.removeEventListener("mousedown", handleMouseDown, true);
|
|
2375
|
+
};
|
|
2376
|
+
}, [selectingPredecessorFor, selectedChip, onSelectedChipChange]);
|
|
2377
|
+
const handleAddDependency = (0, import_react11.useCallback)((successorTaskId, predecessorTaskId, linkType) => {
|
|
2378
|
+
if (successorTaskId === predecessorTaskId) return;
|
|
2379
|
+
const successor = tasks.find((t) => t.id === successorTaskId);
|
|
2380
|
+
if (!successor) return;
|
|
2381
|
+
const alreadyExists = (successor.dependencies ?? []).some(
|
|
2382
|
+
(d) => d.taskId === predecessorTaskId && d.type === linkType
|
|
2383
|
+
);
|
|
2384
|
+
if (alreadyExists) {
|
|
2385
|
+
setSelectingPredecessorFor(null);
|
|
2386
|
+
return;
|
|
2387
|
+
}
|
|
2388
|
+
const newDep = { taskId: predecessorTaskId, type: linkType, lag: 0 };
|
|
2389
|
+
const hypothetical = tasks.map(
|
|
2390
|
+
(t) => t.id === successorTaskId ? { ...t, dependencies: [...t.dependencies ?? [], newDep] } : t
|
|
2391
|
+
);
|
|
2392
|
+
const validation = validateDependencies(hypothetical);
|
|
2393
|
+
if (!validation.isValid) {
|
|
2394
|
+
setCycleError(true);
|
|
2395
|
+
setTimeout(() => setCycleError(false), 3e3);
|
|
2396
|
+
return;
|
|
2397
|
+
}
|
|
2398
|
+
const updatedTask = hypothetical.find((t) => t.id === successorTaskId);
|
|
2399
|
+
const predecessor = tasks.find((t) => t.id === predecessorTaskId);
|
|
2400
|
+
if (predecessor) {
|
|
2401
|
+
const predStart = new Date(predecessor.startDate);
|
|
2402
|
+
const predEnd = new Date(predecessor.endDate);
|
|
2403
|
+
const constraintDate = calculateSuccessorDate(predStart, predEnd, linkType, 0);
|
|
2404
|
+
const origSuccessor = tasks.find((t) => t.id === successorTaskId);
|
|
2405
|
+
const durationMs = new Date(origSuccessor.endDate).getTime() - new Date(origSuccessor.startDate).getTime();
|
|
2406
|
+
let newStart;
|
|
2407
|
+
let newEnd;
|
|
2408
|
+
if (linkType === "FS" || linkType === "SS") {
|
|
2409
|
+
newStart = constraintDate;
|
|
2410
|
+
newEnd = new Date(constraintDate.getTime() + durationMs);
|
|
2411
|
+
} else {
|
|
2412
|
+
newEnd = constraintDate;
|
|
2413
|
+
newStart = new Date(constraintDate.getTime() - durationMs);
|
|
2414
|
+
}
|
|
2415
|
+
const snappedTask = {
|
|
2416
|
+
...updatedTask,
|
|
2417
|
+
startDate: newStart.toISOString().split("T")[0],
|
|
2418
|
+
endDate: newEnd.toISOString().split("T")[0]
|
|
2419
|
+
};
|
|
2420
|
+
onTaskChange?.(snappedTask);
|
|
2421
|
+
} else {
|
|
2422
|
+
onTaskChange?.(updatedTask);
|
|
2423
|
+
}
|
|
2424
|
+
setSelectingPredecessorFor(null);
|
|
2425
|
+
}, [tasks, onTaskChange]);
|
|
2426
|
+
const handleRemoveDependency = (0, import_react11.useCallback)((taskId, predecessorTaskId, linkType) => {
|
|
2427
|
+
const task = tasks.find((t) => t.id === taskId);
|
|
2428
|
+
if (!task) return;
|
|
2429
|
+
const updatedDeps = (task.dependencies ?? []).filter(
|
|
2430
|
+
(d) => !(d.taskId === predecessorTaskId && d.type === linkType)
|
|
2431
|
+
);
|
|
2432
|
+
onTaskChange?.({ ...task, dependencies: updatedDeps });
|
|
2433
|
+
}, [tasks, onTaskChange]);
|
|
2434
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2063
2435
|
"div",
|
|
2064
2436
|
{
|
|
2437
|
+
ref: overlayRef,
|
|
2065
2438
|
className: `gantt-tl-overlay${show ? "" : " gantt-tl-hidden"}`,
|
|
2066
2439
|
style: { width: `${taskListWidth}px` },
|
|
2067
|
-
children: /* @__PURE__ */ (0,
|
|
2068
|
-
/* @__PURE__ */ (0,
|
|
2069
|
-
/* @__PURE__ */ (0,
|
|
2070
|
-
/* @__PURE__ */ (0,
|
|
2071
|
-
/* @__PURE__ */ (0,
|
|
2072
|
-
/* @__PURE__ */ (0,
|
|
2440
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "gantt-tl-table", children: [
|
|
2441
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "gantt-tl-header", style: { height: `${headerHeight + 0.5}px` }, children: [
|
|
2442
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "gantt-tl-headerCell gantt-tl-cell-number", children: "\u2116" }),
|
|
2443
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "gantt-tl-headerCell gantt-tl-cell-name", children: "\u0418\u043C\u044F" }),
|
|
2444
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "gantt-tl-headerCell gantt-tl-cell-date", children: "\u041D\u0430\u0447\u0430\u043B\u043E" }),
|
|
2445
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "gantt-tl-headerCell gantt-tl-cell-date", children: "\u041E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u0435" }),
|
|
2446
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "gantt-tl-headerCell gantt-tl-cell-deps", style: { position: "relative" }, children: [
|
|
2447
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Popover, { open: typeMenuOpen, onOpenChange: setTypeMenuOpen, children: [
|
|
2448
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
2449
|
+
"button",
|
|
2450
|
+
{
|
|
2451
|
+
className: "gantt-tl-dep-type-trigger",
|
|
2452
|
+
disabled: disableDependencyEditing,
|
|
2453
|
+
onClick: (e) => e.stopPropagation(),
|
|
2454
|
+
children: [
|
|
2455
|
+
"\u0421\u0432\u044F\u0437\u0438 ",
|
|
2456
|
+
import_react11.default.createElement(LINK_TYPE_ICONS[activeLinkType]),
|
|
2457
|
+
" \u25BE"
|
|
2458
|
+
]
|
|
2459
|
+
}
|
|
2460
|
+
) }),
|
|
2461
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PopoverContent, { portal: true, align: "start", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "gantt-tl-dep-type-menu", children: LINK_TYPE_ORDER.map((lt) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
2462
|
+
"button",
|
|
2463
|
+
{
|
|
2464
|
+
className: `gantt-tl-dep-type-option${activeLinkType === lt ? " active" : ""}`,
|
|
2465
|
+
onClick: () => {
|
|
2466
|
+
setActiveLinkType(lt);
|
|
2467
|
+
setTypeMenuOpen(false);
|
|
2468
|
+
},
|
|
2469
|
+
children: [
|
|
2470
|
+
import_react11.default.createElement(LINK_TYPE_ICONS[lt]),
|
|
2471
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: LINK_TYPE_LABELS[lt] })
|
|
2472
|
+
]
|
|
2473
|
+
},
|
|
2474
|
+
lt
|
|
2475
|
+
)) }) })
|
|
2476
|
+
] }),
|
|
2477
|
+
cycleError && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "gantt-tl-dep-error", children: "\u0426\u0438\u043A\u043B \u0437\u0430\u0432\u0438\u0441\u0438\u043C\u043E\u0441\u0442\u0435\u0439!" })
|
|
2478
|
+
] })
|
|
2073
2479
|
] }),
|
|
2074
|
-
/* @__PURE__ */ (0,
|
|
2480
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "gantt-tl-body", style: { height: `${totalHeight}px` }, children: tasks.map((task, index) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2075
2481
|
TaskListRow,
|
|
2076
2482
|
{
|
|
2077
2483
|
task,
|
|
@@ -2080,7 +2486,17 @@ var TaskList = ({
|
|
|
2080
2486
|
onTaskChange,
|
|
2081
2487
|
selectedTaskId,
|
|
2082
2488
|
onRowClick: handleRowClick,
|
|
2083
|
-
disableTaskNameEditing
|
|
2489
|
+
disableTaskNameEditing,
|
|
2490
|
+
disableDependencyEditing,
|
|
2491
|
+
allTasks: tasks,
|
|
2492
|
+
activeLinkType,
|
|
2493
|
+
selectingPredecessorFor,
|
|
2494
|
+
onSetSelectingPredecessorFor: setSelectingPredecessorFor,
|
|
2495
|
+
onAddDependency: handleAddDependency,
|
|
2496
|
+
onRemoveDependency: handleRemoveDependency,
|
|
2497
|
+
selectedChip,
|
|
2498
|
+
onChipSelect: handleChipSelect,
|
|
2499
|
+
onScrollToTask
|
|
2084
2500
|
},
|
|
2085
2501
|
task.id
|
|
2086
2502
|
)) })
|
|
@@ -2090,7 +2506,7 @@ var TaskList = ({
|
|
|
2090
2506
|
};
|
|
2091
2507
|
|
|
2092
2508
|
// src/components/GanttChart/GanttChart.tsx
|
|
2093
|
-
var
|
|
2509
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
2094
2510
|
var GanttChart = (0, import_react12.forwardRef)(({
|
|
2095
2511
|
tasks,
|
|
2096
2512
|
dayWidth = 40,
|
|
@@ -2104,10 +2520,12 @@ var GanttChart = (0, import_react12.forwardRef)(({
|
|
|
2104
2520
|
onCascade,
|
|
2105
2521
|
showTaskList = false,
|
|
2106
2522
|
taskListWidth = 520,
|
|
2107
|
-
disableTaskNameEditing = false
|
|
2523
|
+
disableTaskNameEditing = false,
|
|
2524
|
+
disableDependencyEditing = false
|
|
2108
2525
|
}, ref) => {
|
|
2109
2526
|
const scrollContainerRef = (0, import_react12.useRef)(null);
|
|
2110
2527
|
const [selectedTaskId, setSelectedTaskId] = (0, import_react12.useState)(null);
|
|
2528
|
+
const [selectedChip, setSelectedChip] = (0, import_react12.useState)(null);
|
|
2111
2529
|
const dateRange = (0, import_react12.useMemo)(() => getMultiMonthDays(tasks), [tasks]);
|
|
2112
2530
|
const [validationResult, setValidationResult] = (0, import_react12.useState)(null);
|
|
2113
2531
|
const [cascadeOverrides, setCascadeOverrides] = (0, import_react12.useState)(/* @__PURE__ */ new Map());
|
|
@@ -2155,12 +2573,30 @@ var GanttChart = (0, import_react12.forwardRef)(({
|
|
|
2155
2573
|
const scrollLeft = Math.round(todayOffset - containerWidth / 2 + dayWidth / 2);
|
|
2156
2574
|
container.scrollLeft = Math.max(0, scrollLeft);
|
|
2157
2575
|
}, [dateRange, dayWidth]);
|
|
2576
|
+
const scrollToTask = (0, import_react12.useCallback)((taskId) => {
|
|
2577
|
+
const container = scrollContainerRef.current;
|
|
2578
|
+
if (!container || dateRange.length === 0) return;
|
|
2579
|
+
const task = tasks.find((t) => t.id === taskId);
|
|
2580
|
+
if (!task) return;
|
|
2581
|
+
const taskStart = new Date(task.startDate);
|
|
2582
|
+
const taskStartUTC = new Date(Date.UTC(
|
|
2583
|
+
taskStart.getUTCFullYear(),
|
|
2584
|
+
taskStart.getUTCMonth(),
|
|
2585
|
+
taskStart.getUTCDate()
|
|
2586
|
+
));
|
|
2587
|
+
const taskIndex = dateRange.findIndex((day) => day.getTime() === taskStartUTC.getTime());
|
|
2588
|
+
if (taskIndex === -1) return;
|
|
2589
|
+
const taskOffset = taskIndex * dayWidth;
|
|
2590
|
+
const scrollLeft = Math.round(taskOffset - dayWidth * 2);
|
|
2591
|
+
container.scrollLeft = Math.max(0, scrollLeft);
|
|
2592
|
+
}, [tasks, dateRange, dayWidth]);
|
|
2158
2593
|
(0, import_react12.useImperativeHandle)(
|
|
2159
2594
|
ref,
|
|
2160
2595
|
() => ({
|
|
2161
|
-
scrollToToday
|
|
2596
|
+
scrollToToday,
|
|
2597
|
+
scrollToTask
|
|
2162
2598
|
}),
|
|
2163
|
-
[scrollToToday]
|
|
2599
|
+
[scrollToToday, scrollToTask]
|
|
2164
2600
|
);
|
|
2165
2601
|
const [dragGuideLines, setDragGuideLines] = (0, import_react12.useState)(null);
|
|
2166
2602
|
const [draggedTaskOverride, setDraggedTaskOverride] = (0, import_react12.useState)(null);
|
|
@@ -2260,15 +2696,15 @@ var GanttChart = (0, import_react12.forwardRef)(({
|
|
|
2260
2696
|
window.removeEventListener("mouseup", handlePanEnd);
|
|
2261
2697
|
};
|
|
2262
2698
|
}, []);
|
|
2263
|
-
return /* @__PURE__ */ (0,
|
|
2699
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "gantt-container", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2264
2700
|
"div",
|
|
2265
2701
|
{
|
|
2266
2702
|
ref: scrollContainerRef,
|
|
2267
2703
|
className: "gantt-scrollContainer",
|
|
2268
2704
|
style: { height: containerHeight ?? "auto", cursor: "grab" },
|
|
2269
2705
|
onMouseDown: handlePanStart,
|
|
2270
|
-
children: /* @__PURE__ */ (0,
|
|
2271
|
-
/* @__PURE__ */ (0,
|
|
2706
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "gantt-scrollContent", children: [
|
|
2707
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2272
2708
|
TaskList,
|
|
2273
2709
|
{
|
|
2274
2710
|
tasks,
|
|
@@ -2279,11 +2715,14 @@ var GanttChart = (0, import_react12.forwardRef)(({
|
|
|
2279
2715
|
selectedTaskId: selectedTaskId ?? void 0,
|
|
2280
2716
|
onTaskSelect: handleTaskSelect,
|
|
2281
2717
|
show: showTaskList,
|
|
2282
|
-
disableTaskNameEditing
|
|
2718
|
+
disableTaskNameEditing,
|
|
2719
|
+
disableDependencyEditing,
|
|
2720
|
+
onScrollToTask: scrollToTask,
|
|
2721
|
+
onSelectedChipChange: setSelectedChip
|
|
2283
2722
|
}
|
|
2284
2723
|
),
|
|
2285
|
-
/* @__PURE__ */ (0,
|
|
2286
|
-
/* @__PURE__ */ (0,
|
|
2724
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { minWidth: `${gridWidth}px`, flex: 1 }, children: [
|
|
2725
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "gantt-stickyHeader", style: { width: `${gridWidth}px` }, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2287
2726
|
TimeScaleHeader_default,
|
|
2288
2727
|
{
|
|
2289
2728
|
days: dateRange,
|
|
@@ -2291,7 +2730,7 @@ var GanttChart = (0, import_react12.forwardRef)(({
|
|
|
2291
2730
|
headerHeight
|
|
2292
2731
|
}
|
|
2293
2732
|
) }),
|
|
2294
|
-
/* @__PURE__ */ (0,
|
|
2733
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
2295
2734
|
"div",
|
|
2296
2735
|
{
|
|
2297
2736
|
className: "gantt-taskArea",
|
|
@@ -2300,7 +2739,7 @@ var GanttChart = (0, import_react12.forwardRef)(({
|
|
|
2300
2739
|
width: `${gridWidth}px`
|
|
2301
2740
|
},
|
|
2302
2741
|
children: [
|
|
2303
|
-
/* @__PURE__ */ (0,
|
|
2742
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2304
2743
|
GridBackground_default,
|
|
2305
2744
|
{
|
|
2306
2745
|
dateRange,
|
|
@@ -2308,8 +2747,8 @@ var GanttChart = (0, import_react12.forwardRef)(({
|
|
|
2308
2747
|
totalHeight: totalGridHeight
|
|
2309
2748
|
}
|
|
2310
2749
|
),
|
|
2311
|
-
todayInRange && /* @__PURE__ */ (0,
|
|
2312
|
-
/* @__PURE__ */ (0,
|
|
2750
|
+
todayInRange && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(TodayIndicator_default, { monthStart, dayWidth }),
|
|
2751
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2313
2752
|
DependencyLines_default,
|
|
2314
2753
|
{
|
|
2315
2754
|
tasks,
|
|
@@ -2317,10 +2756,11 @@ var GanttChart = (0, import_react12.forwardRef)(({
|
|
|
2317
2756
|
dayWidth,
|
|
2318
2757
|
rowHeight,
|
|
2319
2758
|
gridWidth,
|
|
2320
|
-
dragOverrides: dependencyOverrides
|
|
2759
|
+
dragOverrides: dependencyOverrides,
|
|
2760
|
+
selectedDep: selectedChip
|
|
2321
2761
|
}
|
|
2322
2762
|
),
|
|
2323
|
-
dragGuideLines && /* @__PURE__ */ (0,
|
|
2763
|
+
dragGuideLines && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2324
2764
|
DragGuideLines_default,
|
|
2325
2765
|
{
|
|
2326
2766
|
isDragging: dragGuideLines.isDragging,
|
|
@@ -2330,7 +2770,7 @@ var GanttChart = (0, import_react12.forwardRef)(({
|
|
|
2330
2770
|
totalHeight: totalGridHeight
|
|
2331
2771
|
}
|
|
2332
2772
|
),
|
|
2333
|
-
tasks.map((task, index) => /* @__PURE__ */ (0,
|
|
2773
|
+
tasks.map((task, index) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2334
2774
|
TaskRow_default,
|
|
2335
2775
|
{
|
|
2336
2776
|
task,
|
|
@@ -2369,7 +2809,7 @@ GanttChart.displayName = "GanttChart";
|
|
|
2369
2809
|
|
|
2370
2810
|
// src/components/ui/Button.tsx
|
|
2371
2811
|
var import_react13 = __toESM(require("react"));
|
|
2372
|
-
var
|
|
2812
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
2373
2813
|
var Button = import_react13.default.forwardRef(
|
|
2374
2814
|
({ className, variant = "default", size = "default", children, ...props }, ref) => {
|
|
2375
2815
|
const classes = [
|
|
@@ -2378,7 +2818,7 @@ var Button = import_react13.default.forwardRef(
|
|
|
2378
2818
|
size !== "default" ? `gantt-btn-${size}` : "",
|
|
2379
2819
|
className || ""
|
|
2380
2820
|
].filter(Boolean).join(" ");
|
|
2381
|
-
return /* @__PURE__ */ (0,
|
|
2821
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { ref, className: classes, ...props, children });
|
|
2382
2822
|
}
|
|
2383
2823
|
);
|
|
2384
2824
|
Button.displayName = "Button";
|
|
@@ -2408,6 +2848,7 @@ Button.displayName = "Button";
|
|
|
2408
2848
|
calculateTaskBar,
|
|
2409
2849
|
calculateWeekendBlocks,
|
|
2410
2850
|
cascadeByLinks,
|
|
2851
|
+
computeLagFromDates,
|
|
2411
2852
|
detectCycles,
|
|
2412
2853
|
detectEdgeZone,
|
|
2413
2854
|
formatDateLabel,
|