gantt-lib 0.135.9 → 0.136.1
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/README.md +22 -0
- package/dist/core/scheduling/index.d.mts +1 -1
- package/dist/core/scheduling/index.d.ts +1 -1
- package/dist/{index-DR8Q6-de.d.mts → index-D99kbU4p.d.mts} +5 -0
- package/dist/{index-DR8Q6-de.d.ts → index-D99kbU4p.d.ts} +5 -0
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +19 -2
- package/dist/index.d.ts +19 -2
- package/dist/index.js +469 -119
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +665 -315
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +228 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3306,6 +3306,7 @@ var TimeScaleHeader_default = TimeScaleHeader;
|
|
|
3306
3306
|
|
|
3307
3307
|
// src/components/TaskRow/TaskRow.tsx
|
|
3308
3308
|
var import_react3 = __toESM(require("react"));
|
|
3309
|
+
var import_react_dom = require("react-dom");
|
|
3309
3310
|
|
|
3310
3311
|
// src/utils/geometry.ts
|
|
3311
3312
|
var getUTCDayDifference = (date1, date2) => {
|
|
@@ -4413,12 +4414,36 @@ var useTaskDrag = (options) => {
|
|
|
4413
4414
|
|
|
4414
4415
|
// src/components/TaskRow/TaskRow.tsx
|
|
4415
4416
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
4417
|
+
var COMPOSITE_SEGMENT_CUT_MIN_PX = 10;
|
|
4418
|
+
var formatCompositePreviewDate = (date) => {
|
|
4419
|
+
const month = new Intl.DateTimeFormat("ru-RU", { month: "short", timeZone: "UTC" }).format(date).replace(/\.$/, "");
|
|
4420
|
+
const yearSuffix = date.getUTCFullYear() === (/* @__PURE__ */ new Date()).getFullYear() ? "" : ` ${String(date.getUTCFullYear()).slice(-2)}`;
|
|
4421
|
+
return `${date.getUTCDate()} ${month}${yearSuffix}`;
|
|
4422
|
+
};
|
|
4416
4423
|
var arePropsEqual = (prevProps, nextProps) => {
|
|
4417
|
-
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.baselineStartDate === nextProps.task.baselineStartDate && prevProps.task.baselineEndDate === nextProps.task.baselineEndDate && 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.previewPositionStore === nextProps.previewPositionStore && prevProps.allTasks === nextProps.allTasks && prevProps.disableConstraints === nextProps.disableConstraints && prevProps.deferCascadePreview === nextProps.deferCascadePreview && prevProps.task.locked === nextProps.task.locked && prevProps.task.synced === nextProps.task.synced && prevProps.task.divider === nextProps.task.divider && prevProps.highlightExpiredTasks === nextProps.highlightExpiredTasks && prevProps.isCritical === nextProps.isCritical && prevProps.showBaseline === nextProps.showBaseline && prevProps.isFilterMatch === nextProps.isFilterMatch && prevProps.businessDays === nextProps.businessDays && prevProps.customDays === nextProps.customDays && prevProps.isWeekend === nextProps.isWeekend && prevProps.disableTaskDrag === nextProps.disableTaskDrag && prevProps.disableDependencyEditing === nextProps.disableDependencyEditing && prevProps.isDependencyDragActive === nextProps.isDependencyDragActive && prevProps.viewMode === nextProps.viewMode && prevProps.showTaskDateLabels === nextProps.showTaskDateLabels && prevProps.showTaskNames === nextProps.showTaskNames;
|
|
4424
|
+
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.baselineStartDate === nextProps.task.baselineStartDate && prevProps.task.baselineEndDate === nextProps.task.baselineEndDate && 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.previewPositionStore === nextProps.previewPositionStore && prevProps.allTasks === nextProps.allTasks && prevProps.disableConstraints === nextProps.disableConstraints && prevProps.deferCascadePreview === nextProps.deferCascadePreview && prevProps.task.locked === nextProps.task.locked && prevProps.task.synced === nextProps.task.synced && prevProps.task.divider === nextProps.task.divider && prevProps.highlightExpiredTasks === nextProps.highlightExpiredTasks && prevProps.isCritical === nextProps.isCritical && prevProps.showBaseline === nextProps.showBaseline && prevProps.onCompositeToggle === nextProps.onCompositeToggle && prevProps.compactDetail === nextProps.compactDetail && prevProps.compositeParentColor === nextProps.compositeParentColor && prevProps.compositeExpanded === nextProps.compositeExpanded && prevProps.isFilterMatch === nextProps.isFilterMatch && prevProps.businessDays === nextProps.businessDays && prevProps.customDays === nextProps.customDays && prevProps.isWeekend === nextProps.isWeekend && prevProps.disableTaskDrag === nextProps.disableTaskDrag && prevProps.disableDependencyEditing === nextProps.disableDependencyEditing && prevProps.isDependencyDragActive === nextProps.isDependencyDragActive && prevProps.viewMode === nextProps.viewMode && prevProps.showTaskDateLabels === nextProps.showTaskDateLabels && prevProps.showTaskNames === nextProps.showTaskNames && prevProps.showCompositeSegments === nextProps.showCompositeSegments;
|
|
4418
4425
|
};
|
|
4419
4426
|
var TaskRow = import_react3.default.memo(
|
|
4420
|
-
({ task, monthStart, dayWidth, rowHeight, onTasksChange, onScheduleIntent, onDragStateChange, rowIndex, allTasks, enableAutoSchedule, disableConstraints, deferCascadePreview = false, overridePosition, previewPositionStore, onCascadeProgress, onCascade, divider, highlightExpiredTasks, isCritical = false, showBaseline = false, isFilterMatch = false, businessDays, customDays, isWeekend: isWeekend3, disableTaskDrag = false, disableDependencyEditing = false, onDependencyPortPointerDown, isDependencyDragActive = false, viewMode = "day", showTaskDateLabels = true, showTaskNames = true }) => {
|
|
4427
|
+
({ task, monthStart, dayWidth, rowHeight, onTasksChange, onScheduleIntent, onDragStateChange, rowIndex, allTasks, enableAutoSchedule, disableConstraints, deferCascadePreview = false, overridePosition, previewPositionStore, onCascadeProgress, onCascade, divider, highlightExpiredTasks, isCritical = false, showBaseline = false, isFilterMatch = false, businessDays, customDays, isWeekend: isWeekend3, disableTaskDrag = false, disableDependencyEditing = false, onDependencyPortPointerDown, isDependencyDragActive = false, viewMode = "day", showTaskDateLabels = true, showTaskNames = true, showCompositeSegments: showCompositeSegmentsProp = true, onCompositeToggle, compactDetail = false, compositeParentColor, compositeExpanded = false }) => {
|
|
4421
4428
|
const defaultParentBarColor = "#782FC4";
|
|
4429
|
+
const [showCompositePreview, setShowCompositePreview] = (0, import_react3.useState)(false);
|
|
4430
|
+
const [compositePreviewPosition, setCompositePreviewPosition] = (0, import_react3.useState)(null);
|
|
4431
|
+
const pointerStart = (0, import_react3.useRef)(null);
|
|
4432
|
+
const suppressCompositeClick = (0, import_react3.useRef)(false);
|
|
4433
|
+
const compositeChildren = (0, import_react3.useMemo)(
|
|
4434
|
+
() => task.composite ? (allTasks ?? []).filter((child) => child.parentId === task.id) : [],
|
|
4435
|
+
[allTasks, task.composite, task.id]
|
|
4436
|
+
);
|
|
4437
|
+
(0, import_react3.useEffect)(() => {
|
|
4438
|
+
if (!showCompositePreview) return;
|
|
4439
|
+
const hide = () => setShowCompositePreview(false);
|
|
4440
|
+
window.addEventListener("scroll", hide, true);
|
|
4441
|
+
window.addEventListener("resize", hide);
|
|
4442
|
+
return () => {
|
|
4443
|
+
window.removeEventListener("scroll", hide, true);
|
|
4444
|
+
window.removeEventListener("resize", hide);
|
|
4445
|
+
};
|
|
4446
|
+
}, [showCompositePreview]);
|
|
4422
4447
|
const { divider: taskDivider } = task;
|
|
4423
4448
|
const normalizedTask = (0, import_react3.useMemo)(() => normalizeTaskDatesForType(task), [task]);
|
|
4424
4449
|
const milestone = (0, import_react3.useMemo)(() => isMilestoneTask(normalizedTask), [normalizedTask]);
|
|
@@ -4435,6 +4460,7 @@ var TaskRow = import_react3.default.memo(
|
|
|
4435
4460
|
const isParent = (0, import_react3.useMemo)(() => {
|
|
4436
4461
|
return allTasks ? isTaskParent(task.id, allTasks) : false;
|
|
4437
4462
|
}, [allTasks, task.id]);
|
|
4463
|
+
const isVisualParent = isParent && !task.composite;
|
|
4438
4464
|
const childCount = (0, import_react3.useMemo)(() => {
|
|
4439
4465
|
return allTasks ? getChildren(task.id, allTasks).length : 0;
|
|
4440
4466
|
}, [allTasks, task.id]);
|
|
@@ -4480,19 +4506,19 @@ var TaskRow = import_react3.default.memo(
|
|
|
4480
4506
|
if (isExpired) {
|
|
4481
4507
|
return "color-mix(in srgb, var(--gantt-expired-color) 40%, black)";
|
|
4482
4508
|
}
|
|
4483
|
-
const baseColor =
|
|
4509
|
+
const baseColor = isVisualParent ? task.color || defaultParentBarColor : task.color || "var(--gantt-task-bar-default-color)";
|
|
4484
4510
|
return `color-mix(in srgb, ${baseColor} 40%, black)`;
|
|
4485
|
-
}, [defaultParentBarColor, isCritical, isExpired,
|
|
4511
|
+
}, [defaultParentBarColor, isCritical, isExpired, isVisualParent, task.color]);
|
|
4486
4512
|
const barStyle = (0, import_react3.useMemo)(() => {
|
|
4487
4513
|
const parentBarColor = task.color || defaultParentBarColor;
|
|
4488
4514
|
if (isCritical && !isExpired) {
|
|
4489
4515
|
const c = criticalBarColor;
|
|
4490
|
-
if (
|
|
4516
|
+
if (isVisualParent) {
|
|
4491
4517
|
return { backgroundColor: c, "--gantt-parent-bar-color": c };
|
|
4492
4518
|
}
|
|
4493
4519
|
return { backgroundColor: c };
|
|
4494
4520
|
}
|
|
4495
|
-
if (
|
|
4521
|
+
if (isVisualParent) {
|
|
4496
4522
|
if (progressWidth >= 100) {
|
|
4497
4523
|
const c = isExpired ? "color-mix(in srgb, var(--gantt-expired-color) 40%, black)" : `color-mix(in srgb, ${parentBarColor} 40%, black)`;
|
|
4498
4524
|
return { backgroundColor: c, "--gantt-parent-bar-color": c };
|
|
@@ -4503,7 +4529,7 @@ var TaskRow = import_react3.default.memo(
|
|
|
4503
4529
|
return { backgroundColor: progressColor };
|
|
4504
4530
|
}
|
|
4505
4531
|
return { backgroundColor: barColor };
|
|
4506
|
-
}, [isCritical, defaultParentBarColor, isExpired,
|
|
4532
|
+
}, [isCritical, defaultParentBarColor, isExpired, isVisualParent, progressWidth, barColor, progressColor, task.color]);
|
|
4507
4533
|
const handleDragEnd = (result) => {
|
|
4508
4534
|
const updatedTask = {
|
|
4509
4535
|
...normalizedTask,
|
|
@@ -4577,6 +4603,35 @@ var TaskRow = import_react3.default.memo(
|
|
|
4577
4603
|
}, [displayLeft, dayWidth, milestoneGeometry.size]);
|
|
4578
4604
|
const visualLeft = milestone ? displayMilestoneGeometry.left : displayLeft;
|
|
4579
4605
|
const visualWidth = milestone ? displayMilestoneGeometry.size : displayWidth;
|
|
4606
|
+
const compositeSegments = (0, import_react3.useMemo)(() => {
|
|
4607
|
+
if (!task.composite || width <= 0) return [];
|
|
4608
|
+
const laneEnds = [];
|
|
4609
|
+
const segments2 = compositeChildren.map((child) => {
|
|
4610
|
+
const segment = calculateTaskBar(parseUTCDate(child.startDate), parseUTCDate(child.endDate), monthStart, dayWidth);
|
|
4611
|
+
let lane = Math.max(0, laneEnds.length - 1);
|
|
4612
|
+
if (laneEnds.length > 0 && segment.left < laneEnds[lane]) {
|
|
4613
|
+
lane = laneEnds.length;
|
|
4614
|
+
}
|
|
4615
|
+
laneEnds[lane] = segment.left + segment.width;
|
|
4616
|
+
return {
|
|
4617
|
+
id: child.id,
|
|
4618
|
+
name: child.name,
|
|
4619
|
+
left: (segment.left - left) / width * 100,
|
|
4620
|
+
width: segment.width / width * 100,
|
|
4621
|
+
lane,
|
|
4622
|
+
pxLeft: segment.left - left,
|
|
4623
|
+
cut: false
|
|
4624
|
+
};
|
|
4625
|
+
});
|
|
4626
|
+
const lastCutByLane = [];
|
|
4627
|
+
for (const segment of [...segments2].sort((a, b) => a.pxLeft - b.pxLeft)) {
|
|
4628
|
+
segment.cut = segment.pxLeft >= 1 && segment.pxLeft - (lastCutByLane[segment.lane] ?? 0) >= COMPOSITE_SEGMENT_CUT_MIN_PX;
|
|
4629
|
+
if (segment.cut) lastCutByLane[segment.lane] = segment.pxLeft;
|
|
4630
|
+
}
|
|
4631
|
+
return segments2;
|
|
4632
|
+
}, [task.composite, compositeChildren, monthStart, dayWidth, left, width, displayLeft]);
|
|
4633
|
+
const compositeLaneCount = Math.max(1, ...compositeSegments.map((segment) => segment.lane + 1));
|
|
4634
|
+
const shouldRenderCompositeSegments = showCompositeSegmentsProp && task.composite && compositeSegments.length > 0 && visualWidth / compositeSegments.length >= 22;
|
|
4580
4635
|
const shouldRenderBaseline = showBaseline && baselineGeometry !== null;
|
|
4581
4636
|
const hasPreviewPosition = isDragging || effectiveOverridePosition !== void 0;
|
|
4582
4637
|
const currentStartDate = hasPreviewPosition ? pixelsToDate(displayLeft, monthStart, dayWidth) : taskStartDate;
|
|
@@ -4594,17 +4649,20 @@ var TaskRow = import_react3.default.memo(
|
|
|
4594
4649
|
if (lastDigit >= 2 && lastDigit <= 4) return `${count} \u0440\u0430\u0431\u043E\u0442\u044B`;
|
|
4595
4650
|
return `${count} \u0440\u0430\u0431\u043E\u0442`;
|
|
4596
4651
|
};
|
|
4597
|
-
const estimatedTextWidth =
|
|
4598
|
-
const showProgressInside = !milestone && progressWidth > 0 && displayWidth > estimatedTextWidth;
|
|
4599
|
-
const MIN_DURATION_WIDTH =
|
|
4600
|
-
const showDurationInside = !milestone && durationDays >= 2 && displayWidth > MIN_DURATION_WIDTH;
|
|
4652
|
+
const estimatedTextWidth = isVisualParent ? 120 : durationDays >= 10 ? 76 : 62;
|
|
4653
|
+
const showProgressInside = !milestone && progressWidth > 0 && displayWidth > (compactDetail ? 28 : estimatedTextWidth);
|
|
4654
|
+
const MIN_DURATION_WIDTH = isVisualParent ? 80 : task.composite ? 92 : 50;
|
|
4655
|
+
const showDurationInside = !compactDetail && !milestone && durationDays >= 2 && displayWidth > MIN_DURATION_WIDTH;
|
|
4601
4656
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
4602
4657
|
"div",
|
|
4603
4658
|
{
|
|
4604
4659
|
"data-filter-match": isFilterMatch ? "true" : "false",
|
|
4605
4660
|
"data-gantt-task-row-id": task.id,
|
|
4606
|
-
className: `gantt-tr-row ${isFilterMatch ? "gantt-tr-row-filter-match" : ""}`,
|
|
4607
|
-
style: {
|
|
4661
|
+
className: `gantt-tr-row ${compactDetail ? "gantt-tr-row-compositeDetail" : ""} ${isFilterMatch ? "gantt-tr-row-filter-match" : ""}`,
|
|
4662
|
+
style: {
|
|
4663
|
+
height: `${rowHeight}px`,
|
|
4664
|
+
"--gantt-tr-composite-detail-color": compositeParentColor ?? "var(--gantt-task-bar-default-color, #8b5cf6)"
|
|
4665
|
+
},
|
|
4608
4666
|
children: [
|
|
4609
4667
|
taskDivider === "top" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "gantt-tr-divider gantt-tr-divider-top" }),
|
|
4610
4668
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "gantt-tr-taskContainer", children: [
|
|
@@ -4622,7 +4680,11 @@ var TaskRow = import_react3.default.memo(
|
|
|
4622
4680
|
"div",
|
|
4623
4681
|
{
|
|
4624
4682
|
"data-taskbar": true,
|
|
4625
|
-
|
|
4683
|
+
role: task.composite ? "button" : void 0,
|
|
4684
|
+
tabIndex: task.composite ? 0 : void 0,
|
|
4685
|
+
"aria-label": task.composite ? `${task.name}: ${compositeExpanded ? "\u0441\u0432\u0435\u0440\u043D\u0443\u0442\u044C" : "\u0440\u0430\u0441\u043A\u0440\u044B\u0442\u044C"} \u0434\u0435\u0442\u0430\u043B\u0438` : void 0,
|
|
4686
|
+
"aria-expanded": task.composite ? compositeExpanded : void 0,
|
|
4687
|
+
className: `gantt-tr-taskBar ${isDragging ? "gantt-tr-dragging" : ""} ${task.locked ? "gantt-tr-locked" : ""} ${task.synced === false ? "gantt-tr-unsynced" : ""} ${isVisualParent ? "gantt-tr-parentBar" : ""} ${task.composite ? "gantt-tr-compositeBar" : ""} ${milestone ? "gantt-tr-milestone" : ""} ${isCritical ? "gantt-tr-critical" : ""}`,
|
|
4626
4688
|
style: {
|
|
4627
4689
|
left: `${visualLeft}px`,
|
|
4628
4690
|
...barStyle,
|
|
@@ -4632,14 +4694,57 @@ var TaskRow = import_react3.default.memo(
|
|
|
4632
4694
|
padding: 0
|
|
4633
4695
|
} : {
|
|
4634
4696
|
width: `${visualWidth}px`,
|
|
4635
|
-
height:
|
|
4697
|
+
height: compactDetail ? "18px" : isVisualParent ? "var(--gantt-parent-bar-height, 14px)" : "var(--gantt-task-bar-height)"
|
|
4636
4698
|
},
|
|
4637
4699
|
cursor: dragHandleProps.style.cursor,
|
|
4638
4700
|
userSelect: dragHandleProps.style.userSelect
|
|
4639
4701
|
},
|
|
4640
4702
|
onMouseDown: dragHandleProps.onMouseDown,
|
|
4641
4703
|
onMouseMove: dragHandleProps.onMouseMove,
|
|
4642
|
-
onMouseLeave:
|
|
4704
|
+
onMouseLeave: () => {
|
|
4705
|
+
dragHandleProps.onMouseLeave();
|
|
4706
|
+
setShowCompositePreview(false);
|
|
4707
|
+
},
|
|
4708
|
+
onMouseEnter: task.composite ? (event) => {
|
|
4709
|
+
const rect = event.currentTarget.getBoundingClientRect();
|
|
4710
|
+
const previewWidth = 220;
|
|
4711
|
+
const previewHeight = Math.min(340, 68 + Math.min(compositeChildren.length, 12) * 20);
|
|
4712
|
+
setCompositePreviewPosition({
|
|
4713
|
+
left: Math.max(8, Math.min(rect.left, window.innerWidth - previewWidth - 8)),
|
|
4714
|
+
top: rect.bottom + previewHeight + 8 < window.innerHeight ? rect.bottom + 6 : Math.max(8, rect.top - previewHeight - 6)
|
|
4715
|
+
});
|
|
4716
|
+
setShowCompositePreview(true);
|
|
4717
|
+
} : void 0,
|
|
4718
|
+
onMouseDownCapture: task.composite ? (event) => {
|
|
4719
|
+
suppressCompositeClick.current = Boolean(event.target.closest(".gantt-tr-resizeHandle"));
|
|
4720
|
+
pointerStart.current = { x: event.clientX, y: event.clientY };
|
|
4721
|
+
} : void 0,
|
|
4722
|
+
onMouseMoveCapture: task.composite ? (event) => {
|
|
4723
|
+
const start = pointerStart.current;
|
|
4724
|
+
if (start && Math.hypot(event.clientX - start.x, event.clientY - start.y) >= 4) {
|
|
4725
|
+
suppressCompositeClick.current = true;
|
|
4726
|
+
}
|
|
4727
|
+
} : void 0,
|
|
4728
|
+
onMouseUpCapture: task.composite ? (event) => {
|
|
4729
|
+
const start = pointerStart.current;
|
|
4730
|
+
if (start && Math.hypot(event.clientX - start.x, event.clientY - start.y) >= 4) {
|
|
4731
|
+
suppressCompositeClick.current = true;
|
|
4732
|
+
}
|
|
4733
|
+
pointerStart.current = null;
|
|
4734
|
+
} : void 0,
|
|
4735
|
+
onClick: task.composite ? () => {
|
|
4736
|
+
if (!isDragging && !suppressCompositeClick.current) {
|
|
4737
|
+
setShowCompositePreview(false);
|
|
4738
|
+
onCompositeToggle?.("click");
|
|
4739
|
+
}
|
|
4740
|
+
suppressCompositeClick.current = false;
|
|
4741
|
+
} : void 0,
|
|
4742
|
+
onKeyDown: task.composite ? (event) => {
|
|
4743
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
4744
|
+
event.preventDefault();
|
|
4745
|
+
onCompositeToggle?.("keyboard");
|
|
4746
|
+
}
|
|
4747
|
+
} : void 0,
|
|
4643
4748
|
children: [
|
|
4644
4749
|
!milestone && progressWidth > 0 && progressWidth < 100 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
4645
4750
|
"div",
|
|
@@ -4648,14 +4753,42 @@ var TaskRow = import_react3.default.memo(
|
|
|
4648
4753
|
style: {
|
|
4649
4754
|
width: `${progressWidth}%`,
|
|
4650
4755
|
backgroundColor: progressColor,
|
|
4651
|
-
...
|
|
4756
|
+
...isVisualParent && {
|
|
4652
4757
|
borderRadius: "var(--gantt-parent-bar-radius, 8px) 0 0 0"
|
|
4653
4758
|
}
|
|
4654
4759
|
}
|
|
4655
4760
|
}
|
|
4656
4761
|
),
|
|
4657
4762
|
!milestone && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "gantt-tr-resizeHandle gantt-tr-resizeHandleLeft" }),
|
|
4658
|
-
|
|
4763
|
+
shouldRenderCompositeSegments && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "gantt-tr-compositeSegments", "aria-hidden": "true", children: [
|
|
4764
|
+
compositeSegments.map((segment) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
4765
|
+
"span",
|
|
4766
|
+
{
|
|
4767
|
+
className: "gantt-tr-compositeSegment",
|
|
4768
|
+
style: {
|
|
4769
|
+
left: `${segment.left}%`,
|
|
4770
|
+
width: `${segment.width}%`,
|
|
4771
|
+
top: `${segment.lane / compositeLaneCount * 100}%`,
|
|
4772
|
+
height: `${100 / compositeLaneCount}%`
|
|
4773
|
+
}
|
|
4774
|
+
},
|
|
4775
|
+
segment.id
|
|
4776
|
+
)),
|
|
4777
|
+
compositeSegments.map((segment) => segment.cut ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
4778
|
+
"span",
|
|
4779
|
+
{
|
|
4780
|
+
className: "gantt-tr-compositeSegmentCut",
|
|
4781
|
+
style: {
|
|
4782
|
+
left: `${segment.left}%`,
|
|
4783
|
+
top: `${segment.lane / compositeLaneCount * 100}%`,
|
|
4784
|
+
height: `${100 / compositeLaneCount}%`
|
|
4785
|
+
}
|
|
4786
|
+
},
|
|
4787
|
+
`${segment.id}-cut`
|
|
4788
|
+
) : null)
|
|
4789
|
+
] }),
|
|
4790
|
+
task.composite && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "gantt-tr-compositeHoverChevron", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { className: `gantt-tr-compositeChevron${compositeExpanded ? " gantt-tr-compositeChevron-open" : ""}`, viewBox: "0 0 20 20", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m7 4 6 6-6 6", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }),
|
|
4791
|
+
showDurationInside && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "gantt-tr-taskDuration", children: isVisualParent ? getChildCountLabel(childCount) : `${durationDays} \u0434` }),
|
|
4659
4792
|
progressWidth > 0 && showProgressInside && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "gantt-tr-progressText", children: [
|
|
4660
4793
|
progressWidth,
|
|
4661
4794
|
"%"
|
|
@@ -4664,6 +4797,41 @@ var TaskRow = import_react3.default.memo(
|
|
|
4664
4797
|
]
|
|
4665
4798
|
}
|
|
4666
4799
|
),
|
|
4800
|
+
task.composite && showCompositePreview && compositePreviewPosition && compositeChildren.length > 0 && !isDragging && typeof document !== "undefined" && (0, import_react_dom.createPortal)(
|
|
4801
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
4802
|
+
"div",
|
|
4803
|
+
{
|
|
4804
|
+
className: "gantt-tr-compositePreview",
|
|
4805
|
+
style: { left: `${compositePreviewPosition.left}px`, top: `${compositePreviewPosition.top}px` },
|
|
4806
|
+
role: "tooltip",
|
|
4807
|
+
children: [
|
|
4808
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "gantt-tr-compositePreviewAxis", children: [
|
|
4809
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: formatCompositePreviewDate(currentStartDate) }),
|
|
4810
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: formatCompositePreviewDate(currentEndDate) })
|
|
4811
|
+
] }),
|
|
4812
|
+
compositeChildren.slice(0, 12).map((child) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "gantt-tr-compositePreviewRow", children: [
|
|
4813
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: child.name }),
|
|
4814
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "gantt-tr-compositePreviewTrack", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
4815
|
+
"span",
|
|
4816
|
+
{
|
|
4817
|
+
className: "gantt-tr-compositePreviewBar",
|
|
4818
|
+
style: {
|
|
4819
|
+
left: `${Math.max(0, (parseUTCDate(child.startDate).getTime() - taskStartDate.getTime()) / (taskEndDate.getTime() - taskStartDate.getTime() + 864e5) * 100)}%`,
|
|
4820
|
+
width: `${Math.max(2, (parseUTCDate(child.endDate).getTime() - parseUTCDate(child.startDate).getTime() + 864e5) / (taskEndDate.getTime() - taskStartDate.getTime() + 864e5) * 100)}%`,
|
|
4821
|
+
backgroundColor: barColor
|
|
4822
|
+
}
|
|
4823
|
+
}
|
|
4824
|
+
) })
|
|
4825
|
+
] }, child.id)),
|
|
4826
|
+
compositeChildren.length > 12 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
|
|
4827
|
+
"+",
|
|
4828
|
+
compositeChildren.length - 12
|
|
4829
|
+
] })
|
|
4830
|
+
]
|
|
4831
|
+
}
|
|
4832
|
+
),
|
|
4833
|
+
document.body
|
|
4834
|
+
),
|
|
4667
4835
|
!disableDependencyEditing && onDependencyPortPointerDown && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
4668
4836
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
4669
4837
|
"button",
|
|
@@ -4672,7 +4840,7 @@ var TaskRow = import_react3.default.memo(
|
|
|
4672
4840
|
"data-gantt-dependency-port": true,
|
|
4673
4841
|
"data-task-id": task.id,
|
|
4674
4842
|
"data-port-side": "left",
|
|
4675
|
-
className: `gantt-tr-dependencyPort gantt-tr-dependencyPortLeft ${milestone ? "gantt-tr-dependencyPortMilestone" : ""} ${
|
|
4843
|
+
className: `gantt-tr-dependencyPort gantt-tr-dependencyPortLeft ${milestone ? "gantt-tr-dependencyPortMilestone" : ""} ${isVisualParent ? "gantt-tr-dependencyPortParent" : ""} ${isDependencyDragActive ? "gantt-tr-dependencyPortDragActive" : ""}`,
|
|
4676
4844
|
style: { left: `${visualLeft - 24}px` },
|
|
4677
4845
|
"aria-label": `\u041D\u0430\u0447\u0430\u0442\u044C \u0441\u0432\u044F\u0437\u044C \u043E\u0442 \u043B\u0435\u0432\u043E\u0433\u043E \u043A\u0440\u0430\u044F: ${task.name}`,
|
|
4678
4846
|
title: "\u041F\u043E\u0442\u044F\u043D\u0438\u0442\u0435 \u043A \u043A\u0440\u0430\u044E \u0434\u0440\u0443\u0433\u043E\u0439 \u043F\u043E\u043B\u043E\u0441\u044B, \u0447\u0442\u043E\u0431\u044B \u0441\u043E\u0437\u0434\u0430\u0442\u044C \u0441\u0432\u044F\u0437\u044C",
|
|
@@ -4686,7 +4854,7 @@ var TaskRow = import_react3.default.memo(
|
|
|
4686
4854
|
"data-gantt-dependency-port": true,
|
|
4687
4855
|
"data-task-id": task.id,
|
|
4688
4856
|
"data-port-side": "right",
|
|
4689
|
-
className: `gantt-tr-dependencyPort gantt-tr-dependencyPortRight ${milestone ? "gantt-tr-dependencyPortMilestone" : ""} ${
|
|
4857
|
+
className: `gantt-tr-dependencyPort gantt-tr-dependencyPortRight ${milestone ? "gantt-tr-dependencyPortMilestone" : ""} ${isVisualParent ? "gantt-tr-dependencyPortParent" : ""} ${isDependencyDragActive ? "gantt-tr-dependencyPortDragActive" : ""}`,
|
|
4690
4858
|
style: { left: `${visualLeft + visualWidth}px` },
|
|
4691
4859
|
"aria-label": `\u041D\u0430\u0447\u0430\u0442\u044C \u0441\u0432\u044F\u0437\u044C \u043E\u0442 \u043F\u0440\u0430\u0432\u043E\u0433\u043E \u043A\u0440\u0430\u044F: ${task.name}`,
|
|
4692
4860
|
title: "\u041F\u043E\u0442\u044F\u043D\u0438\u0442\u0435 \u043A \u043A\u0440\u0430\u044E \u0434\u0440\u0443\u0433\u043E\u0439 \u043F\u043E\u043B\u043E\u0441\u044B, \u0447\u0442\u043E\u0431\u044B \u0441\u043E\u0437\u0434\u0430\u0442\u044C \u0441\u0432\u044F\u0437\u044C",
|
|
@@ -4725,6 +4893,14 @@ var TaskRow = import_react3.default.memo(
|
|
|
4725
4893
|
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zM12 17c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2z" })
|
|
4726
4894
|
}
|
|
4727
4895
|
),
|
|
4896
|
+
!showDurationInside && !milestone && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
4897
|
+
"span",
|
|
4898
|
+
{
|
|
4899
|
+
className: `gantt-tr-externalDuration gantt-tr-durationBeforeBar${compactDetail ? " gantt-tr-compositeDuration" : ""}`,
|
|
4900
|
+
style: { left: `${visualLeft - 46}px`, color: isParent ? task.color || defaultParentBarColor : barColor },
|
|
4901
|
+
children: isVisualParent ? getChildCountLabel(childCount) : `${durationDays} \u0434`
|
|
4902
|
+
}
|
|
4903
|
+
),
|
|
4728
4904
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
4729
4905
|
"div",
|
|
4730
4906
|
{
|
|
@@ -4734,7 +4910,6 @@ var TaskRow = import_react3.default.memo(
|
|
|
4734
4910
|
color: isParent ? task.color || defaultParentBarColor : barColor
|
|
4735
4911
|
},
|
|
4736
4912
|
children: [
|
|
4737
|
-
!showDurationInside && !milestone && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "gantt-tr-externalDuration", children: isParent ? getChildCountLabel(childCount) : `${durationDays} \u0434` }),
|
|
4738
4913
|
progressWidth > 0 && !showProgressInside && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "gantt-tr-externalProgress", children: [
|
|
4739
4914
|
progressWidth,
|
|
4740
4915
|
"%"
|
|
@@ -5038,6 +5213,8 @@ var DependencyLines = import_react7.default.memo(({
|
|
|
5038
5213
|
gridWidth,
|
|
5039
5214
|
totalHeight,
|
|
5040
5215
|
rowIndexByTaskId,
|
|
5216
|
+
rowTops,
|
|
5217
|
+
rowHeights,
|
|
5041
5218
|
dragOverrides,
|
|
5042
5219
|
selectedDep,
|
|
5043
5220
|
criticalTaskIds,
|
|
@@ -5061,7 +5238,8 @@ var DependencyLines = import_react7.default.memo(({
|
|
|
5061
5238
|
left: computed.left,
|
|
5062
5239
|
right: computed.right,
|
|
5063
5240
|
centerX: computed.centerX,
|
|
5064
|
-
rowTop: rowIndex * rowHeight,
|
|
5241
|
+
rowTop: rowTops?.[rowIndex] ?? rowIndex * rowHeight,
|
|
5242
|
+
rowHeight: rowHeights?.[rowIndex] ?? rowHeight,
|
|
5065
5243
|
isVirtual: false
|
|
5066
5244
|
});
|
|
5067
5245
|
});
|
|
@@ -5081,6 +5259,7 @@ var DependencyLines = import_react7.default.memo(({
|
|
|
5081
5259
|
right: computed.right,
|
|
5082
5260
|
centerX: computed.centerX,
|
|
5083
5261
|
rowTop: ancestorPosition.rowTop,
|
|
5262
|
+
rowHeight: ancestorPosition.rowHeight,
|
|
5084
5263
|
isVirtual: true
|
|
5085
5264
|
});
|
|
5086
5265
|
}
|
|
@@ -5094,18 +5273,19 @@ var DependencyLines = import_react7.default.memo(({
|
|
|
5094
5273
|
const override = dragOverrides?.get(task.id);
|
|
5095
5274
|
const computed = resolveTaskHorizontalGeometry(task, monthStart, dayWidth, override);
|
|
5096
5275
|
const rowIndex = rowIndexByTaskId?.get(task.id);
|
|
5097
|
-
const rowTop = rowIndex !== void 0 ? rowIndex * rowHeight : 0;
|
|
5276
|
+
const rowTop = rowIndex !== void 0 ? rowTops?.[rowIndex] ?? rowIndex * rowHeight : 0;
|
|
5098
5277
|
positions.set(task.id, {
|
|
5099
5278
|
left: computed.left,
|
|
5100
5279
|
right: computed.right,
|
|
5101
5280
|
centerX: computed.centerX,
|
|
5102
5281
|
rowTop,
|
|
5282
|
+
rowHeight: rowIndex !== void 0 ? rowHeights?.[rowIndex] ?? rowHeight : rowHeight,
|
|
5103
5283
|
isVirtual: false
|
|
5104
5284
|
});
|
|
5105
5285
|
}
|
|
5106
5286
|
}
|
|
5107
5287
|
return { taskPositions: positions, taskIndices: indices, hiddenTaskIds: hidden };
|
|
5108
|
-
}, [tasks, tasksForPositions, allTasks, collapsedParentIds, monthStart, dayWidth, rowHeight, dragOverrides, rowIndexByTaskId]);
|
|
5288
|
+
}, [tasks, tasksForPositions, allTasks, collapsedParentIds, monthStart, dayWidth, rowHeight, rowTops, rowHeights, dragOverrides, rowIndexByTaskId]);
|
|
5109
5289
|
const tasksForCycleDetection = allTasks ?? tasks;
|
|
5110
5290
|
const cycleInfo = (0, import_react7.useMemo)(() => {
|
|
5111
5291
|
const result = detectCycles(tasksForCycleDetection);
|
|
@@ -5147,7 +5327,9 @@ var DependencyLines = import_react7.default.memo(({
|
|
|
5147
5327
|
continue;
|
|
5148
5328
|
}
|
|
5149
5329
|
}
|
|
5150
|
-
|
|
5330
|
+
const predecessorVisibleId = predecessor.isVirtual ? findVisibleAncestor(taskMap.get(edge.predecessorId), collapsedParentIds, taskMap)?.id : edge.predecessorId;
|
|
5331
|
+
const successorVisibleId = successor.isVirtual ? findVisibleAncestor(taskMap.get(edge.successorId), collapsedParentIds, taskMap)?.id : edge.successorId;
|
|
5332
|
+
if (!renderedTaskIdSet.has(predecessorVisibleId ?? "") && !renderedTaskIdSet.has(successorVisibleId ?? "")) {
|
|
5151
5333
|
continue;
|
|
5152
5334
|
}
|
|
5153
5335
|
const isVirtual = predecessor.isVirtual || successor.isVirtual;
|
|
@@ -5161,9 +5343,9 @@ var DependencyLines = import_react7.default.memo(({
|
|
|
5161
5343
|
let toY;
|
|
5162
5344
|
if (reverseOrder) {
|
|
5163
5345
|
fromY = predecessor.rowTop + 10;
|
|
5164
|
-
toY = successor.rowTop + rowHeight - 6;
|
|
5346
|
+
toY = successor.rowTop + successor.rowHeight - 6;
|
|
5165
5347
|
} else {
|
|
5166
|
-
fromY = predecessor.rowTop + rowHeight - 10;
|
|
5348
|
+
fromY = predecessor.rowTop + predecessor.rowHeight - 10;
|
|
5167
5349
|
toY = successor.rowTop + 6;
|
|
5168
5350
|
}
|
|
5169
5351
|
let fromX = predecessorTask && isMilestoneTask(predecessorTask) ? predecessor.centerX : edge.type === "SS" || edge.type === "SF" ? predecessor.left : predecessor.right;
|
|
@@ -6841,6 +7023,7 @@ var TaskListRow = import_react11.default.memo(
|
|
|
6841
7023
|
taskListMenuCommands = [],
|
|
6842
7024
|
hideTaskListRowActions = false,
|
|
6843
7025
|
rowClassName,
|
|
7026
|
+
compositeParentColor,
|
|
6844
7027
|
getTaskListNamePrefixIcon,
|
|
6845
7028
|
taskDateChangeMode = "preserve-duration",
|
|
6846
7029
|
onTaskDateChangeModeChange,
|
|
@@ -6925,6 +7108,35 @@ var TaskListRow = import_react11.default.memo(
|
|
|
6925
7108
|
[businessDays, weekendPredicate]
|
|
6926
7109
|
);
|
|
6927
7110
|
const isCollapsed = collapsedParentIds.has(task.id);
|
|
7111
|
+
const [compositeIconMode, setCompositeIconMode] = (0, import_react11.useState)(
|
|
7112
|
+
() => isCollapsed ? "composite" : "down"
|
|
7113
|
+
);
|
|
7114
|
+
const compositeIconModeRef = (0, import_react11.useRef)(compositeIconMode);
|
|
7115
|
+
const [compositeIconAnimation, setCompositeIconAnimation] = (0, import_react11.useState)(null);
|
|
7116
|
+
const [compositeIconAnimationPhase, setCompositeIconAnimationPhase] = (0, import_react11.useState)(null);
|
|
7117
|
+
(0, import_react11.useEffect)(() => {
|
|
7118
|
+
const nextMode = isCollapsed ? "composite" : "down";
|
|
7119
|
+
if (nextMode === compositeIconModeRef.current) {
|
|
7120
|
+
setCompositeIconAnimation(null);
|
|
7121
|
+
setCompositeIconAnimationPhase(null);
|
|
7122
|
+
return;
|
|
7123
|
+
}
|
|
7124
|
+
setCompositeIconAnimation(isCollapsed ? "closing" : "opening");
|
|
7125
|
+
setCompositeIconAnimationPhase("outgoing");
|
|
7126
|
+
const swapTimeoutId = window.setTimeout(() => {
|
|
7127
|
+
compositeIconModeRef.current = nextMode;
|
|
7128
|
+
setCompositeIconMode(nextMode);
|
|
7129
|
+
setCompositeIconAnimationPhase("incoming");
|
|
7130
|
+
}, 120);
|
|
7131
|
+
const finishTimeoutId = window.setTimeout(() => {
|
|
7132
|
+
setCompositeIconAnimation(null);
|
|
7133
|
+
setCompositeIconAnimationPhase(null);
|
|
7134
|
+
}, 240);
|
|
7135
|
+
return () => {
|
|
7136
|
+
window.clearTimeout(swapTimeoutId);
|
|
7137
|
+
window.clearTimeout(finishTimeoutId);
|
|
7138
|
+
};
|
|
7139
|
+
}, [isCollapsed]);
|
|
6928
7140
|
const getHierarchyLineColor = (0, import_react11.useCallback)((columnDepth) => {
|
|
6929
7141
|
return columnDepth % 2 === 0 ? "#93c5fd" : "var(--gantt-hierarchy-line-color)";
|
|
6930
7142
|
}, []);
|
|
@@ -7033,6 +7245,7 @@ var TaskListRow = import_react11.default.memo(
|
|
|
7033
7245
|
);
|
|
7034
7246
|
const handleNameDoubleClick = (0, import_react11.useCallback)(
|
|
7035
7247
|
(e) => {
|
|
7248
|
+
if (task.composite) return;
|
|
7036
7249
|
if (disableTaskNameEditing) return;
|
|
7037
7250
|
e.stopPropagation();
|
|
7038
7251
|
nameConfirmedRef.current = false;
|
|
@@ -7040,7 +7253,7 @@ var TaskListRow = import_react11.default.memo(
|
|
|
7040
7253
|
setNameValue(task.name);
|
|
7041
7254
|
setEditingColumnId("name");
|
|
7042
7255
|
},
|
|
7043
|
-
[task.name, disableTaskNameEditing]
|
|
7256
|
+
[task.name, task.composite, disableTaskNameEditing]
|
|
7044
7257
|
);
|
|
7045
7258
|
const handleRowKeyDown = (0, import_react11.useCallback)(
|
|
7046
7259
|
(e) => {
|
|
@@ -7689,7 +7902,7 @@ var TaskListRow = import_react11.default.memo(
|
|
|
7689
7902
|
]
|
|
7690
7903
|
}
|
|
7691
7904
|
);
|
|
7692
|
-
const nameTriggerPaddingLeft = isParent ? `${nestingDepth * 20 + 28}px` : nestingDepth > 0 ? `${nestingDepth * 20 + 8}px` : void 0;
|
|
7905
|
+
const nameTriggerPaddingLeft = isParent && !task.composite ? `${nestingDepth * 20 + 28}px` : nestingDepth > 0 ? `${nestingDepth * 20 + 8}px` : void 0;
|
|
7693
7906
|
const nameInputPaddingLeft = nestingDepth > 0 ? `${nestingDepth * 20 + 8}px` : void 0;
|
|
7694
7907
|
const nestedDropIndicatorLeft = (() => {
|
|
7695
7908
|
const numberColumnWidth = resolvedColumns?.find((col) => col.id === "number")?.width ?? 40;
|
|
@@ -7787,36 +8000,35 @@ var TaskListRow = import_react11.default.memo(
|
|
|
7787
8000
|
}
|
|
7788
8001
|
)
|
|
7789
8002
|
] }),
|
|
7790
|
-
|
|
7791
|
-
|
|
7792
|
-
|
|
7793
|
-
|
|
7794
|
-
|
|
7795
|
-
|
|
7796
|
-
|
|
7797
|
-
|
|
7798
|
-
|
|
7799
|
-
|
|
7800
|
-
|
|
7801
|
-
|
|
7802
|
-
|
|
7803
|
-
}
|
|
7804
|
-
}
|
|
7805
|
-
),
|
|
7806
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
7807
|
-
"button",
|
|
7808
|
-
{
|
|
7809
|
-
type: "button",
|
|
7810
|
-
className: `gantt-tl-collapse-btn ${isCollapsed ? "gantt-tl-collapse-btn-collapsed" : ""}`,
|
|
7811
|
-
onClick: handleToggleCollapse,
|
|
7812
|
-
style: { left: `${nestingDepth * 20 + 1}px` },
|
|
7813
|
-
"aria-label": isCollapsed ? "Expand children" : "Collapse children",
|
|
7814
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ChevronRightIcon, {})
|
|
8003
|
+
task.composite && !isFilterHideMode && !isCollapsed && !editingName && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
8004
|
+
"span",
|
|
8005
|
+
{
|
|
8006
|
+
"data-testid": "gantt-tl-parent-connector-tail",
|
|
8007
|
+
style: {
|
|
8008
|
+
position: "absolute",
|
|
8009
|
+
left: `${nestingDepth * 20 + 9}px`,
|
|
8010
|
+
top: `${rowHeight / 2 + 7}px`,
|
|
8011
|
+
height: `${rowHeight / 2 - 7}px`,
|
|
8012
|
+
width: "1.5px",
|
|
8013
|
+
background: getHierarchyLineColor(nestingDepth),
|
|
8014
|
+
borderRadius: "1px",
|
|
8015
|
+
pointerEvents: "none"
|
|
7815
8016
|
}
|
|
7816
|
-
|
|
7817
|
-
|
|
8017
|
+
}
|
|
8018
|
+
),
|
|
8019
|
+
isParent && !task.composite && !editingName && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_jsx_runtime14.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
8020
|
+
"button",
|
|
8021
|
+
{
|
|
8022
|
+
type: "button",
|
|
8023
|
+
className: `gantt-tl-collapse-btn ${isCollapsed ? "gantt-tl-collapse-btn-collapsed" : ""}`,
|
|
8024
|
+
onClick: handleToggleCollapse,
|
|
8025
|
+
style: { left: `${nestingDepth * 20 - 2}px` },
|
|
8026
|
+
"aria-label": isCollapsed ? "Expand children" : "Collapse children",
|
|
8027
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ChevronRightIcon, {})
|
|
8028
|
+
}
|
|
8029
|
+
) })
|
|
7818
8030
|
] }),
|
|
7819
|
-
!isChild && isParent && !editingName && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
|
|
8031
|
+
!isChild && isParent && !task.composite && !editingName && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
|
|
7820
8032
|
!isFilterHideMode && !isCollapsed && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
7821
8033
|
"span",
|
|
7822
8034
|
{
|
|
@@ -7839,7 +8051,7 @@ var TaskListRow = import_react11.default.memo(
|
|
|
7839
8051
|
type: "button",
|
|
7840
8052
|
className: `gantt-tl-collapse-btn ${isCollapsed ? "gantt-tl-collapse-btn-collapsed" : ""}`,
|
|
7841
8053
|
onClick: handleToggleCollapse,
|
|
7842
|
-
style: { left: `${nestingDepth * 20
|
|
8054
|
+
style: { left: `${nestingDepth * 20 - 2}px` },
|
|
7843
8055
|
"aria-label": isCollapsed ? "Expand children" : "Collapse children",
|
|
7844
8056
|
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ChevronRightIcon, {})
|
|
7845
8057
|
}
|
|
@@ -7858,27 +8070,57 @@ var TaskListRow = import_react11.default.memo(
|
|
|
7858
8070
|
style: { paddingLeft: nameInputPaddingLeft },
|
|
7859
8071
|
onClick: (e) => e.stopPropagation()
|
|
7860
8072
|
}
|
|
7861
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
7862
|
-
|
|
7863
|
-
|
|
7864
|
-
|
|
7865
|
-
|
|
7866
|
-
"gantt-tl-
|
|
7867
|
-
|
|
7868
|
-
|
|
7869
|
-
|
|
7870
|
-
|
|
7871
|
-
|
|
7872
|
-
|
|
7873
|
-
|
|
7874
|
-
|
|
7875
|
-
|
|
7876
|
-
|
|
7877
|
-
|
|
7878
|
-
|
|
7879
|
-
|
|
7880
|
-
|
|
7881
|
-
|
|
8073
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
|
|
8074
|
+
task.composite && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
8075
|
+
"button",
|
|
8076
|
+
{
|
|
8077
|
+
type: "button",
|
|
8078
|
+
className: "gantt-tl-compositeToggle",
|
|
8079
|
+
onClick: handleToggleCollapse,
|
|
8080
|
+
style: { left: `${nestingDepth * 20 - 3}px` },
|
|
8081
|
+
"aria-label": isCollapsed ? `\u0420\u0430\u0441\u043A\u0440\u044B\u0442\u044C ${task.name}` : `\u0421\u0432\u0435\u0440\u043D\u0443\u0442\u044C ${task.name}`,
|
|
8082
|
+
"aria-expanded": !isCollapsed,
|
|
8083
|
+
title: isCollapsed ? "\u0420\u0430\u0441\u043A\u0440\u044B\u0442\u044C \u044D\u0442\u0430\u0436\u0438" : "\u0421\u0432\u0435\u0440\u043D\u0443\u0442\u044C \u044D\u0442\u0430\u0436\u0438",
|
|
8084
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
8085
|
+
"svg",
|
|
8086
|
+
{
|
|
8087
|
+
className: compositeIconAnimation && compositeIconAnimationPhase ? `gantt-tl-compositeGlyph-${compositeIconMode}-${compositeIconAnimation}-${compositeIconAnimationPhase}` : void 0,
|
|
8088
|
+
viewBox: "0 0 24 24",
|
|
8089
|
+
fill: "none",
|
|
8090
|
+
stroke: "currentColor",
|
|
8091
|
+
strokeWidth: "2",
|
|
8092
|
+
strokeLinecap: "round",
|
|
8093
|
+
strokeLinejoin: "round",
|
|
8094
|
+
"aria-hidden": "true",
|
|
8095
|
+
children: compositeIconMode === "composite" ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
|
|
8096
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("path", { d: "M21 5H11" }),
|
|
8097
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("path", { d: "M21 12H11" }),
|
|
8098
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("path", { d: "M21 19H11" }),
|
|
8099
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("path", { d: "m3 8 4 4-4 4" })
|
|
8100
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("path", { d: "m6 9 6 6 6-6" })
|
|
8101
|
+
}
|
|
8102
|
+
)
|
|
8103
|
+
}
|
|
8104
|
+
),
|
|
8105
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
8106
|
+
"button",
|
|
8107
|
+
{
|
|
8108
|
+
type: "button",
|
|
8109
|
+
className: `gantt-tl-name-trigger${disableTaskNameEditing ? " gantt-tl-name-locked" : ""}`,
|
|
8110
|
+
title: task.name,
|
|
8111
|
+
onClick: handleNameClick,
|
|
8112
|
+
onDoubleClick: handleNameDoubleClick,
|
|
8113
|
+
style: {
|
|
8114
|
+
paddingLeft: task.composite ? `${nestingDepth * 20 + 30}px` : nameTriggerPaddingLeft,
|
|
8115
|
+
paddingRight: task.color ? "20px" : void 0
|
|
8116
|
+
},
|
|
8117
|
+
children: [
|
|
8118
|
+
taskListNamePrefixIcon ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "gantt-tl-name-trigger-icon", "aria-hidden": "true", children: taskListNamePrefixIcon }) : null,
|
|
8119
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "gantt-tl-name-trigger-text", children: task.name })
|
|
8120
|
+
]
|
|
8121
|
+
}
|
|
8122
|
+
)
|
|
8123
|
+
] }),
|
|
7882
8124
|
!editingName && task.color && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
7883
8125
|
"span",
|
|
7884
8126
|
{
|
|
@@ -8495,8 +8737,9 @@ var TaskListRow = import_react11.default.memo(
|
|
|
8495
8737
|
isDragOver && isNestedDropTarget ? "gantt-tl-row-drag-over-nested" : "",
|
|
8496
8738
|
isDragOver && isDirectChildDropTarget ? "gantt-tl-row-drag-over-direct-child" : "",
|
|
8497
8739
|
isChild ? "gantt-tl-row-child" : "",
|
|
8498
|
-
isParent ? "gantt-tl-row-parent" : "",
|
|
8499
|
-
|
|
8740
|
+
isParent && !task.composite ? "gantt-tl-row-parent" : "",
|
|
8741
|
+
task.composite ? "gantt-tl-row-composite" : "",
|
|
8742
|
+
isParent && !task.composite && fillParentRow ? "gantt-tl-row-parent-filled" : "",
|
|
8500
8743
|
`gantt-tl-row-level-${rowFillLevel}`,
|
|
8501
8744
|
isTotalRow ? "gantt-tl-row-total" : "",
|
|
8502
8745
|
rowClassName ?? ""
|
|
@@ -8504,6 +8747,7 @@ var TaskListRow = import_react11.default.memo(
|
|
|
8504
8747
|
style: {
|
|
8505
8748
|
height: `${rowHeight}px`,
|
|
8506
8749
|
position: "relative",
|
|
8750
|
+
"--gantt-tl-composite-detail-color": compositeParentColor ?? "var(--gantt-task-bar-default-color, #8b5cf6)",
|
|
8507
8751
|
"--gantt-tl-nested-drop-left": nestedDropIndicatorLeft,
|
|
8508
8752
|
"--gantt-tl-nested-inside-drop-left": nestedInsideDropIndicatorLeft
|
|
8509
8753
|
},
|
|
@@ -8729,6 +8973,7 @@ var GenerationSkeletonRows = ({
|
|
|
8729
8973
|
rowHeight,
|
|
8730
8974
|
variant,
|
|
8731
8975
|
startIndex = 0,
|
|
8976
|
+
startTop,
|
|
8732
8977
|
taskListLayout,
|
|
8733
8978
|
chartDayWidth = 40,
|
|
8734
8979
|
chartStartDayOffset = 0,
|
|
@@ -8769,7 +9014,7 @@ var GenerationSkeletonRows = ({
|
|
|
8769
9014
|
"div",
|
|
8770
9015
|
{
|
|
8771
9016
|
className: "gantt-generation-skeleton-row",
|
|
8772
|
-
style: { top: `${
|
|
9017
|
+
style: { top: `${(startTop ?? startIndex * rowHeight) + index * rowHeight}px`, height: `${rowHeight}px` },
|
|
8773
9018
|
children: variant === "task-list" ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: `gantt-generation-skeleton-label ${shortShape ? "gantt-generation-skeleton-label-short" : ""} ${mediumShape ? "gantt-generation-skeleton-label-medium" : ""}` }) }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: `gantt-generation-skeleton-bar ${parentShape ? "gantt-generation-skeleton-bar-parent" : ""} ${shortShape ? "gantt-generation-skeleton-bar-short" : ""}`, style: chartBarStyle })
|
|
8774
9019
|
},
|
|
8775
9020
|
rowIndex
|
|
@@ -9029,6 +9274,8 @@ var SelectAllCheckbox = ({
|
|
|
9029
9274
|
var TaskList = ({
|
|
9030
9275
|
tasks,
|
|
9031
9276
|
rowHeight,
|
|
9277
|
+
rowTops,
|
|
9278
|
+
rowHeights,
|
|
9032
9279
|
headerHeight,
|
|
9033
9280
|
taskListWidth,
|
|
9034
9281
|
onTasksChange,
|
|
@@ -9156,14 +9403,22 @@ var TaskList = ({
|
|
|
9156
9403
|
return tasks2;
|
|
9157
9404
|
}, [orderedTasks, collapsedParentIds, filterMode, filteredTaskIds, isFilterActive, criticalPathMode, criticalTaskIds]);
|
|
9158
9405
|
const totalHeight = (0, import_react14.useMemo)(
|
|
9159
|
-
() => (visibleTasks.length + Math.max(0, Math.floor(skeletonRowCount))
|
|
9160
|
-
[rowHeight, skeletonRowCount, visibleTasks.length]
|
|
9406
|
+
() => (rowTops && rowHeights && visibleTasks.length > 0 ? rowTops[visibleTasks.length - 1] + rowHeights[visibleTasks.length - 1] : visibleTasks.length * rowHeight) + Math.max(0, Math.floor(skeletonRowCount)) * rowHeight,
|
|
9407
|
+
[rowHeight, rowTops, rowHeights, skeletonRowCount, visibleTasks.length]
|
|
9161
9408
|
);
|
|
9162
9409
|
const visibleTaskNumberMap = (0, import_react14.useMemo)(
|
|
9163
9410
|
() => Object.fromEntries(buildTaskNumberMap(visibleTasks)),
|
|
9164
9411
|
[visibleTasks]
|
|
9165
9412
|
);
|
|
9166
9413
|
const visibleTaskIds = (0, import_react14.useMemo)(() => visibleTasks.map((task) => task.id), [visibleTasks]);
|
|
9414
|
+
const compositeParentIds = (0, import_react14.useMemo)(
|
|
9415
|
+
() => new Set(tasks.filter((task) => task.composite).map((task) => task.id)),
|
|
9416
|
+
[tasks]
|
|
9417
|
+
);
|
|
9418
|
+
const compositeParentsById = (0, import_react14.useMemo)(
|
|
9419
|
+
() => new Map(tasks.filter((task) => task.composite).map((task) => [task.id, task])),
|
|
9420
|
+
[tasks]
|
|
9421
|
+
);
|
|
9167
9422
|
const renderedVisibleRowIndices = (0, import_react14.useMemo)(
|
|
9168
9423
|
() => visibleRowIndices ?? visibleTasks.map((_, index) => index),
|
|
9169
9424
|
[visibleRowIndices, visibleTasks]
|
|
@@ -10155,7 +10410,7 @@ var TaskList = ({
|
|
|
10155
10410
|
renderedVisibleTasks.map(({ task, index }) => {
|
|
10156
10411
|
const previousVisibleTask = index > 0 ? visibleTasks[index - 1] : void 0;
|
|
10157
10412
|
const canDemoteTask = index === 0 || !task.parentId || previousVisibleTask?.id !== task.parentId;
|
|
10158
|
-
const topOffset = index * rowHeight + (hasVisiblePendingInsert && index > pendingInsertRowIndex ? rowHeight : 0);
|
|
10413
|
+
const topOffset = (rowTops?.[index] ?? index * rowHeight) + (hasVisiblePendingInsert && index > pendingInsertRowIndex ? rowHeight : 0);
|
|
10159
10414
|
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
10160
10415
|
"div",
|
|
10161
10416
|
{
|
|
@@ -10172,7 +10427,7 @@ var TaskList = ({
|
|
|
10172
10427
|
rowIndex: index,
|
|
10173
10428
|
taskNumber: originalTaskNumberMap[task.id] || "",
|
|
10174
10429
|
taskNumberMap: originalTaskNumberMap,
|
|
10175
|
-
rowHeight,
|
|
10430
|
+
rowHeight: rowHeights?.[index] ?? rowHeight,
|
|
10176
10431
|
onTasksChange,
|
|
10177
10432
|
onDurationChange,
|
|
10178
10433
|
selectedTaskId,
|
|
@@ -10229,7 +10484,8 @@ var TaskList = ({
|
|
|
10229
10484
|
onActiveCustomCellChange: setActiveCustomCell,
|
|
10230
10485
|
taskListMenuCommands,
|
|
10231
10486
|
hideTaskListRowActions,
|
|
10232
|
-
rowClassName: getTaskListRowClassName?.(task),
|
|
10487
|
+
rowClassName: [task.parentId && compositeParentIds.has(task.parentId) ? "gantt-tl-row-composite-detail" : "", getTaskListRowClassName?.(task)].filter(Boolean).join(" "),
|
|
10488
|
+
compositeParentColor: task.parentId ? compositeParentsById.get(task.parentId)?.color : void 0,
|
|
10233
10489
|
getTaskListNamePrefixIcon,
|
|
10234
10490
|
taskDateChangeMode,
|
|
10235
10491
|
onTaskDateChangeModeChange,
|
|
@@ -10245,7 +10501,7 @@ var TaskList = ({
|
|
|
10245
10501
|
{
|
|
10246
10502
|
style: {
|
|
10247
10503
|
position: "absolute",
|
|
10248
|
-
top: `${(pendingInsertRowIndex + 1) * rowHeight}px`,
|
|
10504
|
+
top: `${rowTops?.[pendingInsertRowIndex + 1] ?? (pendingInsertRowIndex + 1) * rowHeight}px`,
|
|
10249
10505
|
left: 0,
|
|
10250
10506
|
right: 0
|
|
10251
10507
|
},
|
|
@@ -10267,6 +10523,7 @@ var TaskList = ({
|
|
|
10267
10523
|
rowHeight,
|
|
10268
10524
|
variant: "task-list",
|
|
10269
10525
|
startIndex: visibleTasks.length,
|
|
10526
|
+
startTop: totalHeight - Math.max(0, Math.floor(skeletonRowCount)) * rowHeight,
|
|
10270
10527
|
taskListLayout: generationSkeletonTaskListLayout
|
|
10271
10528
|
}
|
|
10272
10529
|
)
|
|
@@ -14237,6 +14494,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
14237
14494
|
skeletonStartJitterDays = 0,
|
|
14238
14495
|
showTaskDateLabels = true,
|
|
14239
14496
|
showTaskNames = true,
|
|
14497
|
+
showCompositeSegments = true,
|
|
14240
14498
|
timelineMarkers,
|
|
14241
14499
|
additionalColumns,
|
|
14242
14500
|
hiddenTaskListColumns,
|
|
@@ -14451,17 +14709,46 @@ function TaskGanttChartInner(props, ref) {
|
|
|
14451
14709
|
}, [dependencyLineMenu, onTasksChange, tasks]);
|
|
14452
14710
|
const [activeTimelineTooltip, setActiveTimelineTooltip] = (0, import_react19.useState)(null);
|
|
14453
14711
|
const [internalCollapsedParentIds, setInternalCollapsedParentIds] = (0, import_react19.useState)(/* @__PURE__ */ new Set());
|
|
14454
|
-
const
|
|
14712
|
+
const [expandedCompositeIds, setExpandedCompositeIds] = (0, import_react19.useState)(/* @__PURE__ */ new Set());
|
|
14455
14713
|
const [editingTaskId, setEditingTaskId] = (0, import_react19.useState)(null);
|
|
14456
14714
|
const taskDateChangeMode = externalTaskDateChangeMode ?? internalTaskDateChangeMode;
|
|
14457
14715
|
const handleTaskDateChangeMode = externalOnTaskDateChangeModeChange ?? setInternalTaskDateChangeMode;
|
|
14458
14716
|
const resolvedRowContentLines = isPlanFactMode ? Math.max(2, Math.floor(rowContentLines)) : Math.max(1, Math.floor(rowContentLines));
|
|
14459
14717
|
const shouldFillParentRowsInTaskList = fillParentRowsInTaskList ?? isPlanFactMode;
|
|
14460
14718
|
const effectiveRowHeight = (0, import_react19.useMemo)(
|
|
14461
|
-
() => Math.max(rowHeight, 10 + resolvedRowContentLines * 18),
|
|
14462
|
-
[resolvedRowContentLines, rowHeight]
|
|
14719
|
+
() => rowContentLines === 0 && !isPlanFactMode ? rowHeight : Math.max(rowHeight, 10 + resolvedRowContentLines * 18),
|
|
14720
|
+
[isPlanFactMode, resolvedRowContentLines, rowContentLines, rowHeight]
|
|
14463
14721
|
);
|
|
14464
|
-
const normalizedTasks = (0, import_react19.useMemo)(() =>
|
|
14722
|
+
const normalizedTasks = (0, import_react19.useMemo)(() => {
|
|
14723
|
+
const ordered = normalizeHierarchyTasks(tasks);
|
|
14724
|
+
const ranges = /* @__PURE__ */ new Map();
|
|
14725
|
+
for (const task of ordered) {
|
|
14726
|
+
if (!task.parentId) continue;
|
|
14727
|
+
const start = parseUTCDate(task.startDate).getTime();
|
|
14728
|
+
const end = parseUTCDate(task.endDate).getTime();
|
|
14729
|
+
const range = ranges.get(task.parentId);
|
|
14730
|
+
ranges.set(task.parentId, {
|
|
14731
|
+
start: Math.min(range?.start ?? start, start),
|
|
14732
|
+
end: Math.max(range?.end ?? end, end)
|
|
14733
|
+
});
|
|
14734
|
+
}
|
|
14735
|
+
return ordered.map((task) => {
|
|
14736
|
+
const range = task.composite ? ranges.get(task.id) : void 0;
|
|
14737
|
+
return range ? {
|
|
14738
|
+
...task,
|
|
14739
|
+
startDate: new Date(range.start).toISOString().slice(0, 10),
|
|
14740
|
+
endDate: new Date(range.end).toISOString().slice(0, 10)
|
|
14741
|
+
} : task;
|
|
14742
|
+
});
|
|
14743
|
+
}, [tasks]);
|
|
14744
|
+
const collapsedParentIds = (0, import_react19.useMemo)(() => {
|
|
14745
|
+
if (externalCollapsedParentIds) return externalCollapsedParentIds;
|
|
14746
|
+
const ids = new Set(internalCollapsedParentIds);
|
|
14747
|
+
for (const task of normalizedTasks) {
|
|
14748
|
+
if (task.composite && !expandedCompositeIds.has(task.id)) ids.add(task.id);
|
|
14749
|
+
}
|
|
14750
|
+
return ids;
|
|
14751
|
+
}, [externalCollapsedParentIds, internalCollapsedParentIds, normalizedTasks, expandedCompositeIds]);
|
|
14465
14752
|
const controlledScheduleIdentity = (0, import_react19.useMemo)(
|
|
14466
14753
|
() => buildControlledScheduleIdentity(normalizedTasks),
|
|
14467
14754
|
[normalizedTasks]
|
|
@@ -14541,6 +14828,23 @@ function TaskGanttChartInner(props, ref) {
|
|
|
14541
14828
|
}
|
|
14542
14829
|
return tasks2;
|
|
14543
14830
|
}, [normalizedTasks, collapsedParentIds, filterMode, taskFilter, criticalPathMode, criticalTaskIds]);
|
|
14831
|
+
const compositeRowLayout = (0, import_react19.useMemo)(() => {
|
|
14832
|
+
const compositeIds = new Set(normalizedTasks.filter((task) => task.composite).map((task) => task.id));
|
|
14833
|
+
const tops = [];
|
|
14834
|
+
const heights = [];
|
|
14835
|
+
let top = 0;
|
|
14836
|
+
for (const task of visibleTasks) {
|
|
14837
|
+
tops.push(top);
|
|
14838
|
+
const height = task.parentId && compositeIds.has(task.parentId) ? Math.min(effectiveRowHeight, 22) : effectiveRowHeight;
|
|
14839
|
+
heights.push(height);
|
|
14840
|
+
top += height;
|
|
14841
|
+
}
|
|
14842
|
+
return { tops, heights, totalHeight: top };
|
|
14843
|
+
}, [normalizedTasks, visibleTasks, effectiveRowHeight]);
|
|
14844
|
+
const compositeParentsById = (0, import_react19.useMemo)(
|
|
14845
|
+
() => new Map(normalizedTasks.filter((task) => task.composite).map((task) => [task.id, task])),
|
|
14846
|
+
[normalizedTasks]
|
|
14847
|
+
);
|
|
14544
14848
|
const matchedTaskIds = (0, import_react19.useMemo)(() => {
|
|
14545
14849
|
if (!taskFilter) return /* @__PURE__ */ new Set();
|
|
14546
14850
|
return new Set(visibleTasks.filter(taskFilter).map((task) => task.id));
|
|
@@ -14562,8 +14866,8 @@ function TaskGanttChartInner(props, ref) {
|
|
|
14562
14866
|
return mergedHighlightedTaskIds;
|
|
14563
14867
|
}, [filterMode, highlightedTaskIds, matchedTaskIds, criticalPathMode, criticalTaskIds]);
|
|
14564
14868
|
const totalGridHeight = (0, import_react19.useMemo)(
|
|
14565
|
-
() =>
|
|
14566
|
-
[effectiveRowHeight, skeletonRowCount
|
|
14869
|
+
() => compositeRowLayout.totalHeight + Math.max(0, Math.floor(skeletonRowCount)) * effectiveRowHeight,
|
|
14870
|
+
[compositeRowLayout.totalHeight, effectiveRowHeight, skeletonRowCount]
|
|
14567
14871
|
);
|
|
14568
14872
|
const timelineHeaderHeight = headerHeight + 1;
|
|
14569
14873
|
const tableBodyMinHeight = (0, import_react19.useMemo)(() => {
|
|
@@ -14690,7 +14994,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
14690
14994
|
const rowIndex = visibleTasks.findIndex((visibleTask) => visibleTask.id === taskId);
|
|
14691
14995
|
if (rowIndex === -1) return;
|
|
14692
14996
|
const paddedRowIndex = Math.max(0, rowIndex - SCROLL_TO_ROW_CONTEXT_ROWS);
|
|
14693
|
-
container2.scrollTo({ top: Math.max(0,
|
|
14997
|
+
container2.scrollTo({ top: Math.max(0, compositeRowLayout.tops[paddedRowIndex] ?? 0), behavior: "smooth" });
|
|
14694
14998
|
setSelectedTaskId(taskId);
|
|
14695
14999
|
return;
|
|
14696
15000
|
}
|
|
@@ -14709,7 +15013,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
14709
15013
|
const taskOffset = taskIndex * dayWidth;
|
|
14710
15014
|
const scrollLeft = Math.round(taskOffset - dayWidth * 2);
|
|
14711
15015
|
container.scrollTo({ left: Math.max(0, scrollLeft), behavior: "smooth" });
|
|
14712
|
-
}, [dateRange, dayWidth, effectiveRowHeight, isTableMatrixMode, tasks, visibleTasks]);
|
|
15016
|
+
}, [dateRange, dayWidth, effectiveRowHeight, compositeRowLayout, isTableMatrixMode, tasks, visibleTasks]);
|
|
14713
15017
|
const scrollToRow = (0, import_react19.useCallback)((taskId, options = {}) => {
|
|
14714
15018
|
const container = scrollContainerRef.current;
|
|
14715
15019
|
if (!container) return;
|
|
@@ -14718,7 +15022,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
14718
15022
|
const rowIndex = visibleTasks.findIndex((visibleTask) => visibleTask.id === task.id);
|
|
14719
15023
|
if (rowIndex === -1) return;
|
|
14720
15024
|
const paddedRowIndex = Math.max(0, rowIndex - SCROLL_TO_ROW_CONTEXT_ROWS);
|
|
14721
|
-
const scrollTop = Math.max(0,
|
|
15025
|
+
const scrollTop = Math.max(0, compositeRowLayout.tops[paddedRowIndex] ?? 0);
|
|
14722
15026
|
const {
|
|
14723
15027
|
select = true,
|
|
14724
15028
|
behavior = "smooth",
|
|
@@ -14738,7 +15042,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
14738
15042
|
}
|
|
14739
15043
|
}
|
|
14740
15044
|
container.scrollTo({ top: scrollTop, behavior });
|
|
14741
|
-
}, [effectiveRowHeight, tasks, visibleTasks]);
|
|
15045
|
+
}, [effectiveRowHeight, compositeRowLayout, tasks, visibleTasks]);
|
|
14742
15046
|
const [dragGuideLines, setDragGuideLines] = (0, import_react19.useState)(null);
|
|
14743
15047
|
const [draggedTaskOverride, setDraggedTaskOverride] = (0, import_react19.useState)(null);
|
|
14744
15048
|
(0, import_react19.useEffect)(() => {
|
|
@@ -14765,9 +15069,9 @@ function TaskGanttChartInner(props, ref) {
|
|
|
14765
15069
|
previewPositionStore.clear();
|
|
14766
15070
|
}, [previewPositionStore]);
|
|
14767
15071
|
const handleTaskChange = (0, import_react19.useCallback)((updatedTasks, durationEdit) => {
|
|
14768
|
-
|
|
15072
|
+
let updatedTask = updatedTasks[0];
|
|
14769
15073
|
if (!updatedTask) return;
|
|
14770
|
-
const originalTask =
|
|
15074
|
+
const originalTask = normalizedTasks.find((t) => t.id === updatedTask.id);
|
|
14771
15075
|
if (!originalTask) {
|
|
14772
15076
|
onTasksChange?.(updatedTasks);
|
|
14773
15077
|
if (editingTaskId === updatedTask.id) {
|
|
@@ -14780,6 +15084,8 @@ function TaskGanttChartInner(props, ref) {
|
|
|
14780
15084
|
const newStart = new Date(updatedTask.startDate);
|
|
14781
15085
|
const newEnd = new Date(updatedTask.endDate);
|
|
14782
15086
|
const datesChanged = origStart.getTime() !== newStart.getTime() || origEnd.getTime() !== newEnd.getTime();
|
|
15087
|
+
const isCompositeDetail = datesChanged && tasks.some((task) => task.id === updatedTask.parentId && task.composite);
|
|
15088
|
+
if (isCompositeDetail) updatedTask = { ...updatedTask, synced: false };
|
|
14783
15089
|
if (!datesChanged) {
|
|
14784
15090
|
if (updatedTasks.length > 1) {
|
|
14785
15091
|
onTasksChange?.(updatedTasks);
|
|
@@ -14841,7 +15147,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
14841
15147
|
}
|
|
14842
15148
|
return;
|
|
14843
15149
|
}
|
|
14844
|
-
const movedParentCascade = disableConstraints ? [updatedTask] : universalCascade(updatedTask, newStart, newEnd,
|
|
15150
|
+
const movedParentCascade = disableConstraints && !originalTask.composite ? [updatedTask] : universalCascade(updatedTask, newStart, newEnd, normalizedTasks, businessDays, isCustomWeekend);
|
|
14845
15151
|
if (onScheduleIntent) {
|
|
14846
15152
|
onScheduleIntent({
|
|
14847
15153
|
type: "move_task",
|
|
@@ -14865,7 +15171,8 @@ function TaskGanttChartInner(props, ref) {
|
|
|
14865
15171
|
taskId: updatedTask.id,
|
|
14866
15172
|
duration: durationEdit.duration,
|
|
14867
15173
|
anchor: durationEdit.anchor,
|
|
14868
|
-
taskType: updatedTask.type ?? "task"
|
|
15174
|
+
taskType: updatedTask.type ?? "task",
|
|
15175
|
+
...isCompositeDetail ? { localOverride: true } : {}
|
|
14869
15176
|
});
|
|
14870
15177
|
} else {
|
|
14871
15178
|
onTasksChange?.(cascadedTasks);
|
|
@@ -14877,7 +15184,8 @@ function TaskGanttChartInner(props, ref) {
|
|
|
14877
15184
|
onScheduleIntent({
|
|
14878
15185
|
type: "move_task",
|
|
14879
15186
|
taskId: updatedTask.id,
|
|
14880
|
-
startDate: newStart.toISOString().split("T")[0]
|
|
15187
|
+
startDate: newStart.toISOString().split("T")[0],
|
|
15188
|
+
...isCompositeDetail ? { localOverride: true } : {}
|
|
14881
15189
|
});
|
|
14882
15190
|
} else {
|
|
14883
15191
|
const anchor = startChanged ? "end" : "start";
|
|
@@ -14885,13 +15193,14 @@ function TaskGanttChartInner(props, ref) {
|
|
|
14885
15193
|
type: "resize_task",
|
|
14886
15194
|
taskId: updatedTask.id,
|
|
14887
15195
|
anchor,
|
|
14888
|
-
date: (startChanged ? newStart : newEnd).toISOString().split("T")[0]
|
|
15196
|
+
date: (startChanged ? newStart : newEnd).toISOString().split("T")[0],
|
|
15197
|
+
...isCompositeDetail ? { localOverride: true } : {}
|
|
14889
15198
|
});
|
|
14890
15199
|
}
|
|
14891
15200
|
} else {
|
|
14892
15201
|
onTasksChange?.(cascadedTasks);
|
|
14893
15202
|
}
|
|
14894
|
-
}, [tasks, onTasksChange, onScheduleIntent, disableConstraints, editingTaskId, businessDays, isCustomWeekend, onSubtreeScaleResult]);
|
|
15203
|
+
}, [tasks, normalizedTasks, onTasksChange, onScheduleIntent, disableConstraints, editingTaskId, businessDays, isCustomWeekend, onSubtreeScaleResult]);
|
|
14895
15204
|
const handleTaskDurationChange = (0, import_react19.useCallback)((task, duration) => {
|
|
14896
15205
|
const updatedTask = {
|
|
14897
15206
|
...task,
|
|
@@ -15005,12 +15314,25 @@ function TaskGanttChartInner(props, ref) {
|
|
|
15005
15314
|
if (scrollViewport.viewportHeight <= 0) {
|
|
15006
15315
|
return Array.from({ length: totalTasks }, (_, index) => index);
|
|
15007
15316
|
}
|
|
15008
|
-
|
|
15009
|
-
|
|
15010
|
-
|
|
15011
|
-
|
|
15012
|
-
|
|
15013
|
-
|
|
15317
|
+
let low = 0;
|
|
15318
|
+
let high = totalTasks;
|
|
15319
|
+
while (low < high) {
|
|
15320
|
+
const middle = low + high >>> 1;
|
|
15321
|
+
if (compositeRowLayout.tops[middle] + compositeRowLayout.heights[middle] < scrollViewport.scrollTop) low = middle + 1;
|
|
15322
|
+
else high = middle;
|
|
15323
|
+
}
|
|
15324
|
+
const first = Math.min(low, totalTasks - 1);
|
|
15325
|
+
const viewportBottom = scrollViewport.scrollTop + scrollViewport.viewportHeight;
|
|
15326
|
+
low = first;
|
|
15327
|
+
high = totalTasks;
|
|
15328
|
+
while (low < high) {
|
|
15329
|
+
const middle = low + high >>> 1;
|
|
15330
|
+
if (compositeRowLayout.tops[middle] < viewportBottom) low = middle + 1;
|
|
15331
|
+
else high = middle;
|
|
15332
|
+
}
|
|
15333
|
+
const last = Math.min(low, totalTasks - 1);
|
|
15334
|
+
const rangeStart = Math.max(0, first - TASK_ROW_OVERSCAN);
|
|
15335
|
+
const rangeEnd = Math.min(totalTasks - 1, last + TASK_ROW_OVERSCAN);
|
|
15014
15336
|
const indices = /* @__PURE__ */ new Set();
|
|
15015
15337
|
for (let index = rangeStart; index <= rangeEnd; index += 1) {
|
|
15016
15338
|
indices.add(index);
|
|
@@ -15022,7 +15344,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
15022
15344
|
}
|
|
15023
15345
|
}
|
|
15024
15346
|
return Array.from(indices).sort((left, right) => left - right);
|
|
15025
|
-
}, [
|
|
15347
|
+
}, [compositeRowLayout, forceFullRenderForPrint, forcedRenderedTaskIds, scrollViewport, visibleTaskIndexMap, visibleTasks.length]);
|
|
15026
15348
|
const visiblePlanFactDateIndices = (0, import_react19.useMemo)(() => {
|
|
15027
15349
|
if (forceFullRenderForPrint) {
|
|
15028
15350
|
return void 0;
|
|
@@ -15099,7 +15421,16 @@ function TaskGanttChartInner(props, ref) {
|
|
|
15099
15421
|
}
|
|
15100
15422
|
applyHoveredRows(taskId);
|
|
15101
15423
|
}, [applyHoveredRows]);
|
|
15102
|
-
const handleToggleCollapse = externalOnToggleCollapse ?? (
|
|
15424
|
+
const handleToggleCollapse = externalOnToggleCollapse ?? ((parentId) => {
|
|
15425
|
+
if (normalizedTasks.some((task) => task.id === parentId && task.composite)) {
|
|
15426
|
+
setExpandedCompositeIds((prev) => {
|
|
15427
|
+
const next = new Set(prev);
|
|
15428
|
+
if (next.has(parentId)) next.delete(parentId);
|
|
15429
|
+
else next.add(parentId);
|
|
15430
|
+
return next;
|
|
15431
|
+
});
|
|
15432
|
+
return;
|
|
15433
|
+
}
|
|
15103
15434
|
setInternalCollapsedParentIds((prev) => {
|
|
15104
15435
|
const next = new Set(prev);
|
|
15105
15436
|
if (next.has(parentId)) {
|
|
@@ -15109,7 +15440,14 @@ function TaskGanttChartInner(props, ref) {
|
|
|
15109
15440
|
}
|
|
15110
15441
|
return next;
|
|
15111
15442
|
});
|
|
15112
|
-
}
|
|
15443
|
+
});
|
|
15444
|
+
const lastCompositeBarToggleRef = (0, import_react19.useRef)(null);
|
|
15445
|
+
const handleCompositeBarToggle = (taskId, source) => {
|
|
15446
|
+
const now = Date.now();
|
|
15447
|
+
if (source === "click" && lastCompositeBarToggleRef.current?.source === "release" && lastCompositeBarToggleRef.current.id === taskId && now - lastCompositeBarToggleRef.current.time < 150) return;
|
|
15448
|
+
lastCompositeBarToggleRef.current = { id: taskId, time: now, source };
|
|
15449
|
+
handleToggleCollapse(taskId);
|
|
15450
|
+
};
|
|
15113
15451
|
const allParentIds = (0, import_react19.useMemo)(() => {
|
|
15114
15452
|
const taskIds = new Set(normalizedTasks.map((task) => task.id));
|
|
15115
15453
|
return new Set(normalizedTasks.map((task) => task.parentId).filter((parentId) => Boolean(parentId && taskIds.has(parentId))));
|
|
@@ -15117,11 +15455,13 @@ function TaskGanttChartInner(props, ref) {
|
|
|
15117
15455
|
const handleCollapseAll = (0, import_react19.useCallback)(() => {
|
|
15118
15456
|
if (externalCollapsedParentIds) return;
|
|
15119
15457
|
setInternalCollapsedParentIds(allParentIds);
|
|
15458
|
+
setExpandedCompositeIds(/* @__PURE__ */ new Set());
|
|
15120
15459
|
}, [allParentIds, externalCollapsedParentIds]);
|
|
15121
15460
|
const handleExpandAll = (0, import_react19.useCallback)(() => {
|
|
15122
15461
|
if (externalCollapsedParentIds) return;
|
|
15123
15462
|
setInternalCollapsedParentIds(/* @__PURE__ */ new Set());
|
|
15124
|
-
|
|
15463
|
+
setExpandedCompositeIds(new Set(normalizedTasks.filter((task) => task.composite).map((task) => task.id)));
|
|
15464
|
+
}, [externalCollapsedParentIds, normalizedTasks]);
|
|
15125
15465
|
const exportToPdf = (0, import_react19.useCallback)(async (options) => {
|
|
15126
15466
|
const sourceContainer = containerRef.current;
|
|
15127
15467
|
if (!sourceContainer || typeof window === "undefined" || typeof document === "undefined") {
|
|
@@ -15386,6 +15726,8 @@ function TaskGanttChartInner(props, ref) {
|
|
|
15386
15726
|
{
|
|
15387
15727
|
tasks: normalizedTasks,
|
|
15388
15728
|
rowHeight: effectiveRowHeight,
|
|
15729
|
+
rowTops: compositeRowLayout.tops,
|
|
15730
|
+
rowHeights: compositeRowLayout.heights,
|
|
15389
15731
|
headerHeight,
|
|
15390
15732
|
taskListWidth,
|
|
15391
15733
|
onTasksChange: handleTaskChange,
|
|
@@ -15580,6 +15922,8 @@ function TaskGanttChartInner(props, ref) {
|
|
|
15580
15922
|
gridWidth: renderGridWidth,
|
|
15581
15923
|
totalHeight: totalGridHeight,
|
|
15582
15924
|
rowIndexByTaskId: visibleTaskIndexMap,
|
|
15925
|
+
rowTops: compositeRowLayout.tops,
|
|
15926
|
+
rowHeights: compositeRowLayout.heights,
|
|
15583
15927
|
dragOverrides: dependencyOverrides,
|
|
15584
15928
|
selectedDep: selectedChip,
|
|
15585
15929
|
businessDays,
|
|
@@ -15666,10 +16010,10 @@ function TaskGanttChartInner(props, ref) {
|
|
|
15666
16010
|
{
|
|
15667
16011
|
style: {
|
|
15668
16012
|
position: "absolute",
|
|
15669
|
-
top: `${index
|
|
16013
|
+
top: `${compositeRowLayout.tops[index]}px`,
|
|
15670
16014
|
left: 0,
|
|
15671
16015
|
right: 0,
|
|
15672
|
-
height: `${
|
|
16016
|
+
height: `${compositeRowLayout.heights[index]}px`
|
|
15673
16017
|
},
|
|
15674
16018
|
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
15675
16019
|
TaskRow_default,
|
|
@@ -15677,7 +16021,9 @@ function TaskGanttChartInner(props, ref) {
|
|
|
15677
16021
|
task,
|
|
15678
16022
|
monthStart,
|
|
15679
16023
|
dayWidth,
|
|
15680
|
-
rowHeight:
|
|
16024
|
+
rowHeight: compositeRowLayout.heights[index],
|
|
16025
|
+
compactDetail: compositeRowLayout.heights[index] < effectiveRowHeight,
|
|
16026
|
+
compositeParentColor: task.parentId ? compositeParentsById.get(task.parentId)?.color : void 0,
|
|
15681
16027
|
onTasksChange: handleTaskChange,
|
|
15682
16028
|
onDragStateChange: (state) => {
|
|
15683
16029
|
if (state.isDragging) {
|
|
@@ -15714,7 +16060,10 @@ function TaskGanttChartInner(props, ref) {
|
|
|
15714
16060
|
isDependencyDragActive: dependencyCreationDrag !== null,
|
|
15715
16061
|
viewMode,
|
|
15716
16062
|
showTaskDateLabels,
|
|
15717
|
-
showTaskNames
|
|
16063
|
+
showTaskNames,
|
|
16064
|
+
showCompositeSegments,
|
|
16065
|
+
onCompositeToggle: task.composite ? (source) => handleCompositeBarToggle(task.id, source) : void 0,
|
|
16066
|
+
compositeExpanded: task.composite ? !collapsedParentIds.has(task.id) : void 0
|
|
15718
16067
|
}
|
|
15719
16068
|
)
|
|
15720
16069
|
},
|
|
@@ -15727,6 +16076,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
15727
16076
|
rowHeight: effectiveRowHeight,
|
|
15728
16077
|
variant: "chart",
|
|
15729
16078
|
startIndex: visibleTasks.length,
|
|
16079
|
+
startTop: compositeRowLayout.totalHeight,
|
|
15730
16080
|
chartDayWidth: dayWidth,
|
|
15731
16081
|
chartStartDayOffset: todayInRange ? Math.max(0, todayIndex + Math.floor(Number.isFinite(skeletonStartOffsetDays) ? skeletonStartOffsetDays : 0)) : 0,
|
|
15732
16082
|
chartStartJitterDays: skeletonStartJitterDays
|