gantt-lib 0.64.1 → 0.71.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/core/scheduling/index.d.mts +1 -1
- package/dist/core/scheduling/index.d.ts +1 -1
- package/dist/core/scheduling/index.js +46 -11
- package/dist/core/scheduling/index.js.map +1 -1
- package/dist/core/scheduling/index.mjs +45 -11
- package/dist/core/scheduling/index.mjs.map +1 -1
- package/dist/{index-DMA7NbWe.d.mts → index-DlJm2l_7.d.mts} +16 -1
- package/dist/{index-DMA7NbWe.d.ts → index-DlJm2l_7.d.ts} +16 -1
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +41 -3
- package/dist/index.d.ts +41 -3
- package/dist/index.js +404 -130
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +400 -130
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +10 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -530,6 +530,8 @@ __export(index_exports, {
|
|
|
530
530
|
calculateDependencyPath: () => calculateDependencyPath,
|
|
531
531
|
calculateGridLines: () => calculateGridLines,
|
|
532
532
|
calculateGridWidth: () => calculateGridWidth,
|
|
533
|
+
calculateMilestoneConnectionBounds: () => calculateMilestoneConnectionBounds,
|
|
534
|
+
calculateMilestoneGeometry: () => calculateMilestoneGeometry,
|
|
533
535
|
calculateMonthGridLines: () => calculateMonthGridLines,
|
|
534
536
|
calculateOrthogonalPath: () => calculateOrthogonalPath,
|
|
535
537
|
calculateSuccessorDate: () => calculateSuccessorDate,
|
|
@@ -581,6 +583,7 @@ __export(index_exports, {
|
|
|
581
583
|
nameContains: () => nameContains,
|
|
582
584
|
normalizeDependencyLag: () => normalizeDependencyLag,
|
|
583
585
|
normalizeHierarchyTasks: () => normalizeHierarchyTasks,
|
|
586
|
+
normalizePredecessorDates: () => normalizePredecessorDates,
|
|
584
587
|
normalizeTaskDates: () => normalizeTaskDates,
|
|
585
588
|
normalizeUTCDate: () => normalizeUTCDate,
|
|
586
589
|
not: () => not,
|
|
@@ -596,6 +599,7 @@ __export(index_exports, {
|
|
|
596
599
|
removeDependenciesBetweenTasks: () => removeDependenciesBetweenTasks,
|
|
597
600
|
resizeTaskWithCascade: () => resizeTaskWithCascade,
|
|
598
601
|
resolveDateRangeFromPixels: () => resolveDateRangeFromPixels,
|
|
602
|
+
resolveTaskHorizontalGeometry: () => resolveTaskHorizontalGeometry,
|
|
599
603
|
shiftBusinessDayOffset: () => shiftBusinessDayOffset,
|
|
600
604
|
subtractBusinessDays: () => subtractBusinessDays2,
|
|
601
605
|
universalCascade: () => universalCascade,
|
|
@@ -614,6 +618,12 @@ init_dateMath();
|
|
|
614
618
|
|
|
615
619
|
// src/core/scheduling/dependencies.ts
|
|
616
620
|
init_dateMath();
|
|
621
|
+
function normalizePredecessorDates(predecessor, parseDateFn) {
|
|
622
|
+
const predStart = parseDateFn(predecessor.startDate);
|
|
623
|
+
const isMilestone = predecessor.type === "milestone";
|
|
624
|
+
const predEnd = isMilestone ? new Date(predStart.getTime() - DAY_MS) : parseDateFn(predecessor.endDate);
|
|
625
|
+
return { predStart, predEnd };
|
|
626
|
+
}
|
|
617
627
|
function getDependencyLag(dep) {
|
|
618
628
|
return Number.isFinite(dep.lag) ? dep.lag : 0;
|
|
619
629
|
}
|
|
@@ -889,8 +899,7 @@ function clampTaskRangeForIncomingFS(task, proposedStart, proposedEnd, allTasks,
|
|
|
889
899
|
if (!predecessor) {
|
|
890
900
|
continue;
|
|
891
901
|
}
|
|
892
|
-
const predecessorStart =
|
|
893
|
-
const predecessorEnd = parseDateOnly(predecessor.endDate);
|
|
902
|
+
const { predStart: predecessorStart, predEnd: predecessorEnd } = normalizePredecessorDates(predecessor, parseDateOnly);
|
|
894
903
|
const predecessorDuration = getTaskDuration(
|
|
895
904
|
predecessorStart,
|
|
896
905
|
predecessorEnd,
|
|
@@ -926,8 +935,10 @@ function recalculateIncomingLags(task, newStartDate, newEndDate, allTasks, busin
|
|
|
926
935
|
if (!predecessor) {
|
|
927
936
|
return { ...dep, lag: getDependencyLag(dep) };
|
|
928
937
|
}
|
|
929
|
-
const predecessorStart =
|
|
930
|
-
|
|
938
|
+
const { predStart: predecessorStart, predEnd: predecessorEnd } = normalizePredecessorDates(
|
|
939
|
+
predecessor,
|
|
940
|
+
(d) => new Date(d instanceof Date ? d.getTime() : `${String(d).split("T")[0]}T00:00:00.000Z`)
|
|
941
|
+
);
|
|
931
942
|
const nextLag = computeLagFromDates(
|
|
932
943
|
dep.type,
|
|
933
944
|
predecessorStart,
|
|
@@ -942,6 +953,12 @@ function recalculateIncomingLags(task, newStartDate, newEndDate, allTasks, busin
|
|
|
942
953
|
}
|
|
943
954
|
|
|
944
955
|
// src/core/scheduling/cascade.ts
|
|
956
|
+
function parseCascadeDateInput(date) {
|
|
957
|
+
if (date instanceof Date) {
|
|
958
|
+
return normalizeUTCDate(date);
|
|
959
|
+
}
|
|
960
|
+
return normalizeUTCDate(/* @__PURE__ */ new Date(`${date.split("T")[0]}T00:00:00.000Z`));
|
|
961
|
+
}
|
|
945
962
|
function getSuccessorChain(draggedTaskId, allTasks, linkTypes = ["FS"]) {
|
|
946
963
|
const successorMap = /* @__PURE__ */ new Map();
|
|
947
964
|
for (const task of allTasks) {
|
|
@@ -1020,7 +1037,21 @@ function cascadeByLinks(movedTaskId, newStart, newEnd, allTasks, skipChildCascad
|
|
|
1020
1037
|
const origStart = new Date(orig.startDate);
|
|
1021
1038
|
const origEnd = new Date(orig.endDate);
|
|
1022
1039
|
const duration = getTaskDuration(origStart, origEnd);
|
|
1023
|
-
const
|
|
1040
|
+
const currentTask = taskById.get(currentId);
|
|
1041
|
+
const { predStart: normalizedPredStart, predEnd: normalizedPredEnd } = normalizePredecessorDates(
|
|
1042
|
+
{
|
|
1043
|
+
startDate: predStart,
|
|
1044
|
+
endDate: predEnd,
|
|
1045
|
+
type: currentTask.type
|
|
1046
|
+
},
|
|
1047
|
+
parseCascadeDateInput
|
|
1048
|
+
);
|
|
1049
|
+
const constraintDate = calculateSuccessorDate(
|
|
1050
|
+
normalizedPredStart,
|
|
1051
|
+
normalizedPredEnd,
|
|
1052
|
+
dep.type,
|
|
1053
|
+
getDependencyLag(dep)
|
|
1054
|
+
);
|
|
1024
1055
|
let newSuccStart;
|
|
1025
1056
|
let newSuccEnd;
|
|
1026
1057
|
if (dep.type === "FS" || dep.type === "SS") {
|
|
@@ -1175,9 +1206,17 @@ function universalCascade(movedTask, newStart, newEnd, allTasks, businessDays =
|
|
|
1175
1206
|
if (!dep) continue;
|
|
1176
1207
|
const origStart = new Date(task.startDate);
|
|
1177
1208
|
const origEnd = new Date(task.endDate);
|
|
1209
|
+
const { predStart: normalizedPredStart, predEnd: normalizedPredEnd } = normalizePredecessorDates(
|
|
1210
|
+
{
|
|
1211
|
+
startDate: currStart,
|
|
1212
|
+
endDate: currEnd,
|
|
1213
|
+
type: currentOriginal.type
|
|
1214
|
+
},
|
|
1215
|
+
parseCascadeDateInput
|
|
1216
|
+
);
|
|
1178
1217
|
const constraintDate = calculateSuccessorDate(
|
|
1179
|
-
|
|
1180
|
-
|
|
1218
|
+
normalizedPredStart,
|
|
1219
|
+
normalizedPredEnd,
|
|
1181
1220
|
dep.type,
|
|
1182
1221
|
getDependencyLag(dep),
|
|
1183
1222
|
businessDays,
|
|
@@ -1394,8 +1433,7 @@ function recalculateTaskFromDependencies(taskId, snapshot, options) {
|
|
|
1394
1433
|
for (const dep of task.dependencies) {
|
|
1395
1434
|
const predecessor = snapshot.find((t) => t.id === dep.taskId);
|
|
1396
1435
|
if (!predecessor) continue;
|
|
1397
|
-
const predStart =
|
|
1398
|
-
const predEnd = parseDateOnly(predecessor.endDate);
|
|
1436
|
+
const { predStart, predEnd } = normalizePredecessorDates(predecessor, parseDateOnly);
|
|
1399
1437
|
const constraintDate = calculateSuccessorDate(
|
|
1400
1438
|
predStart,
|
|
1401
1439
|
predEnd,
|
|
@@ -1511,8 +1549,7 @@ function recalculateProjectSchedule(snapshot, options) {
|
|
|
1511
1549
|
if (!predecessor) {
|
|
1512
1550
|
continue;
|
|
1513
1551
|
}
|
|
1514
|
-
const predecessorStart =
|
|
1515
|
-
const predecessorEnd = parseDateOnly(predecessor.endDate);
|
|
1552
|
+
const { predStart: predecessorStart, predEnd: predecessorEnd } = normalizePredecessorDates(predecessor, parseDateOnly);
|
|
1516
1553
|
const constraintDate = calculateSuccessorDate(
|
|
1517
1554
|
predecessorStart,
|
|
1518
1555
|
predecessorEnd,
|
|
@@ -1931,6 +1968,45 @@ var calculateTaskBar = (taskStartDate, taskEndDate, monthStart, dayWidth) => {
|
|
|
1931
1968
|
const width = Math.round((duration + 1) * dayWidth);
|
|
1932
1969
|
return { left, width };
|
|
1933
1970
|
};
|
|
1971
|
+
var calculateMilestoneGeometry = (taskDate, monthStart, dayWidth, size = 14) => {
|
|
1972
|
+
const { left, width } = calculateTaskBar(taskDate, taskDate, monthStart, dayWidth);
|
|
1973
|
+
const centerX = Math.round(left + width / 2);
|
|
1974
|
+
const halfSize = Math.round(size / 2);
|
|
1975
|
+
return {
|
|
1976
|
+
centerX,
|
|
1977
|
+
left: centerX - halfSize,
|
|
1978
|
+
right: centerX + halfSize,
|
|
1979
|
+
size
|
|
1980
|
+
};
|
|
1981
|
+
};
|
|
1982
|
+
var calculateMilestoneConnectionBounds = (dayLeft, dayWidth, size = 14) => {
|
|
1983
|
+
const halfDiagonal = Math.round(size / Math.SQRT2);
|
|
1984
|
+
const visualNudge = 2;
|
|
1985
|
+
return {
|
|
1986
|
+
left: dayLeft + halfDiagonal + visualNudge,
|
|
1987
|
+
right: dayLeft + dayWidth - halfDiagonal - visualNudge
|
|
1988
|
+
};
|
|
1989
|
+
};
|
|
1990
|
+
var resolveTaskHorizontalGeometry = (task, monthStart, dayWidth, override) => {
|
|
1991
|
+
const startDate = new Date(task.startDate);
|
|
1992
|
+
const endDate = new Date(task.endDate);
|
|
1993
|
+
if (task.type === "milestone") {
|
|
1994
|
+
const size = 14;
|
|
1995
|
+
if (override) {
|
|
1996
|
+
return calculateMilestoneConnectionBounds(override.left, dayWidth, size);
|
|
1997
|
+
}
|
|
1998
|
+
const bar2 = calculateTaskBar(startDate, startDate, monthStart, dayWidth);
|
|
1999
|
+
return calculateMilestoneConnectionBounds(bar2.left, dayWidth, size);
|
|
2000
|
+
}
|
|
2001
|
+
if (override) {
|
|
2002
|
+
return {
|
|
2003
|
+
left: override.left,
|
|
2004
|
+
right: override.left + override.width
|
|
2005
|
+
};
|
|
2006
|
+
}
|
|
2007
|
+
const bar = calculateTaskBar(startDate, endDate, monthStart, dayWidth);
|
|
2008
|
+
return { left: bar.left, right: bar.left + bar.width };
|
|
2009
|
+
};
|
|
1934
2010
|
var pixelsToDate = (pixels, monthStart, dayWidth) => {
|
|
1935
2011
|
const days = Math.round(pixels / dayWidth);
|
|
1936
2012
|
return new Date(Date.UTC(
|
|
@@ -2034,6 +2110,9 @@ var calculateDependencyPath = (from, to, arrivesFromRight) => {
|
|
|
2034
2110
|
if (fy === ty) {
|
|
2035
2111
|
return `M ${fx} ${fy} H ${tx}`;
|
|
2036
2112
|
}
|
|
2113
|
+
if (fx === tx) {
|
|
2114
|
+
return `M ${fx} ${fy} V ${ty}`;
|
|
2115
|
+
}
|
|
2037
2116
|
const C = 2;
|
|
2038
2117
|
const goingDown = ty > fy;
|
|
2039
2118
|
const dirY = goingDown ? 1 : -1;
|
|
@@ -2141,6 +2220,37 @@ var isTaskExpired = (task, referenceDate = /* @__PURE__ */ new Date()) => {
|
|
|
2141
2220
|
return actualProgress < expectedProgress;
|
|
2142
2221
|
};
|
|
2143
2222
|
|
|
2223
|
+
// src/utils/taskType.ts
|
|
2224
|
+
init_dateUtils();
|
|
2225
|
+
var TASK_TYPE_DEFAULT = "task";
|
|
2226
|
+
function getTaskType(task) {
|
|
2227
|
+
return task.type ?? TASK_TYPE_DEFAULT;
|
|
2228
|
+
}
|
|
2229
|
+
function isMilestoneTask(task) {
|
|
2230
|
+
return getTaskType(task) === "milestone";
|
|
2231
|
+
}
|
|
2232
|
+
function normalizeMilestoneStartDate(startDateInput) {
|
|
2233
|
+
const parsedStartDate = parseUTCDate(startDateInput);
|
|
2234
|
+
if (startDateInput instanceof Date) {
|
|
2235
|
+
return new Date(Date.UTC(
|
|
2236
|
+
parsedStartDate.getUTCFullYear(),
|
|
2237
|
+
parsedStartDate.getUTCMonth(),
|
|
2238
|
+
parsedStartDate.getUTCDate()
|
|
2239
|
+
));
|
|
2240
|
+
}
|
|
2241
|
+
return parsedStartDate.toISOString().split("T")[0];
|
|
2242
|
+
}
|
|
2243
|
+
function normalizeTaskDatesForType(task) {
|
|
2244
|
+
if (!isMilestoneTask(task)) {
|
|
2245
|
+
return task;
|
|
2246
|
+
}
|
|
2247
|
+
const startDate = normalizeMilestoneStartDate(task.startDate);
|
|
2248
|
+
return {
|
|
2249
|
+
...task,
|
|
2250
|
+
endDate: startDate
|
|
2251
|
+
};
|
|
2252
|
+
}
|
|
2253
|
+
|
|
2144
2254
|
// src/hooks/useTaskDrag.ts
|
|
2145
2255
|
var import_react2 = require("react");
|
|
2146
2256
|
|
|
@@ -2159,6 +2269,17 @@ function resolveDateRangeFromPixels(mode, left, width, monthStart, dayWidth, tas
|
|
|
2159
2269
|
monthStart.getUTCMonth(),
|
|
2160
2270
|
monthStart.getUTCDate() + rawEndOffset
|
|
2161
2271
|
));
|
|
2272
|
+
const isMilestone = task.type === "milestone";
|
|
2273
|
+
if (isMilestone) {
|
|
2274
|
+
const anchorDate = mode === "resize-right" ? rawEndDate : rawStartDate;
|
|
2275
|
+
if (businessDays && weekendPredicate) {
|
|
2276
|
+
const originalAnchor = mode === "resize-right" ? new Date(task.endDate) : new Date(task.startDate);
|
|
2277
|
+
const snapDirection2 = anchorDate.getTime() >= originalAnchor.getTime() ? 1 : -1;
|
|
2278
|
+
const alignedDate = alignToWorkingDay(anchorDate, snapDirection2, weekendPredicate);
|
|
2279
|
+
return { start: alignedDate, end: alignedDate };
|
|
2280
|
+
}
|
|
2281
|
+
return { start: anchorDate, end: anchorDate };
|
|
2282
|
+
}
|
|
2162
2283
|
if (!(businessDays && weekendPredicate)) {
|
|
2163
2284
|
return { start: rawStartDate, end: rawEndDate };
|
|
2164
2285
|
}
|
|
@@ -2249,8 +2370,10 @@ function handleGlobalMouseMove(e) {
|
|
|
2249
2370
|
const activeDrag = globalActiveDrag;
|
|
2250
2371
|
const { startX, initialLeft, initialWidth, mode, dayWidth, onProgress, allTasks } = activeDrag;
|
|
2251
2372
|
const deltaX = e.clientX - startX;
|
|
2373
|
+
const draggedTask = allTasks.find((t) => t.id === activeDrag.taskId);
|
|
2374
|
+
const effectiveWidth = draggedTask && isMilestoneTask(draggedTask) ? dayWidth : initialWidth;
|
|
2252
2375
|
let newLeft = initialLeft;
|
|
2253
|
-
let newWidth =
|
|
2376
|
+
let newWidth = effectiveWidth;
|
|
2254
2377
|
switch (mode) {
|
|
2255
2378
|
case "move":
|
|
2256
2379
|
newLeft = snapToGrid(initialLeft + deltaX, dayWidth);
|
|
@@ -2266,7 +2389,6 @@ function handleGlobalMouseMove(e) {
|
|
|
2266
2389
|
newWidth = Math.max(dayWidth, snappedWidth);
|
|
2267
2390
|
break;
|
|
2268
2391
|
}
|
|
2269
|
-
const draggedTask = allTasks.find((t) => t.id === activeDrag.taskId);
|
|
2270
2392
|
if (activeDrag.businessDays && activeDrag.weekendPredicate && draggedTask) {
|
|
2271
2393
|
const previewRange = clampDateRangeForIncomingFS(
|
|
2272
2394
|
draggedTask,
|
|
@@ -2308,6 +2430,9 @@ function handleGlobalMouseMove(e) {
|
|
|
2308
2430
|
newLeft = Math.round(alignedStartDay * dayWidth);
|
|
2309
2431
|
newWidth = Math.round((alignedEndDay - alignedStartDay + 1) * dayWidth);
|
|
2310
2432
|
}
|
|
2433
|
+
if (draggedTask && isMilestoneTask(draggedTask)) {
|
|
2434
|
+
newWidth = dayWidth;
|
|
2435
|
+
}
|
|
2311
2436
|
if (!activeDrag.disableConstraints && activeDrag.onCascadeProgress) {
|
|
2312
2437
|
const { dayWidth: dayWidth2, monthStart: mStart, taskId: dragId } = activeDrag;
|
|
2313
2438
|
const originalDraggedTask = draggedTask ?? allTasks.find((t) => t.id === dragId);
|
|
@@ -2344,7 +2469,8 @@ function handleGlobalMouseMove(e) {
|
|
|
2344
2469
|
};
|
|
2345
2470
|
})();
|
|
2346
2471
|
const previewStartDate = previewRange.start;
|
|
2347
|
-
const
|
|
2472
|
+
const isMilestone = originalDraggedTask ? isMilestoneTask(originalDraggedTask) : false;
|
|
2473
|
+
const previewEndDate = isMilestone ? previewRange.start : previewRange.end;
|
|
2348
2474
|
const movedTaskData = originalDraggedTask ?? { id: dragId, name: "", startDate: "", endDate: "" };
|
|
2349
2475
|
const cascadeResult = universalCascade(
|
|
2350
2476
|
{ ...movedTaskData, startDate: previewStartDate.toISOString(), endDate: previewEndDate.toISOString() },
|
|
@@ -2434,6 +2560,9 @@ var useTaskDrag = (options) => {
|
|
|
2434
2560
|
businessDays = true,
|
|
2435
2561
|
weekendPredicate
|
|
2436
2562
|
} = options;
|
|
2563
|
+
const rawHookTask = allTasks.find((t) => t.id === taskId);
|
|
2564
|
+
const hookTask = rawHookTask ? normalizeTaskDatesForType(rawHookTask) : void 0;
|
|
2565
|
+
const hookTaskIsMilestone = hookTask ? isMilestoneTask(hookTask) : false;
|
|
2437
2566
|
const isOwnerRef = (0, import_react2.useRef)(false);
|
|
2438
2567
|
const effectiveLocked = locked || disableTaskDrag;
|
|
2439
2568
|
const [isDragging, setIsDragging] = (0, import_react2.useState)(false);
|
|
@@ -2455,11 +2584,11 @@ var useTaskDrag = (options) => {
|
|
|
2455
2584
|
return Math.round((ms1 - ms2) / (1e3 * 60 * 60 * 24));
|
|
2456
2585
|
};
|
|
2457
2586
|
const startOffset = getUTCDayDifference2(initialStartDate, monthStart);
|
|
2458
|
-
const duration = getUTCDayDifference2(initialEndDate, initialStartDate);
|
|
2587
|
+
const duration = hookTaskIsMilestone ? 0 : getUTCDayDifference2(initialEndDate, initialStartDate);
|
|
2459
2588
|
const left = Math.round(startOffset * dayWidth);
|
|
2460
2589
|
const width = Math.round((duration + 1) * dayWidth);
|
|
2461
2590
|
return { left, width };
|
|
2462
|
-
}, [initialStartDate, initialEndDate, monthStart, dayWidth]);
|
|
2591
|
+
}, [initialStartDate, initialEndDate, monthStart, dayWidth, hookTaskIsMilestone]);
|
|
2463
2592
|
(0, import_react2.useEffect)(() => {
|
|
2464
2593
|
if (isOwnerRef.current && globalActiveDrag) return;
|
|
2465
2594
|
const { left, width } = getInitialPosition();
|
|
@@ -2494,7 +2623,8 @@ var useTaskDrag = (options) => {
|
|
|
2494
2623
|
const handleComplete = (0, import_react2.useCallback)((finalLeft, finalWidth, finalMode) => {
|
|
2495
2624
|
const wasOwner = isOwnerRef.current;
|
|
2496
2625
|
isOwnerRef.current = false;
|
|
2497
|
-
const
|
|
2626
|
+
const currentTaskRaw = allTasks.find((t) => t.id === taskId);
|
|
2627
|
+
const currentTask = currentTaskRaw ? normalizeTaskDatesForType(currentTaskRaw) : void 0;
|
|
2498
2628
|
const finalRange = currentTask ? clampDateRangeForIncomingFS(
|
|
2499
2629
|
currentTask,
|
|
2500
2630
|
resolveDateRangeFromPixels(
|
|
@@ -2528,7 +2658,7 @@ var useTaskDrag = (options) => {
|
|
|
2528
2658
|
};
|
|
2529
2659
|
})();
|
|
2530
2660
|
const newStartDate = finalRange.start;
|
|
2531
|
-
const newEndDate = finalRange.end;
|
|
2661
|
+
const newEndDate = currentTask && isMilestoneTask(currentTask) ? finalRange.start : finalRange.end;
|
|
2532
2662
|
setIsDragging(false);
|
|
2533
2663
|
setDragMode(null);
|
|
2534
2664
|
if (onDragStateChange) {
|
|
@@ -2540,6 +2670,23 @@ var useTaskDrag = (options) => {
|
|
|
2540
2670
|
});
|
|
2541
2671
|
}
|
|
2542
2672
|
if (wasOwner) {
|
|
2673
|
+
const startUnchanged = newStartDate.getTime() === Date.UTC(
|
|
2674
|
+
initialStartDate.getUTCFullYear(),
|
|
2675
|
+
initialStartDate.getUTCMonth(),
|
|
2676
|
+
initialStartDate.getUTCDate()
|
|
2677
|
+
);
|
|
2678
|
+
const baselineEndDate = hookTaskIsMilestone ? initialStartDate : initialEndDate;
|
|
2679
|
+
const endUnchanged = newEndDate.getTime() === Date.UTC(
|
|
2680
|
+
baselineEndDate.getUTCFullYear(),
|
|
2681
|
+
baselineEndDate.getUTCMonth(),
|
|
2682
|
+
baselineEndDate.getUTCDate()
|
|
2683
|
+
);
|
|
2684
|
+
if (startUnchanged && endUnchanged) {
|
|
2685
|
+
const { left, width } = getInitialPosition();
|
|
2686
|
+
setCurrentLeft(left);
|
|
2687
|
+
setCurrentWidth(width);
|
|
2688
|
+
return;
|
|
2689
|
+
}
|
|
2543
2690
|
if (!disableConstraints && onCascade && allTasks.length > 0) {
|
|
2544
2691
|
const draggedTaskData = currentTask;
|
|
2545
2692
|
const movedTask = {
|
|
@@ -2577,7 +2724,8 @@ var useTaskDrag = (options) => {
|
|
|
2577
2724
|
businessDays,
|
|
2578
2725
|
weekendPredicate,
|
|
2579
2726
|
initialStartDate,
|
|
2580
|
-
initialEndDate
|
|
2727
|
+
initialEndDate,
|
|
2728
|
+
hookTaskIsMilestone
|
|
2581
2729
|
]);
|
|
2582
2730
|
const handleCancel = (0, import_react2.useCallback)(() => {
|
|
2583
2731
|
isOwnerRef.current = false;
|
|
@@ -2620,6 +2768,9 @@ var useTaskDrag = (options) => {
|
|
|
2620
2768
|
if (currentTask2 && isTaskParent(taskId, allTasks)) {
|
|
2621
2769
|
mode = "move";
|
|
2622
2770
|
}
|
|
2771
|
+
if (currentTask2 && isMilestoneTask(currentTask2)) {
|
|
2772
|
+
mode = "move";
|
|
2773
|
+
}
|
|
2623
2774
|
}
|
|
2624
2775
|
if (!mode) {
|
|
2625
2776
|
return;
|
|
@@ -2705,14 +2856,16 @@ var useTaskDrag = (options) => {
|
|
|
2705
2856
|
// src/components/TaskRow/TaskRow.tsx
|
|
2706
2857
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
2707
2858
|
var arePropsEqual = (prevProps, nextProps) => {
|
|
2708
|
-
return prevProps.task.id === nextProps.task.id && prevProps.task.name === nextProps.task.name && prevProps.task.startDate === nextProps.task.startDate && prevProps.task.endDate === nextProps.task.endDate && prevProps.task.color === nextProps.task.color && prevProps.task.progress === nextProps.task.progress && prevProps.task.accepted === nextProps.task.accepted && prevProps.monthStart.getTime() === nextProps.monthStart.getTime() && prevProps.dayWidth === nextProps.dayWidth && prevProps.rowHeight === nextProps.rowHeight && prevProps.overridePosition?.left === nextProps.overridePosition?.left && prevProps.overridePosition?.width === nextProps.overridePosition?.width && prevProps.allTasks === nextProps.allTasks && prevProps.disableConstraints === nextProps.disableConstraints && prevProps.task.locked === nextProps.task.locked && prevProps.task.divider === nextProps.task.divider && prevProps.highlightExpiredTasks === nextProps.highlightExpiredTasks && prevProps.isFilterMatch === nextProps.isFilterMatch && prevProps.businessDays === nextProps.businessDays && prevProps.customDays === nextProps.customDays && prevProps.isWeekend === nextProps.isWeekend && prevProps.disableTaskDrag === nextProps.disableTaskDrag;
|
|
2859
|
+
return prevProps.task.id === nextProps.task.id && prevProps.task.name === nextProps.task.name && prevProps.task.startDate === nextProps.task.startDate && prevProps.task.endDate === nextProps.task.endDate && prevProps.task.type === nextProps.task.type && prevProps.task.color === nextProps.task.color && prevProps.task.progress === nextProps.task.progress && prevProps.task.accepted === nextProps.task.accepted && prevProps.monthStart.getTime() === nextProps.monthStart.getTime() && prevProps.dayWidth === nextProps.dayWidth && prevProps.rowHeight === nextProps.rowHeight && prevProps.overridePosition?.left === nextProps.overridePosition?.left && prevProps.overridePosition?.width === nextProps.overridePosition?.width && prevProps.allTasks === nextProps.allTasks && prevProps.disableConstraints === nextProps.disableConstraints && prevProps.task.locked === nextProps.task.locked && prevProps.task.divider === nextProps.task.divider && prevProps.highlightExpiredTasks === nextProps.highlightExpiredTasks && prevProps.isFilterMatch === nextProps.isFilterMatch && prevProps.businessDays === nextProps.businessDays && prevProps.customDays === nextProps.customDays && prevProps.isWeekend === nextProps.isWeekend && prevProps.disableTaskDrag === nextProps.disableTaskDrag;
|
|
2709
2860
|
};
|
|
2710
2861
|
var TaskRow = import_react3.default.memo(
|
|
2711
2862
|
({ task, monthStart, dayWidth, rowHeight, onTasksChange, onDragStateChange, rowIndex, allTasks, enableAutoSchedule, disableConstraints, overridePosition, onCascadeProgress, onCascade, divider, highlightExpiredTasks, isFilterMatch = false, businessDays, customDays, isWeekend: isWeekend3, disableTaskDrag = false }) => {
|
|
2712
2863
|
const defaultParentBarColor = "#782FC4";
|
|
2713
2864
|
const { divider: taskDivider } = task;
|
|
2714
|
-
const
|
|
2715
|
-
const
|
|
2865
|
+
const normalizedTask = (0, import_react3.useMemo)(() => normalizeTaskDatesForType(task), [task]);
|
|
2866
|
+
const milestone = (0, import_react3.useMemo)(() => isMilestoneTask(normalizedTask), [normalizedTask]);
|
|
2867
|
+
const taskStartDate = (0, import_react3.useMemo)(() => parseUTCDate(normalizedTask.startDate), [normalizedTask.startDate]);
|
|
2868
|
+
const taskEndDate = (0, import_react3.useMemo)(() => parseUTCDate(normalizedTask.endDate), [normalizedTask.endDate]);
|
|
2716
2869
|
const isParent = (0, import_react3.useMemo)(() => {
|
|
2717
2870
|
return allTasks ? isTaskParent(task.id, allTasks) : false;
|
|
2718
2871
|
}, [allTasks, task.id]);
|
|
@@ -2721,12 +2874,16 @@ var TaskRow = import_react3.default.memo(
|
|
|
2721
2874
|
}, [allTasks, task.id]);
|
|
2722
2875
|
const isExpired = (0, import_react3.useMemo)(() => {
|
|
2723
2876
|
if (!highlightExpiredTasks) return false;
|
|
2724
|
-
return isTaskExpired(
|
|
2725
|
-
}, [
|
|
2877
|
+
return isTaskExpired(normalizedTask);
|
|
2878
|
+
}, [normalizedTask.startDate, normalizedTask.endDate, normalizedTask.progress, highlightExpiredTasks]);
|
|
2726
2879
|
const { left, width } = (0, import_react3.useMemo)(
|
|
2727
2880
|
() => calculateTaskBar(taskStartDate, taskEndDate, monthStart, dayWidth),
|
|
2728
2881
|
[taskStartDate, taskEndDate, monthStart, dayWidth]
|
|
2729
2882
|
);
|
|
2883
|
+
const milestoneGeometry = (0, import_react3.useMemo)(
|
|
2884
|
+
() => calculateMilestoneGeometry(taskStartDate, monthStart, dayWidth),
|
|
2885
|
+
[taskStartDate, monthStart, dayWidth]
|
|
2886
|
+
);
|
|
2730
2887
|
const barColor = isExpired ? "var(--gantt-expired-color)" : task.color || "var(--gantt-task-bar-default-color)";
|
|
2731
2888
|
const progressWidth = (0, import_react3.useMemo)(() => {
|
|
2732
2889
|
if (task.progress === void 0 || task.progress <= 0) return 0;
|
|
@@ -2765,7 +2922,7 @@ var TaskRow = import_react3.default.memo(
|
|
|
2765
2922
|
}, [defaultParentBarColor, isExpired, isParent, progressWidth, barColor, progressColor, task.color]);
|
|
2766
2923
|
const handleDragEnd = (result) => {
|
|
2767
2924
|
const updatedTask = {
|
|
2768
|
-
...
|
|
2925
|
+
...normalizedTask,
|
|
2769
2926
|
startDate: result.startDate.toISOString(),
|
|
2770
2927
|
endDate: result.endDate.toISOString(),
|
|
2771
2928
|
...result.updatedDependencies !== void 0 && { dependencies: result.updatedDependencies }
|
|
@@ -2804,8 +2961,20 @@ var TaskRow = import_react3.default.memo(
|
|
|
2804
2961
|
});
|
|
2805
2962
|
const displayLeft = overridePosition?.left ?? (isDragging ? currentLeft : left);
|
|
2806
2963
|
const displayWidth = overridePosition?.width ?? (isDragging ? currentWidth : width);
|
|
2964
|
+
const displayMilestoneGeometry = (0, import_react3.useMemo)(() => {
|
|
2965
|
+
const centerX = Math.round(displayLeft + dayWidth / 2);
|
|
2966
|
+
const halfSize = Math.round(milestoneGeometry.size / 2);
|
|
2967
|
+
return {
|
|
2968
|
+
centerX,
|
|
2969
|
+
left: centerX - halfSize,
|
|
2970
|
+
right: centerX + halfSize,
|
|
2971
|
+
size: milestoneGeometry.size
|
|
2972
|
+
};
|
|
2973
|
+
}, [displayLeft, dayWidth, milestoneGeometry.size]);
|
|
2974
|
+
const visualLeft = milestone ? displayMilestoneGeometry.left : displayLeft;
|
|
2975
|
+
const visualWidth = milestone ? displayMilestoneGeometry.size : displayWidth;
|
|
2807
2976
|
const currentStartDate = isDragging ? pixelsToDate(displayLeft, monthStart, dayWidth) : taskStartDate;
|
|
2808
|
-
const currentEndDate = isDragging ? pixelsToDate(displayLeft + displayWidth - dayWidth, monthStart, dayWidth) : taskEndDate;
|
|
2977
|
+
const currentEndDate = isDragging ? milestone ? pixelsToDate(displayLeft, monthStart, dayWidth) : pixelsToDate(displayLeft + displayWidth - dayWidth, monthStart, dayWidth) : taskEndDate;
|
|
2809
2978
|
const dateRangeLabel = formatDateRangeLabel(currentStartDate, currentEndDate);
|
|
2810
2979
|
const durationDays = businessDays ? getBusinessDaysCount(currentStartDate, currentEndDate, weekendPredicate) : Math.round(
|
|
2811
2980
|
(currentEndDate.getTime() - currentStartDate.getTime()) / (1e3 * 60 * 60 * 24)
|
|
@@ -2820,9 +2989,9 @@ var TaskRow = import_react3.default.memo(
|
|
|
2820
2989
|
return `${count} \u0437\u0430\u0434\u0430\u0447`;
|
|
2821
2990
|
};
|
|
2822
2991
|
const estimatedTextWidth = isParent ? 120 : durationDays >= 10 ? 76 : 62;
|
|
2823
|
-
const showProgressInside = progressWidth > 0 && displayWidth > estimatedTextWidth;
|
|
2992
|
+
const showProgressInside = !milestone && progressWidth > 0 && displayWidth > estimatedTextWidth;
|
|
2824
2993
|
const MIN_DURATION_WIDTH = isParent ? 80 : 50;
|
|
2825
|
-
const showDurationInside = durationDays >= 2 && displayWidth > MIN_DURATION_WIDTH;
|
|
2994
|
+
const showDurationInside = !milestone && durationDays >= 2 && displayWidth > MIN_DURATION_WIDTH;
|
|
2826
2995
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
2827
2996
|
"div",
|
|
2828
2997
|
{
|
|
@@ -2836,18 +3005,24 @@ var TaskRow = import_react3.default.memo(
|
|
|
2836
3005
|
"div",
|
|
2837
3006
|
{
|
|
2838
3007
|
"data-taskbar": true,
|
|
2839
|
-
className: `gantt-tr-taskBar ${isDragging ? "gantt-tr-dragging" : ""} ${task.locked ? "gantt-tr-locked" : ""} ${isParent ? "gantt-tr-parentBar" : ""}`,
|
|
3008
|
+
className: `gantt-tr-taskBar ${isDragging ? "gantt-tr-dragging" : ""} ${task.locked ? "gantt-tr-locked" : ""} ${isParent ? "gantt-tr-parentBar" : ""} ${milestone ? "gantt-tr-milestone" : ""}`,
|
|
2840
3009
|
style: {
|
|
2841
|
-
left: `${
|
|
2842
|
-
width: `${displayWidth}px`,
|
|
3010
|
+
left: `${visualLeft}px`,
|
|
2843
3011
|
...barStyle,
|
|
2844
|
-
|
|
3012
|
+
...milestone ? {
|
|
3013
|
+
height: `${displayMilestoneGeometry.size}px`,
|
|
3014
|
+
width: `${displayMilestoneGeometry.size}px`,
|
|
3015
|
+
padding: 0
|
|
3016
|
+
} : {
|
|
3017
|
+
width: `${visualWidth}px`,
|
|
3018
|
+
height: isParent ? "var(--gantt-parent-bar-height, 14px)" : "var(--gantt-task-bar-height)"
|
|
3019
|
+
},
|
|
2845
3020
|
cursor: dragHandleProps.style.cursor,
|
|
2846
3021
|
userSelect: dragHandleProps.style.userSelect
|
|
2847
3022
|
},
|
|
2848
3023
|
onMouseDown: dragHandleProps.onMouseDown,
|
|
2849
3024
|
children: [
|
|
2850
|
-
progressWidth > 0 && progressWidth < 100 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
3025
|
+
!milestone && progressWidth > 0 && progressWidth < 100 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2851
3026
|
"div",
|
|
2852
3027
|
{
|
|
2853
3028
|
className: "gantt-tr-progressBar",
|
|
@@ -2860,13 +3035,13 @@ var TaskRow = import_react3.default.memo(
|
|
|
2860
3035
|
}
|
|
2861
3036
|
}
|
|
2862
3037
|
),
|
|
2863
|
-
!isParent && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "gantt-tr-resizeHandle gantt-tr-resizeHandleLeft" }),
|
|
3038
|
+
!isParent && !milestone && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "gantt-tr-resizeHandle gantt-tr-resizeHandleLeft" }),
|
|
2864
3039
|
showDurationInside && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "gantt-tr-taskDuration", children: isParent ? getChildCountLabel(childCount) : `${durationDays} \u0434` }),
|
|
2865
3040
|
progressWidth > 0 && showProgressInside && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "gantt-tr-progressText", children: [
|
|
2866
3041
|
progressWidth,
|
|
2867
3042
|
"%"
|
|
2868
3043
|
] }),
|
|
2869
|
-
!isParent && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "gantt-tr-resizeHandle gantt-tr-resizeHandleRight" })
|
|
3044
|
+
!isParent && !milestone && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "gantt-tr-resizeHandle gantt-tr-resizeHandleRight" })
|
|
2870
3045
|
]
|
|
2871
3046
|
}
|
|
2872
3047
|
),
|
|
@@ -2875,7 +3050,7 @@ var TaskRow = import_react3.default.memo(
|
|
|
2875
3050
|
{
|
|
2876
3051
|
className: `gantt-tr-leftLabels ${task.locked ? "gantt-tr-leftLabels-locked" : ""}`,
|
|
2877
3052
|
style: {
|
|
2878
|
-
left: `${
|
|
3053
|
+
left: `${visualLeft}px`
|
|
2879
3054
|
},
|
|
2880
3055
|
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "gantt-tr-dateLabel gantt-tr-dateLabelLeft", children: dateRangeLabel })
|
|
2881
3056
|
}
|
|
@@ -2886,7 +3061,7 @@ var TaskRow = import_react3.default.memo(
|
|
|
2886
3061
|
className: "gantt-tr-lockIcon",
|
|
2887
3062
|
style: {
|
|
2888
3063
|
position: "absolute",
|
|
2889
|
-
left: `${
|
|
3064
|
+
left: `${visualLeft - 16}px`,
|
|
2890
3065
|
top: "50%",
|
|
2891
3066
|
transform: "translateY(-50%)",
|
|
2892
3067
|
width: "12px",
|
|
@@ -2906,11 +3081,11 @@ var TaskRow = import_react3.default.memo(
|
|
|
2906
3081
|
{
|
|
2907
3082
|
className: "gantt-tr-rightLabels",
|
|
2908
3083
|
style: {
|
|
2909
|
-
left: `${
|
|
3084
|
+
left: `${visualLeft + Math.max(visualWidth, 20) - Math.min(6, Math.max(visualWidth, 20) / 2) + 8}px`,
|
|
2910
3085
|
color: isParent ? task.color || defaultParentBarColor : barColor
|
|
2911
3086
|
},
|
|
2912
3087
|
children: [
|
|
2913
|
-
!showDurationInside && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "gantt-tr-externalDuration", children: isParent ? getChildCountLabel(childCount) : `${durationDays} \u0434` }),
|
|
3088
|
+
!showDurationInside && !milestone && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "gantt-tr-externalDuration", children: isParent ? getChildCountLabel(childCount) : `${durationDays} \u0434` }),
|
|
2914
3089
|
progressWidth > 0 && !showProgressInside && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "gantt-tr-externalProgress", children: [
|
|
2915
3090
|
progressWidth,
|
|
2916
3091
|
"%"
|
|
@@ -3159,16 +3334,12 @@ var DependencyLines = import_react6.default.memo(({
|
|
|
3159
3334
|
const taskMap = new Map(tasksForPositions.map((t) => [t.id, t]));
|
|
3160
3335
|
const visibleTaskMap = new Map(tasks.map((t) => [t.id, t]));
|
|
3161
3336
|
tasks.forEach((task, index) => {
|
|
3162
|
-
const startDate = new Date(task.startDate);
|
|
3163
|
-
const endDate = new Date(task.endDate);
|
|
3164
|
-
const computed = calculateTaskBar(startDate, endDate, monthStart, dayWidth);
|
|
3165
3337
|
const override = dragOverrides?.get(task.id);
|
|
3166
|
-
const
|
|
3167
|
-
const resolvedWidth = override?.width ?? computed.width;
|
|
3338
|
+
const computed = resolveTaskHorizontalGeometry(task, monthStart, dayWidth, override);
|
|
3168
3339
|
indices.set(task.id, index);
|
|
3169
3340
|
positions.set(task.id, {
|
|
3170
|
-
left:
|
|
3171
|
-
right:
|
|
3341
|
+
left: computed.left,
|
|
3342
|
+
right: computed.right,
|
|
3172
3343
|
rowTop: index * rowHeight,
|
|
3173
3344
|
isVirtual: false
|
|
3174
3345
|
});
|
|
@@ -3182,15 +3353,11 @@ var DependencyLines = import_react6.default.memo(({
|
|
|
3182
3353
|
if (!visibleAncestor) continue;
|
|
3183
3354
|
const ancestorPosition = positions.get(visibleAncestor.id);
|
|
3184
3355
|
if (!ancestorPosition) continue;
|
|
3185
|
-
const startDate = new Date(task.startDate);
|
|
3186
|
-
const endDate = new Date(task.endDate);
|
|
3187
|
-
const computed = calculateTaskBar(startDate, endDate, monthStart, dayWidth);
|
|
3188
3356
|
const override = dragOverrides?.get(task.id);
|
|
3189
|
-
const
|
|
3190
|
-
const resolvedWidth = override?.width ?? computed.width;
|
|
3357
|
+
const computed = resolveTaskHorizontalGeometry(task, monthStart, dayWidth, override);
|
|
3191
3358
|
positions.set(task.id, {
|
|
3192
|
-
left:
|
|
3193
|
-
right:
|
|
3359
|
+
left: computed.left,
|
|
3360
|
+
right: computed.right,
|
|
3194
3361
|
rowTop: ancestorPosition.rowTop,
|
|
3195
3362
|
isVirtual: true
|
|
3196
3363
|
});
|
|
@@ -3206,6 +3373,7 @@ var DependencyLines = import_react6.default.memo(({
|
|
|
3206
3373
|
}, [tasks, allTasks]);
|
|
3207
3374
|
const lines = (0, import_react6.useMemo)(() => {
|
|
3208
3375
|
const tasksForEdges = allTasks ?? tasks;
|
|
3376
|
+
const taskMap = new Map(tasksForEdges.map((task) => [task.id, task]));
|
|
3209
3377
|
const edges = getAllDependencyEdges(tasksForEdges);
|
|
3210
3378
|
const lines2 = [];
|
|
3211
3379
|
for (const edge of edges) {
|
|
@@ -3216,9 +3384,11 @@ var DependencyLines = import_react6.default.memo(({
|
|
|
3216
3384
|
if (!predecessor || !successor) {
|
|
3217
3385
|
continue;
|
|
3218
3386
|
}
|
|
3387
|
+
const predecessorTask = taskMap.get(edge.predecessorId);
|
|
3388
|
+
const successorTask = taskMap.get(edge.successorId);
|
|
3219
3389
|
if (allTasks && collapsedParentIds.size > 0) {
|
|
3220
|
-
const
|
|
3221
|
-
if (areBothHiddenInSameParent(edge.predecessorId, edge.successorId, collapsedParentIds,
|
|
3390
|
+
const taskMap2 = new Map(allTasks.map((t) => [t.id, t]));
|
|
3391
|
+
if (areBothHiddenInSameParent(edge.predecessorId, edge.successorId, collapsedParentIds, taskMap2)) {
|
|
3222
3392
|
continue;
|
|
3223
3393
|
}
|
|
3224
3394
|
}
|
|
@@ -3238,11 +3408,18 @@ var DependencyLines = import_react6.default.memo(({
|
|
|
3238
3408
|
fromY = predecessor.rowTop + rowHeight - 10;
|
|
3239
3409
|
toY = successor.rowTop + 6;
|
|
3240
3410
|
}
|
|
3241
|
-
|
|
3411
|
+
let fromX = edge.type === "SS" || edge.type === "SF" ? predecessor.left : predecessor.right;
|
|
3242
3412
|
const toX = edge.type === "FF" || edge.type === "SF" ? successor.right : successor.left;
|
|
3413
|
+
const stackedMilestonesSameDay = Boolean(
|
|
3414
|
+
predecessorTask && successorTask && isMilestoneTask(predecessorTask) && isMilestoneTask(successorTask) && edge.lag === 0 && new Date(predecessorTask.startDate).toISOString().split("T")[0] === new Date(successorTask.startDate).toISOString().split("T")[0] && predecessor.rowTop !== successor.rowTop && edge.type === "FS"
|
|
3415
|
+
);
|
|
3416
|
+
const finalToX = stackedMilestonesSameDay ? Math.round(((predecessor.left + predecessor.right) / 2 + (successor.left + successor.right) / 2) / 2) : toX;
|
|
3417
|
+
if (stackedMilestonesSameDay) {
|
|
3418
|
+
fromX = finalToX;
|
|
3419
|
+
}
|
|
3243
3420
|
const arrivesFromRight = edge.type === "FF" || edge.type === "SF";
|
|
3244
3421
|
const from = { x: fromX, y: fromY };
|
|
3245
|
-
const to = { x:
|
|
3422
|
+
const to = { x: finalToX, y: toY };
|
|
3246
3423
|
const path = calculateDependencyPath(from, to, arrivesFromRight);
|
|
3247
3424
|
const hasCycle = cycleInfo.has(edge.predecessorId) || cycleInfo.has(edge.successorId);
|
|
3248
3425
|
lines2.push({
|
|
@@ -3251,7 +3428,7 @@ var DependencyLines = import_react6.default.memo(({
|
|
|
3251
3428
|
hasCycle,
|
|
3252
3429
|
lag: edge.lag,
|
|
3253
3430
|
fromX,
|
|
3254
|
-
toX,
|
|
3431
|
+
toX: finalToX,
|
|
3255
3432
|
fromY,
|
|
3256
3433
|
reverseOrder,
|
|
3257
3434
|
isVirtual
|
|
@@ -3264,6 +3441,7 @@ var DependencyLines = import_react6.default.memo(({
|
|
|
3264
3441
|
"svg",
|
|
3265
3442
|
{
|
|
3266
3443
|
className: "gantt-dependencies-svg",
|
|
3444
|
+
"data-testid": "dependency-lines-svg",
|
|
3267
3445
|
width: gridWidth,
|
|
3268
3446
|
height: svgHeight,
|
|
3269
3447
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -4238,7 +4416,7 @@ var DepChip = ({
|
|
|
4238
4416
|
const predecessor = taskById.get(dep.taskId);
|
|
4239
4417
|
if (!predecessor) return;
|
|
4240
4418
|
const predStart = parseUTCDate(predecessor.startDate);
|
|
4241
|
-
const predEnd = parseUTCDate(predecessor.endDate);
|
|
4419
|
+
const predEnd = predecessor.type === "milestone" ? predStart : parseUTCDate(predecessor.endDate);
|
|
4242
4420
|
const origStart = parseUTCDate(task.startDate);
|
|
4243
4421
|
const origEnd = parseUTCDate(task.endDate);
|
|
4244
4422
|
const durationMs = origEnd.getTime() - origStart.getTime();
|
|
@@ -4489,7 +4667,8 @@ var TaskListRow = import_react10.default.memo(
|
|
|
4489
4667
|
canDemoteTask = true,
|
|
4490
4668
|
isLastChild = true,
|
|
4491
4669
|
nestingDepth = 0,
|
|
4492
|
-
|
|
4670
|
+
hasVisibleChildren = false,
|
|
4671
|
+
ancestorLineModes = [],
|
|
4493
4672
|
customDays,
|
|
4494
4673
|
isWeekend: isWeekend3,
|
|
4495
4674
|
businessDays,
|
|
@@ -4501,10 +4680,12 @@ var TaskListRow = import_react10.default.memo(
|
|
|
4501
4680
|
const editingName = editingColumnId === "name";
|
|
4502
4681
|
const editingDuration = editingColumnId === "duration";
|
|
4503
4682
|
const editingProgress = editingColumnId === "progress";
|
|
4683
|
+
const normalizedTask = (0, import_react10.useMemo)(() => normalizeTaskDatesForType(task), [task]);
|
|
4684
|
+
const isMilestone = (0, import_react10.useMemo)(() => isMilestoneTask(normalizedTask), [normalizedTask]);
|
|
4504
4685
|
const [nameValue, setNameValue] = (0, import_react10.useState)("");
|
|
4505
4686
|
const nameInputRef = (0, import_react10.useRef)(null);
|
|
4506
4687
|
const [durationValue, setDurationValue] = (0, import_react10.useState)(
|
|
4507
|
-
() => getInclusiveDurationDays(
|
|
4688
|
+
() => getInclusiveDurationDays(normalizedTask.startDate, normalizedTask.endDate)
|
|
4508
4689
|
);
|
|
4509
4690
|
const durationInputRef = (0, import_react10.useRef)(null);
|
|
4510
4691
|
const dependencySearchInputRef = (0, import_react10.useRef)(null);
|
|
@@ -4544,6 +4725,9 @@ var TaskListRow = import_react10.default.memo(
|
|
|
4544
4725
|
[businessDays, weekendPredicate]
|
|
4545
4726
|
);
|
|
4546
4727
|
const isCollapsed = collapsedParentIds.has(task.id);
|
|
4728
|
+
const getHierarchyLineColor = (0, import_react10.useCallback)((columnDepth) => {
|
|
4729
|
+
return columnDepth % 2 === 0 ? "var(--gantt-hierarchy-line-color)" : "#93c5fd";
|
|
4730
|
+
}, []);
|
|
4547
4731
|
const isPicking = selectingPredecessorFor != null;
|
|
4548
4732
|
const isSourceRow = isPicking && selectingPredecessorFor === task.id;
|
|
4549
4733
|
const [dependencySearchQuery, setDependencySearchQuery] = (0, import_react10.useState)("");
|
|
@@ -4705,14 +4889,14 @@ var TaskListRow = import_react10.default.memo(
|
|
|
4705
4889
|
e.stopPropagation();
|
|
4706
4890
|
durationConfirmedRef.current = false;
|
|
4707
4891
|
setDurationValue(
|
|
4708
|
-
getDuration(
|
|
4892
|
+
isMilestone ? 0 : getDuration(normalizedTask.startDate, normalizedTask.endDate)
|
|
4709
4893
|
);
|
|
4710
4894
|
setEditingColumnId("duration");
|
|
4711
4895
|
},
|
|
4712
|
-
[task.locked,
|
|
4896
|
+
[task.locked, normalizedTask.startDate, normalizedTask.endDate, getDuration, isMilestone]
|
|
4713
4897
|
);
|
|
4714
4898
|
const applyDurationChange = (0, import_react10.useCallback)((nextDuration) => {
|
|
4715
|
-
const normalizedDuration = Math.max(
|
|
4899
|
+
const normalizedDuration = Math.max(0, Math.round(nextDuration) || 0);
|
|
4716
4900
|
setDurationValue(normalizedDuration);
|
|
4717
4901
|
}, []);
|
|
4718
4902
|
const handleDurationSave = (0, import_react10.useCallback)(() => {
|
|
@@ -4720,19 +4904,26 @@ var TaskListRow = import_react10.default.memo(
|
|
|
4720
4904
|
durationConfirmedRef.current = false;
|
|
4721
4905
|
return;
|
|
4722
4906
|
}
|
|
4723
|
-
const
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
...task,
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4907
|
+
const rounded = Math.round(durationValue) || 0;
|
|
4908
|
+
if (isMilestone && rounded > 0) {
|
|
4909
|
+
onTasksChange?.([
|
|
4910
|
+
{ ...task, type: "task", endDate: getEndDate(task.startDate, rounded) }
|
|
4911
|
+
]);
|
|
4912
|
+
} else if (!isMilestone && rounded === 0) {
|
|
4913
|
+
onTasksChange?.([
|
|
4914
|
+
{ ...task, type: "milestone", endDate: task.startDate }
|
|
4915
|
+
]);
|
|
4916
|
+
} else if (!isMilestone && rounded > 0) {
|
|
4917
|
+
onTasksChange?.([
|
|
4918
|
+
{ ...task, endDate: getEndDate(task.startDate, rounded) }
|
|
4919
|
+
]);
|
|
4920
|
+
}
|
|
4730
4921
|
setEditingColumnId(null);
|
|
4731
|
-
}, [durationValue, task, onTasksChange, getEndDate]);
|
|
4922
|
+
}, [durationValue, task, onTasksChange, getEndDate, isMilestone]);
|
|
4732
4923
|
const handleDurationCancel = (0, import_react10.useCallback)(() => {
|
|
4733
|
-
setDurationValue(getDuration(
|
|
4924
|
+
setDurationValue(isMilestone ? 0 : getDuration(normalizedTask.startDate, normalizedTask.endDate));
|
|
4734
4925
|
setEditingColumnId(null);
|
|
4735
|
-
}, [
|
|
4926
|
+
}, [normalizedTask.startDate, normalizedTask.endDate, getDuration, isMilestone]);
|
|
4736
4927
|
const handleDurationAdjust = (0, import_react10.useCallback)(
|
|
4737
4928
|
(delta) => {
|
|
4738
4929
|
applyDurationChange(durationValue + delta);
|
|
@@ -4744,25 +4935,26 @@ var TaskListRow = import_react10.default.memo(
|
|
|
4744
4935
|
e.stopPropagation();
|
|
4745
4936
|
if (e.key === "Enter") {
|
|
4746
4937
|
durationConfirmedRef.current = true;
|
|
4747
|
-
const
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
endDate:
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4938
|
+
const rounded = Math.round(durationValue) || 0;
|
|
4939
|
+
if (isMilestone && rounded > 0) {
|
|
4940
|
+
onTasksChange?.([
|
|
4941
|
+
{ ...task, type: "task", endDate: getEndDate(task.startDate, rounded) }
|
|
4942
|
+
]);
|
|
4943
|
+
} else if (!isMilestone && rounded === 0) {
|
|
4944
|
+
onTasksChange?.([
|
|
4945
|
+
{ ...task, type: "milestone", endDate: task.startDate }
|
|
4946
|
+
]);
|
|
4947
|
+
} else if (!isMilestone && rounded > 0) {
|
|
4948
|
+
onTasksChange?.([
|
|
4949
|
+
{ ...task, endDate: getEndDate(task.startDate, rounded) }
|
|
4950
|
+
]);
|
|
4951
|
+
}
|
|
4760
4952
|
setEditingColumnId(null);
|
|
4761
4953
|
} else if (e.key === "Escape") {
|
|
4762
4954
|
handleDurationCancel();
|
|
4763
4955
|
}
|
|
4764
4956
|
},
|
|
4765
|
-
[durationValue, task, onTasksChange, handleDurationCancel, getEndDate]
|
|
4957
|
+
[durationValue, task, onTasksChange, handleDurationCancel, getEndDate, isMilestone]
|
|
4766
4958
|
);
|
|
4767
4959
|
const handleProgressClick = (0, import_react10.useCallback)(
|
|
4768
4960
|
(e) => {
|
|
@@ -4833,17 +5025,54 @@ var TaskListRow = import_react10.default.memo(
|
|
|
4833
5025
|
}
|
|
4834
5026
|
}, [editingProgress]);
|
|
4835
5027
|
(0, import_react10.useEffect)(() => {
|
|
4836
|
-
setDurationValue(getDuration(
|
|
4837
|
-
}, [
|
|
5028
|
+
setDurationValue(getDuration(normalizedTask.startDate, normalizedTask.endDate));
|
|
5029
|
+
}, [normalizedTask.startDate, normalizedTask.endDate, getDuration]);
|
|
4838
5030
|
(0, import_react10.useEffect)(() => {
|
|
4839
5031
|
if (editingDuration && durationInputRef.current) {
|
|
4840
5032
|
durationInputRef.current.focus();
|
|
4841
5033
|
durationInputRef.current.select();
|
|
4842
5034
|
}
|
|
4843
5035
|
}, [editingDuration]);
|
|
5036
|
+
const emitMilestoneDateChange = (0, import_react10.useCallback)((nextDateISO) => {
|
|
5037
|
+
const alignedDate = businessDays ? alignToWorkingDay(/* @__PURE__ */ new Date(`${nextDateISO}T00:00:00.000Z`), 1, weekendPredicate) : /* @__PURE__ */ new Date(`${nextDateISO}T00:00:00.000Z`);
|
|
5038
|
+
const clampedRange = clampTaskRangeForIncomingFS(
|
|
5039
|
+
task,
|
|
5040
|
+
alignedDate,
|
|
5041
|
+
alignedDate,
|
|
5042
|
+
allTasks,
|
|
5043
|
+
businessDays,
|
|
5044
|
+
weekendPredicate
|
|
5045
|
+
);
|
|
5046
|
+
const normalized = normalizeTaskDatesForType({
|
|
5047
|
+
...task,
|
|
5048
|
+
startDate: clampedRange.start.toISOString().split("T")[0],
|
|
5049
|
+
endDate: clampedRange.end.toISOString().split("T")[0]
|
|
5050
|
+
});
|
|
5051
|
+
const startDate = parseUTCDate(normalized.startDate);
|
|
5052
|
+
const endDate = parseUTCDate(normalized.endDate);
|
|
5053
|
+
onTasksChange?.([
|
|
5054
|
+
{
|
|
5055
|
+
...normalized,
|
|
5056
|
+
...task.dependencies && {
|
|
5057
|
+
dependencies: recalculateIncomingLags(
|
|
5058
|
+
task,
|
|
5059
|
+
startDate,
|
|
5060
|
+
endDate,
|
|
5061
|
+
allTasks,
|
|
5062
|
+
businessDays,
|
|
5063
|
+
weekendPredicate
|
|
5064
|
+
)
|
|
5065
|
+
}
|
|
5066
|
+
}
|
|
5067
|
+
]);
|
|
5068
|
+
}, [task, onTasksChange, allTasks, businessDays, weekendPredicate]);
|
|
4844
5069
|
const handleStartDateChange = (0, import_react10.useCallback)(
|
|
4845
5070
|
(newDateISO) => {
|
|
4846
5071
|
if (!newDateISO) return;
|
|
5072
|
+
if (isMilestone) {
|
|
5073
|
+
emitMilestoneDateChange(newDateISO);
|
|
5074
|
+
return;
|
|
5075
|
+
}
|
|
4847
5076
|
let nextEndISO;
|
|
4848
5077
|
const normalizedInputStart = businessDays ? alignToWorkingDay(/* @__PURE__ */ new Date(`${newDateISO}T00:00:00.000Z`), 1, weekendPredicate) : /* @__PURE__ */ new Date(`${newDateISO}T00:00:00.000Z`);
|
|
4849
5078
|
if (businessDays) {
|
|
@@ -4890,11 +5119,15 @@ var TaskListRow = import_react10.default.memo(
|
|
|
4890
5119
|
}
|
|
4891
5120
|
]);
|
|
4892
5121
|
},
|
|
4893
|
-
[task, onTasksChange, businessDays, getDuration, getEndDate, allTasks, weekendPredicate]
|
|
5122
|
+
[task, onTasksChange, businessDays, getDuration, getEndDate, allTasks, weekendPredicate, isMilestone, emitMilestoneDateChange]
|
|
4894
5123
|
);
|
|
4895
5124
|
const handleEndDateChange = (0, import_react10.useCallback)(
|
|
4896
5125
|
(newDateISO) => {
|
|
4897
5126
|
if (!newDateISO) return;
|
|
5127
|
+
if (isMilestone) {
|
|
5128
|
+
emitMilestoneDateChange(newDateISO);
|
|
5129
|
+
return;
|
|
5130
|
+
}
|
|
4898
5131
|
let nextStartISO;
|
|
4899
5132
|
const normalizedInputEnd = businessDays ? alignToWorkingDay(/* @__PURE__ */ new Date(`${newDateISO}T00:00:00.000Z`), -1, weekendPredicate) : /* @__PURE__ */ new Date(`${newDateISO}T00:00:00.000Z`);
|
|
4900
5133
|
if (businessDays) {
|
|
@@ -4941,7 +5174,7 @@ var TaskListRow = import_react10.default.memo(
|
|
|
4941
5174
|
}
|
|
4942
5175
|
]);
|
|
4943
5176
|
},
|
|
4944
|
-
[task, onTasksChange, businessDays, getDuration, weekendPredicate, allTasks]
|
|
5177
|
+
[task, onTasksChange, businessDays, getDuration, weekendPredicate, allTasks, isMilestone, emitMilestoneDateChange]
|
|
4945
5178
|
);
|
|
4946
5179
|
const handleRowClickInternal = (0, import_react10.useCallback)(() => {
|
|
4947
5180
|
onRowClick?.(task.id);
|
|
@@ -5212,8 +5445,8 @@ var TaskListRow = import_react10.default.memo(
|
|
|
5212
5445
|
},
|
|
5213
5446
|
[selectedChip?.successorId, selectedChip?.predecessorId, selectedChip?.linkType, onRemoveDependency, onChipSelect]
|
|
5214
5447
|
);
|
|
5215
|
-
const startDateISO = toISODate(
|
|
5216
|
-
const endDateISO = editingDuration ? getEndDate(
|
|
5448
|
+
const startDateISO = toISODate(normalizedTask.startDate);
|
|
5449
|
+
const endDateISO = editingDuration ? getEndDate(normalizedTask.startDate, durationValue) : toISODate(normalizedTask.endDate);
|
|
5217
5450
|
const numberCell = /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
5218
5451
|
"div",
|
|
5219
5452
|
{
|
|
@@ -5243,23 +5476,41 @@ var TaskListRow = import_react10.default.memo(
|
|
|
5243
5476
|
const nameCell = /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "gantt-tl-cell gantt-tl-cell-name", children: [
|
|
5244
5477
|
isChild && !editingName && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
|
|
5245
5478
|
!isFilterHideMode && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
|
|
5246
|
-
|
|
5247
|
-
(
|
|
5248
|
-
|
|
5249
|
-
|
|
5250
|
-
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
5254
|
-
|
|
5255
|
-
|
|
5256
|
-
|
|
5257
|
-
|
|
5258
|
-
|
|
5479
|
+
ancestorLineModes.map(
|
|
5480
|
+
(mode, idx) => mode ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react10.default.Fragment, { children: [
|
|
5481
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
5482
|
+
"span",
|
|
5483
|
+
{
|
|
5484
|
+
"data-testid": `gantt-tl-ancestor-connector-${idx}`,
|
|
5485
|
+
style: {
|
|
5486
|
+
position: "absolute",
|
|
5487
|
+
left: `${idx * 20 + 9}px`,
|
|
5488
|
+
top: 0,
|
|
5489
|
+
height: mode === "half" ? `${rowHeight / 2}px` : `${rowHeight}px`,
|
|
5490
|
+
width: "1.5px",
|
|
5491
|
+
background: getHierarchyLineColor(idx),
|
|
5492
|
+
borderRadius: "1px",
|
|
5493
|
+
pointerEvents: "none"
|
|
5494
|
+
}
|
|
5259
5495
|
}
|
|
5260
|
-
|
|
5261
|
-
|
|
5262
|
-
|
|
5496
|
+
),
|
|
5497
|
+
mode === "half" && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
5498
|
+
"span",
|
|
5499
|
+
{
|
|
5500
|
+
"data-testid": `gantt-tl-ancestor-connector-cap-${idx}`,
|
|
5501
|
+
style: {
|
|
5502
|
+
position: "absolute",
|
|
5503
|
+
left: `${idx * 20 + 9}px`,
|
|
5504
|
+
top: `${rowHeight / 2 - 0.75}px`,
|
|
5505
|
+
width: "5px",
|
|
5506
|
+
height: "1.5px",
|
|
5507
|
+
background: getHierarchyLineColor(idx),
|
|
5508
|
+
borderRadius: "1px",
|
|
5509
|
+
pointerEvents: "none"
|
|
5510
|
+
}
|
|
5511
|
+
}
|
|
5512
|
+
)
|
|
5513
|
+
] }, idx) : null
|
|
5263
5514
|
),
|
|
5264
5515
|
nestingDepth > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
5265
5516
|
"span",
|
|
@@ -5269,9 +5520,9 @@ var TaskListRow = import_react10.default.memo(
|
|
|
5269
5520
|
position: "absolute",
|
|
5270
5521
|
left: `${(nestingDepth - 1) * 20 + 9}px`,
|
|
5271
5522
|
top: 0,
|
|
5272
|
-
height: isLastChild ? `${rowHeight / 2}px` : `${rowHeight}px`,
|
|
5523
|
+
height: isLastChild && !hasVisibleChildren ? `${rowHeight / 2}px` : `${rowHeight}px`,
|
|
5273
5524
|
width: "1.5px",
|
|
5274
|
-
background:
|
|
5525
|
+
background: getHierarchyLineColor(nestingDepth - 1),
|
|
5275
5526
|
borderRadius: "1px",
|
|
5276
5527
|
pointerEvents: "none"
|
|
5277
5528
|
}
|
|
@@ -5286,7 +5537,7 @@ var TaskListRow = import_react10.default.memo(
|
|
|
5286
5537
|
top: `${rowHeight / 2 - 0.75}px`,
|
|
5287
5538
|
width: "8px",
|
|
5288
5539
|
height: "1.5px",
|
|
5289
|
-
background:
|
|
5540
|
+
background: getHierarchyLineColor(nestingDepth - 1),
|
|
5290
5541
|
borderRadius: "1px",
|
|
5291
5542
|
pointerEvents: "none"
|
|
5292
5543
|
}
|
|
@@ -5302,7 +5553,7 @@ var TaskListRow = import_react10.default.memo(
|
|
|
5302
5553
|
width: "4px",
|
|
5303
5554
|
height: "4px",
|
|
5304
5555
|
borderRadius: "50%",
|
|
5305
|
-
background:
|
|
5556
|
+
background: getHierarchyLineColor(nestingDepth - 1),
|
|
5306
5557
|
pointerEvents: "none"
|
|
5307
5558
|
}
|
|
5308
5559
|
}
|
|
@@ -5318,7 +5569,7 @@ var TaskListRow = import_react10.default.memo(
|
|
|
5318
5569
|
top: `${rowHeight / 2 + 7}px`,
|
|
5319
5570
|
height: `${rowHeight / 2 - 7}px`,
|
|
5320
5571
|
width: "1.5px",
|
|
5321
|
-
background:
|
|
5572
|
+
background: getHierarchyLineColor(nestingDepth),
|
|
5322
5573
|
borderRadius: "1px",
|
|
5323
5574
|
pointerEvents: "none"
|
|
5324
5575
|
}
|
|
@@ -5348,7 +5599,7 @@ var TaskListRow = import_react10.default.memo(
|
|
|
5348
5599
|
top: `${rowHeight / 2 + 7}px`,
|
|
5349
5600
|
height: `${rowHeight / 2 - 7}px`,
|
|
5350
5601
|
width: "1.5px",
|
|
5351
|
-
background:
|
|
5602
|
+
background: getHierarchyLineColor(nestingDepth),
|
|
5352
5603
|
borderRadius: "1px",
|
|
5353
5604
|
pointerEvents: "none"
|
|
5354
5605
|
}
|
|
@@ -5619,10 +5870,10 @@ var TaskListRow = import_react10.default.memo(
|
|
|
5619
5870
|
{
|
|
5620
5871
|
ref: durationInputRef,
|
|
5621
5872
|
type: "number",
|
|
5622
|
-
min:
|
|
5873
|
+
min: 0,
|
|
5623
5874
|
step: 1,
|
|
5624
5875
|
value: durationValue,
|
|
5625
|
-
onChange: (e) => applyDurationChange(parseInt(e.target.value, 10) ||
|
|
5876
|
+
onChange: (e) => applyDurationChange(parseInt(e.target.value, 10) || 0),
|
|
5626
5877
|
onBlur: handleDurationSave,
|
|
5627
5878
|
onKeyDown: handleDurationKeyDown,
|
|
5628
5879
|
className: "gantt-tl-number-input"
|
|
@@ -5683,14 +5934,11 @@ var TaskListRow = import_react10.default.memo(
|
|
|
5683
5934
|
]
|
|
5684
5935
|
}
|
|
5685
5936
|
),
|
|
5686
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.
|
|
5937
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
5687
5938
|
"span",
|
|
5688
5939
|
{
|
|
5689
5940
|
style: editingDuration ? { visibility: "hidden", pointerEvents: "none" } : void 0,
|
|
5690
|
-
children:
|
|
5691
|
-
getDuration(task.startDate, task.endDate),
|
|
5692
|
-
"\u0434"
|
|
5693
|
-
]
|
|
5941
|
+
children: isMilestone ? "\u25C6" : `${getDuration(normalizedTask.startDate, normalizedTask.endDate)}\u0434`
|
|
5694
5942
|
}
|
|
5695
5943
|
)
|
|
5696
5944
|
]
|
|
@@ -6338,20 +6586,41 @@ var TaskList = ({
|
|
|
6338
6586
|
}
|
|
6339
6587
|
return last;
|
|
6340
6588
|
}, [visibleTasks]);
|
|
6341
|
-
const
|
|
6589
|
+
const visibleParentIds = (0, import_react12.useMemo)(() => {
|
|
6590
|
+
const parentIds = /* @__PURE__ */ new Set();
|
|
6591
|
+
for (const task of visibleTasks) {
|
|
6592
|
+
if (task.parentId) parentIds.add(task.parentId);
|
|
6593
|
+
}
|
|
6594
|
+
return parentIds;
|
|
6595
|
+
}, [visibleTasks]);
|
|
6596
|
+
const ancestorLineModesMap = (0, import_react12.useMemo)(() => {
|
|
6342
6597
|
const taskById = new Map(tasks.map((t) => [t.id, t]));
|
|
6598
|
+
const isDescendantOf = (taskId, ancestorId) => {
|
|
6599
|
+
let current = taskById.get(taskId);
|
|
6600
|
+
while (current?.parentId && taskById.has(current.parentId)) {
|
|
6601
|
+
if (current.parentId === ancestorId) return true;
|
|
6602
|
+
current = taskById.get(current.parentId);
|
|
6603
|
+
}
|
|
6604
|
+
return false;
|
|
6605
|
+
};
|
|
6343
6606
|
const map = /* @__PURE__ */ new Map();
|
|
6344
|
-
for (
|
|
6345
|
-
const
|
|
6607
|
+
for (let index = 0; index < visibleTasks.length; index++) {
|
|
6608
|
+
const task = visibleTasks[index];
|
|
6609
|
+
const ancestorIds = [];
|
|
6346
6610
|
let current = taskById.get(task.id);
|
|
6347
6611
|
while (current?.parentId && taskById.has(current.parentId)) {
|
|
6348
|
-
|
|
6612
|
+
ancestorIds.unshift(current.parentId);
|
|
6349
6613
|
current = taskById.get(current.parentId);
|
|
6350
6614
|
}
|
|
6351
|
-
|
|
6615
|
+
const ancestorsAboveParent = ancestorIds.slice(0, -1);
|
|
6616
|
+
const modes = ancestorsAboveParent.map((ancestorId) => {
|
|
6617
|
+
const hasLaterVisibleDescendant = visibleTasks.slice(index + 1).some((laterTask) => isDescendantOf(laterTask.id, ancestorId));
|
|
6618
|
+
return hasLaterVisibleDescendant ? "full" : "half";
|
|
6619
|
+
});
|
|
6620
|
+
map.set(task.id, modes);
|
|
6352
6621
|
}
|
|
6353
6622
|
return map;
|
|
6354
|
-
}, [tasks, visibleTasks
|
|
6623
|
+
}, [tasks, visibleTasks]);
|
|
6355
6624
|
const handleRowClick = (0, import_react12.useCallback)((taskId) => {
|
|
6356
6625
|
onTaskSelect?.(taskId);
|
|
6357
6626
|
}, [onTaskSelect]);
|
|
@@ -6896,7 +7165,8 @@ var TaskList = ({
|
|
|
6896
7165
|
canDemoteTask,
|
|
6897
7166
|
isLastChild: lastChildIds.has(task.id),
|
|
6898
7167
|
nestingDepth: nestingDepthMap.get(task.id) ?? 0,
|
|
6899
|
-
|
|
7168
|
+
hasVisibleChildren: visibleParentIds.has(task.id),
|
|
7169
|
+
ancestorLineModes: ancestorLineModesMap.get(task.id) ?? [],
|
|
6900
7170
|
customDays,
|
|
6901
7171
|
isWeekend: isWeekend3,
|
|
6902
7172
|
businessDays,
|
|
@@ -7635,6 +7905,8 @@ var nameContains = (substring, caseSensitive = false) => (task) => {
|
|
|
7635
7905
|
calculateDependencyPath,
|
|
7636
7906
|
calculateGridLines,
|
|
7637
7907
|
calculateGridWidth,
|
|
7908
|
+
calculateMilestoneConnectionBounds,
|
|
7909
|
+
calculateMilestoneGeometry,
|
|
7638
7910
|
calculateMonthGridLines,
|
|
7639
7911
|
calculateOrthogonalPath,
|
|
7640
7912
|
calculateSuccessorDate,
|
|
@@ -7686,6 +7958,7 @@ var nameContains = (substring, caseSensitive = false) => (task) => {
|
|
|
7686
7958
|
nameContains,
|
|
7687
7959
|
normalizeDependencyLag,
|
|
7688
7960
|
normalizeHierarchyTasks,
|
|
7961
|
+
normalizePredecessorDates,
|
|
7689
7962
|
normalizeTaskDates,
|
|
7690
7963
|
normalizeUTCDate,
|
|
7691
7964
|
not,
|
|
@@ -7701,6 +7974,7 @@ var nameContains = (substring, caseSensitive = false) => (task) => {
|
|
|
7701
7974
|
removeDependenciesBetweenTasks,
|
|
7702
7975
|
resizeTaskWithCascade,
|
|
7703
7976
|
resolveDateRangeFromPixels,
|
|
7977
|
+
resolveTaskHorizontalGeometry,
|
|
7704
7978
|
shiftBusinessDayOffset,
|
|
7705
7979
|
subtractBusinessDays,
|
|
7706
7980
|
universalCascade,
|