gantt-lib 0.17.2 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +95 -3
- package/dist/index.d.ts +95 -3
- package/dist/index.js +1058 -470
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1063 -471
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +15 -44
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
"use client";
|
|
2
4
|
var __defProp = Object.defineProperty;
|
|
3
5
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -23,6 +25,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
23
25
|
// src/utils/dateUtils.ts
|
|
24
26
|
var dateUtils_exports = {};
|
|
25
27
|
__export(dateUtils_exports, {
|
|
28
|
+
createDateKey: () => createDateKey,
|
|
29
|
+
createIsWeekendPredicate: () => createIsWeekendPredicate,
|
|
26
30
|
formatDateLabel: () => formatDateLabel,
|
|
27
31
|
getDayOffset: () => getDayOffset,
|
|
28
32
|
getMonthBlocks: () => getMonthBlocks,
|
|
@@ -37,7 +41,7 @@ __export(dateUtils_exports, {
|
|
|
37
41
|
normalizeTaskDates: () => normalizeTaskDates,
|
|
38
42
|
parseUTCDate: () => parseUTCDate
|
|
39
43
|
});
|
|
40
|
-
var parseUTCDate, getMonthDays, getDayOffset, isToday, isWeekend, getMultiMonthDays, getMonthSpans, formatDateLabel, getWeekBlocks, getWeekSpans, getMonthBlocks, getYearSpans, normalizeTaskDates;
|
|
44
|
+
var parseUTCDate, getMonthDays, getDayOffset, isToday, isWeekend, createDateKey, createIsWeekendPredicate, getMultiMonthDays, getMonthSpans, formatDateLabel, getWeekBlocks, getWeekSpans, getMonthBlocks, getYearSpans, normalizeTaskDates;
|
|
41
45
|
var init_dateUtils = __esm({
|
|
42
46
|
"src/utils/dateUtils.ts"() {
|
|
43
47
|
"use strict";
|
|
@@ -94,6 +98,41 @@ var init_dateUtils = __esm({
|
|
|
94
98
|
const day = date.getUTCDay();
|
|
95
99
|
return day === 0 || day === 6;
|
|
96
100
|
};
|
|
101
|
+
createDateKey = (date) => {
|
|
102
|
+
return `${date.getUTCFullYear()}-${date.getUTCMonth()}-${date.getUTCDate()}`;
|
|
103
|
+
};
|
|
104
|
+
createIsWeekendPredicate = (config) => {
|
|
105
|
+
const { weekends, workdays, isWeekend: customPredicate } = config;
|
|
106
|
+
if (customPredicate) {
|
|
107
|
+
return customPredicate;
|
|
108
|
+
}
|
|
109
|
+
if (workdays && workdays.length > 0) {
|
|
110
|
+
const workdaySet = new Set(workdays.map(createDateKey));
|
|
111
|
+
return (date) => {
|
|
112
|
+
const key = createDateKey(date);
|
|
113
|
+
if (workdaySet.has(key)) {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
const dayOfWeek = date.getUTCDay();
|
|
117
|
+
return dayOfWeek === 0 || dayOfWeek === 6;
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
if (weekends && weekends.length > 0) {
|
|
121
|
+
const weekendSet = new Set(weekends.map(createDateKey));
|
|
122
|
+
return (date) => {
|
|
123
|
+
const key = createDateKey(date);
|
|
124
|
+
if (weekendSet.has(key)) {
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
const dayOfWeek = date.getUTCDay();
|
|
128
|
+
return dayOfWeek === 0 || dayOfWeek === 6;
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
return (date) => {
|
|
132
|
+
const dayOfWeek = date.getUTCDay();
|
|
133
|
+
return dayOfWeek === 0 || dayOfWeek === 6;
|
|
134
|
+
};
|
|
135
|
+
};
|
|
97
136
|
getMultiMonthDays = (tasks) => {
|
|
98
137
|
if (!tasks || tasks.length === 0) {
|
|
99
138
|
return getMonthDays(/* @__PURE__ */ new Date());
|
|
@@ -817,7 +856,8 @@ var TimeScaleHeader = ({
|
|
|
817
856
|
days,
|
|
818
857
|
dayWidth,
|
|
819
858
|
headerHeight,
|
|
820
|
-
viewMode = "day"
|
|
859
|
+
viewMode = "day",
|
|
860
|
+
isCustomWeekend
|
|
821
861
|
}) => {
|
|
822
862
|
const monthSpans = useMemo(() => getMonthSpans(days), [days]);
|
|
823
863
|
const rowHeight = headerHeight / 2;
|
|
@@ -981,12 +1021,12 @@ var TimeScaleHeader = ({
|
|
|
981
1021
|
) : (
|
|
982
1022
|
// Day-view row 2: individual day numbers (existing code)
|
|
983
1023
|
days.map((day, index) => {
|
|
984
|
-
const
|
|
1024
|
+
const isWeekendDay = isCustomWeekend ? isCustomWeekend(day) : day.getUTCDay() === 0 || day.getUTCDay() === 6;
|
|
985
1025
|
const prevDay = days[index - 1];
|
|
986
|
-
const isMonthBoundary = index > 0 && prevDay && prevDay.
|
|
1026
|
+
const isMonthBoundary = index > 0 && prevDay && prevDay.getUTCMonth() !== day.getUTCMonth();
|
|
987
1027
|
const now = /* @__PURE__ */ new Date();
|
|
988
1028
|
const isTodayDate = day.getUTCFullYear() === now.getFullYear() && day.getUTCMonth() === now.getMonth() && day.getUTCDate() === now.getDate();
|
|
989
|
-
return /* @__PURE__ */ jsx("div", { className: `gantt-tsh-dayCell ${
|
|
1029
|
+
return /* @__PURE__ */ jsx("div", { className: `gantt-tsh-dayCell ${isWeekendDay ? "gantt-tsh-weekendDay" : ""} ${isTodayDate ? "gantt-tsh-today" : ""}`, children: /* @__PURE__ */ jsx("span", { className: "gantt-tsh-dayLabel", children: format(day, "d") }) }, `day-${index}`);
|
|
990
1030
|
})
|
|
991
1031
|
)
|
|
992
1032
|
}
|
|
@@ -1079,14 +1119,13 @@ var calculateGridLines = (dateRange, dayWidth) => {
|
|
|
1079
1119
|
}
|
|
1080
1120
|
return lines;
|
|
1081
1121
|
};
|
|
1082
|
-
var calculateWeekendBlocks = (dateRange, dayWidth) => {
|
|
1122
|
+
var calculateWeekendBlocks = (dateRange, dayWidth, isCustomWeekend) => {
|
|
1083
1123
|
const blocks = [];
|
|
1084
1124
|
let inWeekend = false;
|
|
1085
1125
|
let weekendStartIndex = -1;
|
|
1086
1126
|
for (let i = 0; i < dateRange.length; i++) {
|
|
1087
1127
|
const date = dateRange[i];
|
|
1088
|
-
const
|
|
1089
|
-
const isWeekend3 = dayOfWeek === 0 || dayOfWeek === 6;
|
|
1128
|
+
const isWeekend3 = isCustomWeekend ? isCustomWeekend(date) : date.getUTCDay() === 0 || date.getUTCDay() === 6;
|
|
1090
1129
|
if (isWeekend3 && !inWeekend) {
|
|
1091
1130
|
inWeekend = true;
|
|
1092
1131
|
weekendStartIndex = i;
|
|
@@ -1902,10 +1941,10 @@ import React4, { useMemo as useMemo4 } from "react";
|
|
|
1902
1941
|
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1903
1942
|
var arePropsEqual2 = (prevProps, nextProps) => {
|
|
1904
1943
|
return prevProps.dayWidth === nextProps.dayWidth && prevProps.dateRange.length === nextProps.dateRange.length && prevProps.totalHeight === nextProps.totalHeight && // skip re-render only when totalHeight unchanged
|
|
1905
|
-
prevProps.viewMode === nextProps.viewMode;
|
|
1944
|
+
prevProps.viewMode === nextProps.viewMode && prevProps.isCustomWeekend === nextProps.isCustomWeekend;
|
|
1906
1945
|
};
|
|
1907
1946
|
var GridBackground = React4.memo(
|
|
1908
|
-
({ dateRange, dayWidth, totalHeight, viewMode = "day" }) => {
|
|
1947
|
+
({ dateRange, dayWidth, totalHeight, viewMode = "day", isCustomWeekend }) => {
|
|
1909
1948
|
const weekGridLines = useMemo4(() => {
|
|
1910
1949
|
if (viewMode !== "week") return [];
|
|
1911
1950
|
return calculateWeekGridLines(dateRange, dayWidth);
|
|
@@ -1920,8 +1959,8 @@ var GridBackground = React4.memo(
|
|
|
1920
1959
|
}, [dateRange, dayWidth, viewMode]);
|
|
1921
1960
|
const weekendBlocks = useMemo4(() => {
|
|
1922
1961
|
if (viewMode === "week" || viewMode === "month") return [];
|
|
1923
|
-
return calculateWeekendBlocks(dateRange, dayWidth);
|
|
1924
|
-
}, [dateRange, dayWidth, viewMode]);
|
|
1962
|
+
return calculateWeekendBlocks(dateRange, dayWidth, isCustomWeekend);
|
|
1963
|
+
}, [dateRange, dayWidth, viewMode, isCustomWeekend]);
|
|
1925
1964
|
const gridWidth = useMemo4(() => {
|
|
1926
1965
|
return Math.round(dateRange.length * dayWidth);
|
|
1927
1966
|
}, [dateRange.length, dayWidth]);
|
|
@@ -2391,7 +2430,13 @@ var PopoverContent = ({
|
|
|
2391
2430
|
|
|
2392
2431
|
// src/components/TaskList/TaskListRow.tsx
|
|
2393
2432
|
init_dateUtils();
|
|
2394
|
-
import React9, {
|
|
2433
|
+
import React9, {
|
|
2434
|
+
useState as useState4,
|
|
2435
|
+
useRef as useRef4,
|
|
2436
|
+
useEffect as useEffect4,
|
|
2437
|
+
useCallback as useCallback4,
|
|
2438
|
+
useMemo as useMemo7
|
|
2439
|
+
} from "react";
|
|
2395
2440
|
|
|
2396
2441
|
// src/components/ui/Input.tsx
|
|
2397
2442
|
import React6 from "react";
|
|
@@ -2415,6 +2460,7 @@ import { useState as useState3, useCallback as useCallback3, useEffect as useEff
|
|
|
2415
2460
|
import { format as format3, isValid, parse, addDays, addMonths as addMonths2, addYears, subMonths as subMonths2, subYears, subDays } from "date-fns";
|
|
2416
2461
|
|
|
2417
2462
|
// src/components/ui/Calendar.tsx
|
|
2463
|
+
init_dateUtils();
|
|
2418
2464
|
import {
|
|
2419
2465
|
useState as useState2,
|
|
2420
2466
|
useRef as useRef2,
|
|
@@ -2437,11 +2483,11 @@ import {
|
|
|
2437
2483
|
} from "date-fns";
|
|
2438
2484
|
import { ru as ru2 } from "date-fns/locale";
|
|
2439
2485
|
import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
2440
|
-
function getDayClassName(day, selected) {
|
|
2486
|
+
function getDayClassName(day, selected, isWeekendProp) {
|
|
2441
2487
|
const classes = ["gantt-day-btn"];
|
|
2442
2488
|
if (selected && isSameDay(day, selected)) classes.push("selected");
|
|
2443
2489
|
if (isToday2(day)) classes.push("today");
|
|
2444
|
-
if (isWeekend2(day)) classes.push("weekend");
|
|
2490
|
+
if (isWeekendProp ? isWeekendProp(day) : isWeekend2(day)) classes.push("weekend");
|
|
2445
2491
|
if (isBefore(day, startOfDay(/* @__PURE__ */ new Date())) && !isToday2(day)) classes.push("past");
|
|
2446
2492
|
return classes.join(" ");
|
|
2447
2493
|
}
|
|
@@ -2450,9 +2496,22 @@ var Calendar = ({
|
|
|
2450
2496
|
onSelect,
|
|
2451
2497
|
initialDate,
|
|
2452
2498
|
mode = "single",
|
|
2453
|
-
disabled = false
|
|
2499
|
+
disabled = false,
|
|
2500
|
+
isWeekend: isWeekendProp,
|
|
2501
|
+
weekends,
|
|
2502
|
+
workdays
|
|
2454
2503
|
}) => {
|
|
2455
2504
|
const scrollRef = useRef2(null);
|
|
2505
|
+
const derivedWeekendPredicate = useMemo6(() => {
|
|
2506
|
+
if (isWeekendProp) return isWeekendProp;
|
|
2507
|
+
if (weekends || workdays) {
|
|
2508
|
+
return createIsWeekendPredicate({
|
|
2509
|
+
weekends: weekends ?? [],
|
|
2510
|
+
workdays: workdays ?? []
|
|
2511
|
+
});
|
|
2512
|
+
}
|
|
2513
|
+
return void 0;
|
|
2514
|
+
}, [isWeekendProp, weekends, workdays]);
|
|
2456
2515
|
const initialMonth = useMemo6(
|
|
2457
2516
|
() => startOfMonth(initialDate ?? selected ?? /* @__PURE__ */ new Date()),
|
|
2458
2517
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
@@ -2506,11 +2565,13 @@ var Calendar = ({
|
|
|
2506
2565
|
const emptyDays = (getDay(firstDay) + 6) % 7;
|
|
2507
2566
|
const monthKey = format2(month, "yyyy-MM");
|
|
2508
2567
|
const monthLabel = format2(month, "LLLL yyyy", { locale: ru2 });
|
|
2568
|
+
const weekdayLabels = ["\u041F\u043D", "\u0412\u0442", "\u0421\u0440", "\u0427\u0442", "\u041F\u0442", "\u0421\u0431", "\u0412\u0441"];
|
|
2569
|
+
const weekdayHeaders = weekdayLabels.map((label, i) => /* @__PURE__ */ jsx9("div", { className: "gantt-cal-weekday", children: label }, `wd-${i}`));
|
|
2509
2570
|
const emptyCells = Array.from({ length: emptyDays }, (_, i) => /* @__PURE__ */ jsx9("div", { className: "gantt-cal-empty-day" }, `e-${i}`));
|
|
2510
2571
|
const dayCells = Array.from({ length: totalDays }, (_, i) => {
|
|
2511
2572
|
const dayNum = i + 1;
|
|
2512
|
-
const day = new Date(month.getFullYear(), month.getMonth(), dayNum);
|
|
2513
|
-
const className = getDayClassName(day, selected);
|
|
2573
|
+
const day = new Date(Date.UTC(month.getFullYear(), month.getMonth(), dayNum));
|
|
2574
|
+
const className = getDayClassName(day, selected, derivedWeekendPredicate);
|
|
2514
2575
|
return /* @__PURE__ */ jsx9(
|
|
2515
2576
|
"button",
|
|
2516
2577
|
{
|
|
@@ -2519,7 +2580,7 @@ var Calendar = ({
|
|
|
2519
2580
|
disabled,
|
|
2520
2581
|
onClick: () => {
|
|
2521
2582
|
if (!disabled && onSelect) {
|
|
2522
|
-
onSelect(new Date(month.getFullYear(), month.getMonth(), dayNum));
|
|
2583
|
+
onSelect(new Date(Date.UTC(month.getFullYear(), month.getMonth(), dayNum)));
|
|
2523
2584
|
}
|
|
2524
2585
|
},
|
|
2525
2586
|
children: dayNum
|
|
@@ -2530,12 +2591,13 @@ var Calendar = ({
|
|
|
2530
2591
|
return /* @__PURE__ */ jsxs6("div", { className: "gantt-cal-month", "data-month": monthKey, children: [
|
|
2531
2592
|
/* @__PURE__ */ jsx9("div", { className: "gantt-cal-month-header", children: monthLabel }),
|
|
2532
2593
|
/* @__PURE__ */ jsxs6("div", { className: "gantt-cal-month-days", children: [
|
|
2594
|
+
weekdayHeaders,
|
|
2533
2595
|
emptyCells,
|
|
2534
2596
|
dayCells
|
|
2535
2597
|
] })
|
|
2536
2598
|
] }, monthKey);
|
|
2537
2599
|
},
|
|
2538
|
-
[selected, onSelect, disabled]
|
|
2600
|
+
[selected, onSelect, disabled, derivedWeekendPredicate]
|
|
2539
2601
|
);
|
|
2540
2602
|
const renderedMonths = useMemo6(
|
|
2541
2603
|
() => months.map(renderMonth),
|
|
@@ -2559,7 +2621,10 @@ var DatePicker = ({
|
|
|
2559
2621
|
placeholder = "Pick a date",
|
|
2560
2622
|
portal = true,
|
|
2561
2623
|
className,
|
|
2562
|
-
disabled = false
|
|
2624
|
+
disabled = false,
|
|
2625
|
+
weekends,
|
|
2626
|
+
workdays,
|
|
2627
|
+
isWeekend: isWeekend3
|
|
2563
2628
|
}) => {
|
|
2564
2629
|
const [open, setOpen] = useState3(false);
|
|
2565
2630
|
const [inputValue, setInputValue] = useState3("");
|
|
@@ -2779,7 +2844,10 @@ var DatePicker = ({
|
|
|
2779
2844
|
mode: "single",
|
|
2780
2845
|
selected: selectedDate,
|
|
2781
2846
|
onSelect: handleCalendarSelect,
|
|
2782
|
-
initialDate: selectedDate
|
|
2847
|
+
initialDate: selectedDate,
|
|
2848
|
+
weekends,
|
|
2849
|
+
workdays,
|
|
2850
|
+
isWeekend: isWeekend3
|
|
2783
2851
|
}
|
|
2784
2852
|
)
|
|
2785
2853
|
]
|
|
@@ -2828,18 +2896,49 @@ var DAY_MS2 = 24 * 60 * 60 * 1e3;
|
|
|
2828
2896
|
var getInclusiveDurationDays = (startDate, endDate) => {
|
|
2829
2897
|
const start = parseUTCDate(startDate);
|
|
2830
2898
|
const end = parseUTCDate(endDate);
|
|
2831
|
-
return Math.max(
|
|
2899
|
+
return Math.max(
|
|
2900
|
+
1,
|
|
2901
|
+
Math.round((end.getTime() - start.getTime()) / DAY_MS2) + 1
|
|
2902
|
+
);
|
|
2832
2903
|
};
|
|
2833
2904
|
var getEndDateFromDuration = (startDate, durationDays) => {
|
|
2834
2905
|
const start = parseUTCDate(startDate);
|
|
2835
2906
|
return new Date(start.getTime() + (durationDays - 1) * DAY_MS2).toISOString().split("T")[0];
|
|
2836
2907
|
};
|
|
2837
|
-
var TrashIcon = () => /* @__PURE__ */ jsxs9(
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2908
|
+
var TrashIcon = () => /* @__PURE__ */ jsxs9(
|
|
2909
|
+
"svg",
|
|
2910
|
+
{
|
|
2911
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2912
|
+
width: "12",
|
|
2913
|
+
height: "12",
|
|
2914
|
+
viewBox: "0 0 24 24",
|
|
2915
|
+
fill: "none",
|
|
2916
|
+
stroke: "currentColor",
|
|
2917
|
+
strokeWidth: "2",
|
|
2918
|
+
strokeLinecap: "round",
|
|
2919
|
+
strokeLinejoin: "round",
|
|
2920
|
+
children: [
|
|
2921
|
+
/* @__PURE__ */ jsx12("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6" }),
|
|
2922
|
+
/* @__PURE__ */ jsx12("path", { d: "M3 6h18" }),
|
|
2923
|
+
/* @__PURE__ */ jsx12("path", { d: "M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" })
|
|
2924
|
+
]
|
|
2925
|
+
}
|
|
2926
|
+
);
|
|
2927
|
+
var PlusIcon = () => /* @__PURE__ */ jsx12(
|
|
2928
|
+
"svg",
|
|
2929
|
+
{
|
|
2930
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2931
|
+
width: "14",
|
|
2932
|
+
height: "14",
|
|
2933
|
+
viewBox: "0 0 24 24",
|
|
2934
|
+
fill: "none",
|
|
2935
|
+
stroke: "currentColor",
|
|
2936
|
+
strokeWidth: "2",
|
|
2937
|
+
strokeLinecap: "round",
|
|
2938
|
+
strokeLinejoin: "round",
|
|
2939
|
+
children: /* @__PURE__ */ jsx12("path", { d: "M12 5v14M5 12h14" })
|
|
2940
|
+
}
|
|
2941
|
+
);
|
|
2843
2942
|
var DragHandleIcon = () => /* @__PURE__ */ jsxs9("svg", { width: "10", height: "14", viewBox: "0 0 10 14", fill: "currentColor", children: [
|
|
2844
2943
|
/* @__PURE__ */ jsx12("circle", { cx: "2", cy: "2", r: "1.5" }),
|
|
2845
2944
|
/* @__PURE__ */ jsx12("circle", { cx: "8", cy: "2", r: "1.5" }),
|
|
@@ -2848,51 +2947,94 @@ var DragHandleIcon = () => /* @__PURE__ */ jsxs9("svg", { width: "10", height: "
|
|
|
2848
2947
|
/* @__PURE__ */ jsx12("circle", { cx: "2", cy: "12", r: "1.5" }),
|
|
2849
2948
|
/* @__PURE__ */ jsx12("circle", { cx: "8", cy: "12", r: "1.5" })
|
|
2850
2949
|
] });
|
|
2851
|
-
var ChevronRightIcon = () => /* @__PURE__ */ jsx12(
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2950
|
+
var ChevronRightIcon = () => /* @__PURE__ */ jsx12(
|
|
2951
|
+
"svg",
|
|
2952
|
+
{
|
|
2953
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2954
|
+
width: "14",
|
|
2955
|
+
height: "14",
|
|
2956
|
+
viewBox: "0 0 24 24",
|
|
2957
|
+
fill: "none",
|
|
2958
|
+
stroke: "currentColor",
|
|
2959
|
+
strokeWidth: "2",
|
|
2960
|
+
strokeLinecap: "round",
|
|
2961
|
+
strokeLinejoin: "round",
|
|
2962
|
+
children: /* @__PURE__ */ jsx12("path", { d: "m9 18 6-6-6-6" })
|
|
2963
|
+
}
|
|
2964
|
+
);
|
|
2965
|
+
var ArrowLeft = () => /* @__PURE__ */ jsxs9(
|
|
2966
|
+
"svg",
|
|
2967
|
+
{
|
|
2968
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2969
|
+
width: "16",
|
|
2970
|
+
height: "16",
|
|
2971
|
+
viewBox: "0 0 24 24",
|
|
2972
|
+
fill: "none",
|
|
2973
|
+
stroke: "currentColor",
|
|
2974
|
+
strokeWidth: "2",
|
|
2975
|
+
strokeLinecap: "round",
|
|
2976
|
+
strokeLinejoin: "round",
|
|
2977
|
+
children: [
|
|
2978
|
+
/* @__PURE__ */ jsx12("path", { d: "m12 19-7-7 7-7" }),
|
|
2979
|
+
/* @__PURE__ */ jsx12("path", { d: "M19 12H5" })
|
|
2980
|
+
]
|
|
2981
|
+
}
|
|
2982
|
+
);
|
|
2983
|
+
var ArrowRight = () => /* @__PURE__ */ jsxs9(
|
|
2984
|
+
"svg",
|
|
2985
|
+
{
|
|
2986
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2987
|
+
width: "16",
|
|
2988
|
+
height: "16",
|
|
2989
|
+
viewBox: "0 0 24 24",
|
|
2990
|
+
fill: "none",
|
|
2991
|
+
stroke: "currentColor",
|
|
2992
|
+
strokeWidth: "2",
|
|
2993
|
+
strokeLinecap: "round",
|
|
2994
|
+
strokeLinejoin: "round",
|
|
2995
|
+
children: [
|
|
2996
|
+
/* @__PURE__ */ jsx12("path", { d: "M5 12h14" }),
|
|
2997
|
+
/* @__PURE__ */ jsx12("path", { d: "m12 5 7 7-7 7" })
|
|
2998
|
+
]
|
|
2999
|
+
}
|
|
3000
|
+
);
|
|
2857
3001
|
var HierarchyButton = ({
|
|
2858
3002
|
isChild,
|
|
2859
|
-
|
|
2860
|
-
rowIndex,
|
|
3003
|
+
rowIndex: _rowIndex,
|
|
2861
3004
|
onPromote,
|
|
2862
3005
|
onDemote
|
|
2863
3006
|
}) => {
|
|
2864
3007
|
const canPromote = isChild && onPromote;
|
|
2865
|
-
const canDemote =
|
|
2866
|
-
if (!canPromote && !canDemote)
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
3008
|
+
const canDemote = !!onDemote;
|
|
3009
|
+
if (!canPromote && !canDemote) return null;
|
|
3010
|
+
return /* @__PURE__ */ jsxs9(Fragment2, { children: [
|
|
3011
|
+
canPromote && /* @__PURE__ */ jsx12(
|
|
3012
|
+
"button",
|
|
3013
|
+
{
|
|
3014
|
+
type: "button",
|
|
3015
|
+
className: "gantt-tl-name-action-btn gantt-tl-action-hierarchy",
|
|
3016
|
+
onClick: (e) => {
|
|
3017
|
+
e.stopPropagation();
|
|
3018
|
+
onPromote(e);
|
|
3019
|
+
},
|
|
3020
|
+
title: "\u041F\u043E\u0432\u044B\u0441\u0438\u0442\u044C \u0443\u0440\u043E\u0432\u0435\u043D\u044C",
|
|
3021
|
+
children: /* @__PURE__ */ jsx12(ArrowLeft, {})
|
|
3022
|
+
}
|
|
3023
|
+
),
|
|
3024
|
+
canDemote && /* @__PURE__ */ jsx12(
|
|
3025
|
+
"button",
|
|
3026
|
+
{
|
|
3027
|
+
type: "button",
|
|
3028
|
+
className: "gantt-tl-name-action-btn gantt-tl-action-hierarchy",
|
|
3029
|
+
onClick: (e) => {
|
|
3030
|
+
e.stopPropagation();
|
|
3031
|
+
onDemote(e);
|
|
3032
|
+
},
|
|
3033
|
+
title: "\u041F\u043E\u043D\u0438\u0437\u0438\u0442\u044C \u0443\u0440\u043E\u0432\u0435\u043D\u044C",
|
|
3034
|
+
children: /* @__PURE__ */ jsx12(ArrowRight, {})
|
|
3035
|
+
}
|
|
3036
|
+
)
|
|
2885
3037
|
] });
|
|
2886
|
-
return /* @__PURE__ */ jsx12(
|
|
2887
|
-
"button",
|
|
2888
|
-
{
|
|
2889
|
-
type: "button",
|
|
2890
|
-
className: "gantt-tl-name-action-btn gantt-tl-action-hierarchy",
|
|
2891
|
-
onClick: handleClick,
|
|
2892
|
-
title,
|
|
2893
|
-
children: canPromote ? /* @__PURE__ */ jsx12(ArrowLeft, {}) : /* @__PURE__ */ jsx12(ArrowRight, {})
|
|
2894
|
-
}
|
|
2895
|
-
);
|
|
2896
3038
|
};
|
|
2897
3039
|
var DepChip = ({
|
|
2898
3040
|
lag,
|
|
@@ -2924,71 +3066,91 @@ var DepChip = ({
|
|
|
2924
3066
|
const nextOpen = !popoverOpen;
|
|
2925
3067
|
setPopoverOpen(nextOpen);
|
|
2926
3068
|
if (nextOpen) {
|
|
2927
|
-
onChipSelect?.({
|
|
3069
|
+
onChipSelect?.({
|
|
3070
|
+
successorId: taskId,
|
|
3071
|
+
predecessorId: dep.taskId,
|
|
3072
|
+
linkType: dep.type
|
|
3073
|
+
});
|
|
2928
3074
|
onScrollToTask?.(dep.taskId);
|
|
2929
3075
|
} else {
|
|
2930
3076
|
onChipSelect?.(null);
|
|
2931
3077
|
}
|
|
2932
3078
|
};
|
|
2933
|
-
const handleOpenChange = useCallback4(
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
3079
|
+
const handleOpenChange = useCallback4(
|
|
3080
|
+
(open) => {
|
|
3081
|
+
setPopoverOpen(open);
|
|
3082
|
+
if (!open) {
|
|
3083
|
+
onChipSelect?.(null);
|
|
3084
|
+
}
|
|
3085
|
+
},
|
|
3086
|
+
[onChipSelect]
|
|
3087
|
+
);
|
|
2939
3088
|
const handleTrashClick = (e) => {
|
|
2940
3089
|
e.stopPropagation();
|
|
2941
3090
|
onRemoveDependency?.(taskId, dep.taskId, dep.type);
|
|
2942
3091
|
onChipSelectClear();
|
|
2943
3092
|
setPopoverOpen(false);
|
|
2944
3093
|
};
|
|
2945
|
-
const handleLagChange = useCallback4(
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
newStart
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
3094
|
+
const handleLagChange = useCallback4(
|
|
3095
|
+
(newLag) => {
|
|
3096
|
+
if (!onTasksChange || !allTasks) return;
|
|
3097
|
+
const taskById = new Map(allTasks.map((t) => [t.id, t]));
|
|
3098
|
+
const predecessor = taskById.get(dep.taskId);
|
|
3099
|
+
if (!predecessor) return;
|
|
3100
|
+
const predStart = parseUTCDate(predecessor.startDate);
|
|
3101
|
+
const predEnd = parseUTCDate(predecessor.endDate);
|
|
3102
|
+
const origStart = parseUTCDate(task.startDate);
|
|
3103
|
+
const origEnd = parseUTCDate(task.endDate);
|
|
3104
|
+
const durationMs = origEnd.getTime() - origStart.getTime();
|
|
3105
|
+
const constraintDate = calculateSuccessorDate(
|
|
3106
|
+
predStart,
|
|
3107
|
+
predEnd,
|
|
3108
|
+
dep.type,
|
|
3109
|
+
newLag
|
|
3110
|
+
);
|
|
3111
|
+
let newStart, newEnd;
|
|
3112
|
+
if (dep.type === "FS" || dep.type === "SS") {
|
|
3113
|
+
newStart = constraintDate;
|
|
3114
|
+
newEnd = new Date(constraintDate.getTime() + durationMs);
|
|
3115
|
+
} else {
|
|
3116
|
+
newEnd = constraintDate;
|
|
3117
|
+
newStart = new Date(constraintDate.getTime() - durationMs);
|
|
3118
|
+
}
|
|
3119
|
+
onTasksChange([
|
|
3120
|
+
{
|
|
3121
|
+
...task,
|
|
3122
|
+
startDate: newStart.toISOString().split("T")[0],
|
|
3123
|
+
endDate: newEnd.toISOString().split("T")[0]
|
|
3124
|
+
}
|
|
3125
|
+
]);
|
|
3126
|
+
},
|
|
3127
|
+
[dep, task, allTasks, onTasksChange]
|
|
3128
|
+
);
|
|
3129
|
+
const handleInputCommit = useCallback4(
|
|
3130
|
+
(raw) => {
|
|
3131
|
+
if (raw === "") {
|
|
3132
|
+
handleLagChange(0);
|
|
3133
|
+
return;
|
|
3134
|
+
}
|
|
3135
|
+
const parsed = parseInt(raw, 10);
|
|
3136
|
+
const effectiveLag2 = lag ?? 0;
|
|
3137
|
+
if (isNaN(parsed)) {
|
|
3138
|
+
const abs = Math.abs(effectiveLag2);
|
|
3139
|
+
setInputAbs(abs === 0 ? "" : String(abs));
|
|
3140
|
+
return;
|
|
3141
|
+
}
|
|
3142
|
+
let newLag;
|
|
3143
|
+
if (parsed === 0) {
|
|
3144
|
+
newLag = 0;
|
|
3145
|
+
} else if (dep.type === "SF") {
|
|
3146
|
+
newLag = -Math.abs(parsed);
|
|
3147
|
+
} else {
|
|
3148
|
+
newLag = parsed;
|
|
3149
|
+
}
|
|
3150
|
+
if (newLag !== effectiveLag2) handleLagChange(newLag);
|
|
3151
|
+
},
|
|
3152
|
+
[lag, dep.type, handleLagChange]
|
|
3153
|
+
);
|
|
2992
3154
|
const Icon = LINK_TYPE_ICONS[dep.type];
|
|
2993
3155
|
const depName = predecessorName ?? dep.taskId;
|
|
2994
3156
|
const effectiveLag = lag ?? 0;
|
|
@@ -3027,67 +3189,92 @@ var DepChip = ({
|
|
|
3027
3189
|
]
|
|
3028
3190
|
}
|
|
3029
3191
|
) }),
|
|
3030
|
-
/* @__PURE__ */ jsx12(
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3192
|
+
/* @__PURE__ */ jsx12(
|
|
3193
|
+
PopoverContent,
|
|
3194
|
+
{
|
|
3195
|
+
className: "gantt-tl-dep-edit-popover",
|
|
3196
|
+
portal: true,
|
|
3197
|
+
align: "start",
|
|
3198
|
+
children: /* @__PURE__ */ jsxs9("div", { onClick: (e) => e.stopPropagation(), children: [
|
|
3199
|
+
/* @__PURE__ */ jsx12("div", { className: "gantt-tl-dep-edit-task", children: task.name }),
|
|
3200
|
+
/* @__PURE__ */ jsxs9("div", { className: "gantt-tl-dep-edit-row", children: [
|
|
3201
|
+
/* @__PURE__ */ jsxs9("span", { className: "gantt-tl-dep-edit-label", children: [
|
|
3202
|
+
actionVerb,
|
|
3203
|
+
preWord ? ` ${preWord}` : ""
|
|
3204
|
+
] }),
|
|
3205
|
+
/* @__PURE__ */ jsx12(
|
|
3206
|
+
"button",
|
|
3207
|
+
{
|
|
3208
|
+
type: "button",
|
|
3209
|
+
className: "gantt-tl-dep-edit-btn",
|
|
3210
|
+
onClick: () => handleLagChange(effectiveLag - 1),
|
|
3211
|
+
children: "\u2212"
|
|
3212
|
+
}
|
|
3213
|
+
),
|
|
3214
|
+
/* @__PURE__ */ jsx12(
|
|
3215
|
+
"input",
|
|
3216
|
+
{
|
|
3217
|
+
type: "number",
|
|
3218
|
+
className: "gantt-tl-dep-edit-input",
|
|
3219
|
+
value: inputAbs,
|
|
3220
|
+
placeholder: zeroPlaceholder,
|
|
3221
|
+
min: "0",
|
|
3222
|
+
onChange: (e) => setInputAbs(e.target.value),
|
|
3223
|
+
onFocus: (e) => e.target.select(),
|
|
3224
|
+
onBlur: (e) => handleInputCommit(e.target.value),
|
|
3225
|
+
onKeyDown: (e) => {
|
|
3226
|
+
if (e.key === "Enter") handleInputCommit(inputAbs);
|
|
3227
|
+
}
|
|
3228
|
+
}
|
|
3229
|
+
),
|
|
3230
|
+
!(dep.type === "SF" && effectiveLag === 0) && /* @__PURE__ */ jsx12(
|
|
3231
|
+
"button",
|
|
3232
|
+
{
|
|
3233
|
+
type: "button",
|
|
3234
|
+
className: "gantt-tl-dep-edit-btn",
|
|
3235
|
+
onClick: () => handleLagChange(effectiveLag + 1),
|
|
3236
|
+
children: "+"
|
|
3237
|
+
}
|
|
3238
|
+
),
|
|
3239
|
+
effectiveLag !== 0 && /* @__PURE__ */ jsx12("span", { children: "\u0434." }),
|
|
3240
|
+
/* @__PURE__ */ jsx12("span", { children: afterWhat })
|
|
3241
|
+
] }),
|
|
3242
|
+
/* @__PURE__ */ jsx12("div", { className: "gantt-tl-dep-edit-pred", children: depName }),
|
|
3243
|
+
!disableDependencyEditing && /* @__PURE__ */ jsxs9(Fragment2, { children: [
|
|
3244
|
+
/* @__PURE__ */ jsx12("hr", { className: "gantt-tl-dep-edit-divider" }),
|
|
3245
|
+
/* @__PURE__ */ jsxs9("div", { className: "gantt-tl-dep-edit-actions", children: [
|
|
3246
|
+
/* @__PURE__ */ jsx12(
|
|
3247
|
+
"button",
|
|
3248
|
+
{
|
|
3249
|
+
type: "button",
|
|
3250
|
+
className: "gantt-tl-dep-edit-close",
|
|
3251
|
+
onClick: () => {
|
|
3252
|
+
setPopoverOpen(false);
|
|
3253
|
+
onChipSelectClear();
|
|
3254
|
+
},
|
|
3255
|
+
children: "\u0417\u0430\u043A\u0440\u044B\u0442\u044C"
|
|
3256
|
+
}
|
|
3257
|
+
),
|
|
3258
|
+
/* @__PURE__ */ jsx12(
|
|
3259
|
+
"button",
|
|
3260
|
+
{
|
|
3261
|
+
type: "button",
|
|
3262
|
+
className: "gantt-tl-dep-edit-delete",
|
|
3263
|
+
onClick: handleTrashClick,
|
|
3264
|
+
children: "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0441\u0432\u044F\u0437\u044C"
|
|
3265
|
+
}
|
|
3266
|
+
)
|
|
3267
|
+
] })
|
|
3268
|
+
] })
|
|
3083
3269
|
] })
|
|
3084
|
-
|
|
3085
|
-
|
|
3270
|
+
}
|
|
3271
|
+
)
|
|
3086
3272
|
] });
|
|
3087
3273
|
};
|
|
3088
3274
|
var toISODate = (value) => {
|
|
3089
3275
|
if (value instanceof Date) return value.toISOString().split("T")[0];
|
|
3090
|
-
if (typeof value === "string" && value.includes("T"))
|
|
3276
|
+
if (typeof value === "string" && value.includes("T"))
|
|
3277
|
+
return value.split("T")[0];
|
|
3091
3278
|
return value;
|
|
3092
3279
|
};
|
|
3093
3280
|
var TaskListRow = React9.memo(
|
|
@@ -3124,13 +3311,20 @@ var TaskListRow = React9.memo(
|
|
|
3124
3311
|
onToggleCollapse,
|
|
3125
3312
|
onPromoteTask,
|
|
3126
3313
|
onDemoteTask,
|
|
3127
|
-
isLastChild = true
|
|
3314
|
+
isLastChild = true,
|
|
3315
|
+
nestingDepth = 0,
|
|
3316
|
+
ancestorContinues = [],
|
|
3317
|
+
weekends,
|
|
3318
|
+
workdays,
|
|
3319
|
+
isWeekend: isWeekend3
|
|
3128
3320
|
}) => {
|
|
3129
3321
|
const [editingName, setEditingName] = useState4(false);
|
|
3130
3322
|
const [nameValue, setNameValue] = useState4("");
|
|
3131
3323
|
const nameInputRef = useRef4(null);
|
|
3132
3324
|
const [editingDuration, setEditingDuration] = useState4(false);
|
|
3133
|
-
const [durationValue, setDurationValue] = useState4(
|
|
3325
|
+
const [durationValue, setDurationValue] = useState4(
|
|
3326
|
+
getInclusiveDurationDays(task.startDate, task.endDate)
|
|
3327
|
+
);
|
|
3134
3328
|
const durationInputRef = useRef4(null);
|
|
3135
3329
|
const [editingProgress, setEditingProgress] = useState4(false);
|
|
3136
3330
|
const [progressValue, setProgressValue] = useState4(0);
|
|
@@ -3140,11 +3334,16 @@ var TaskListRow = React9.memo(
|
|
|
3140
3334
|
const durationConfirmedRef = useRef4(false);
|
|
3141
3335
|
const progressConfirmedRef = useRef4(false);
|
|
3142
3336
|
const autoEditedForRef = useRef4(null);
|
|
3143
|
-
const editTriggerRef = useRef4(
|
|
3337
|
+
const editTriggerRef = useRef4(
|
|
3338
|
+
"doubleclick"
|
|
3339
|
+
);
|
|
3144
3340
|
const [deletePending, setDeletePending] = useState4(false);
|
|
3145
3341
|
const deleteButtonRef = useRef4(null);
|
|
3146
3342
|
const isSelected = selectedTaskId === task.id;
|
|
3147
|
-
const isParent = useMemo7(
|
|
3343
|
+
const isParent = useMemo7(
|
|
3344
|
+
() => isTaskParent(task.id, allTasks),
|
|
3345
|
+
[task.id, allTasks]
|
|
3346
|
+
);
|
|
3148
3347
|
const isChild = task.parentId !== void 0;
|
|
3149
3348
|
const isCollapsed = collapsedParentIds.has(task.id);
|
|
3150
3349
|
const isPicking = selectingPredecessorFor != null;
|
|
@@ -3199,31 +3398,40 @@ var TaskListRow = React9.memo(
|
|
|
3199
3398
|
setEditingName(true);
|
|
3200
3399
|
}
|
|
3201
3400
|
}, [editingTaskId, task.id, disableTaskNameEditing]);
|
|
3202
|
-
const handleNameClick = useCallback4(
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
}, [task.name, disableTaskNameEditing]);
|
|
3216
|
-
const handleRowKeyDown = useCallback4((e) => {
|
|
3217
|
-
if (editingProgress) return;
|
|
3218
|
-
if (!editingName && !disableTaskNameEditing && e.key === "F2") {
|
|
3219
|
-
e.preventDefault();
|
|
3401
|
+
const handleNameClick = useCallback4(
|
|
3402
|
+
(e) => {
|
|
3403
|
+
if (disableTaskNameEditing) return;
|
|
3404
|
+
e.stopPropagation();
|
|
3405
|
+
onRowClick?.(task.id);
|
|
3406
|
+
onScrollToTask?.(task.id);
|
|
3407
|
+
},
|
|
3408
|
+
[task.id, disableTaskNameEditing, onRowClick, onScrollToTask]
|
|
3409
|
+
);
|
|
3410
|
+
const handleNameDoubleClick = useCallback4(
|
|
3411
|
+
(e) => {
|
|
3412
|
+
if (disableTaskNameEditing) return;
|
|
3413
|
+
e.stopPropagation();
|
|
3220
3414
|
nameConfirmedRef.current = false;
|
|
3221
|
-
editTriggerRef.current = "
|
|
3415
|
+
editTriggerRef.current = "doubleclick";
|
|
3222
3416
|
setNameValue(task.name);
|
|
3223
3417
|
setEditingName(true);
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3418
|
+
},
|
|
3419
|
+
[task.name, disableTaskNameEditing]
|
|
3420
|
+
);
|
|
3421
|
+
const handleRowKeyDown = useCallback4(
|
|
3422
|
+
(e) => {
|
|
3423
|
+
if (editingProgress) return;
|
|
3424
|
+
if (!editingName && !disableTaskNameEditing && e.key === "F2") {
|
|
3425
|
+
e.preventDefault();
|
|
3426
|
+
nameConfirmedRef.current = false;
|
|
3427
|
+
editTriggerRef.current = "keypress";
|
|
3428
|
+
setNameValue(task.name);
|
|
3429
|
+
setEditingName(true);
|
|
3430
|
+
return;
|
|
3431
|
+
}
|
|
3432
|
+
},
|
|
3433
|
+
[editingName, disableTaskNameEditing, task.name]
|
|
3434
|
+
);
|
|
3227
3435
|
const handleNameSave = useCallback4(() => {
|
|
3228
3436
|
if (nameConfirmedRef.current) {
|
|
3229
3437
|
nameConfirmedRef.current = false;
|
|
@@ -3237,24 +3445,32 @@ var TaskListRow = React9.memo(
|
|
|
3237
3445
|
const handleNameCancel = useCallback4(() => {
|
|
3238
3446
|
setEditingName(false);
|
|
3239
3447
|
}, []);
|
|
3240
|
-
const handleNameKeyDown = useCallback4(
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3448
|
+
const handleNameKeyDown = useCallback4(
|
|
3449
|
+
(e) => {
|
|
3450
|
+
if (e.key === "Enter") {
|
|
3451
|
+
nameConfirmedRef.current = true;
|
|
3452
|
+
if (nameValue.trim()) {
|
|
3453
|
+
onTasksChange?.([{ ...task, name: nameValue.trim() }]);
|
|
3454
|
+
}
|
|
3455
|
+
setEditingName(false);
|
|
3456
|
+
} else if (e.key === "Escape") {
|
|
3457
|
+
handleNameCancel();
|
|
3245
3458
|
}
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3459
|
+
},
|
|
3460
|
+
[nameValue, task, onTasksChange, handleNameCancel]
|
|
3461
|
+
);
|
|
3462
|
+
const handleDurationClick = useCallback4(
|
|
3463
|
+
(e) => {
|
|
3464
|
+
if (task.locked) return;
|
|
3465
|
+
e.stopPropagation();
|
|
3466
|
+
durationConfirmedRef.current = false;
|
|
3467
|
+
setDurationValue(
|
|
3468
|
+
getInclusiveDurationDays(task.startDate, task.endDate)
|
|
3469
|
+
);
|
|
3470
|
+
setEditingDuration(true);
|
|
3471
|
+
},
|
|
3472
|
+
[task.locked, task.startDate, task.endDate]
|
|
3473
|
+
);
|
|
3258
3474
|
const applyDurationChange = useCallback4((nextDuration) => {
|
|
3259
3475
|
const normalizedDuration = Math.max(1, Math.round(nextDuration) || 1);
|
|
3260
3476
|
setDurationValue(normalizedDuration);
|
|
@@ -3265,34 +3481,59 @@ var TaskListRow = React9.memo(
|
|
|
3265
3481
|
return;
|
|
3266
3482
|
}
|
|
3267
3483
|
const normalizedDuration = Math.max(1, Math.round(durationValue) || 1);
|
|
3268
|
-
onTasksChange?.([
|
|
3484
|
+
onTasksChange?.([
|
|
3485
|
+
{
|
|
3486
|
+
...task,
|
|
3487
|
+
endDate: getEndDateFromDuration(task.startDate, normalizedDuration)
|
|
3488
|
+
}
|
|
3489
|
+
]);
|
|
3269
3490
|
setEditingDuration(false);
|
|
3270
3491
|
}, [durationValue, task, onTasksChange]);
|
|
3271
3492
|
const handleDurationCancel = useCallback4(() => {
|
|
3272
3493
|
setDurationValue(getInclusiveDurationDays(task.startDate, task.endDate));
|
|
3273
3494
|
setEditingDuration(false);
|
|
3274
3495
|
}, [task.startDate, task.endDate]);
|
|
3275
|
-
const handleDurationAdjust = useCallback4(
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3496
|
+
const handleDurationAdjust = useCallback4(
|
|
3497
|
+
(delta) => {
|
|
3498
|
+
applyDurationChange(durationValue + delta);
|
|
3499
|
+
},
|
|
3500
|
+
[applyDurationChange, durationValue]
|
|
3501
|
+
);
|
|
3502
|
+
const handleDurationKeyDown = useCallback4(
|
|
3503
|
+
(e) => {
|
|
3504
|
+
e.stopPropagation();
|
|
3505
|
+
if (e.key === "Enter") {
|
|
3506
|
+
durationConfirmedRef.current = true;
|
|
3507
|
+
const normalizedDuration = Math.max(
|
|
3508
|
+
1,
|
|
3509
|
+
Math.round(durationValue) || 1
|
|
3510
|
+
);
|
|
3511
|
+
onTasksChange?.([
|
|
3512
|
+
{
|
|
3513
|
+
...task,
|
|
3514
|
+
endDate: getEndDateFromDuration(
|
|
3515
|
+
task.startDate,
|
|
3516
|
+
normalizedDuration
|
|
3517
|
+
)
|
|
3518
|
+
}
|
|
3519
|
+
]);
|
|
3520
|
+
setEditingDuration(false);
|
|
3521
|
+
} else if (e.key === "Escape") {
|
|
3522
|
+
handleDurationCancel();
|
|
3523
|
+
}
|
|
3524
|
+
},
|
|
3525
|
+
[durationValue, task, onTasksChange, handleDurationCancel]
|
|
3526
|
+
);
|
|
3527
|
+
const handleProgressClick = useCallback4(
|
|
3528
|
+
(e) => {
|
|
3529
|
+
if (task.locked) return;
|
|
3530
|
+
e.stopPropagation();
|
|
3531
|
+
progressConfirmedRef.current = false;
|
|
3532
|
+
setProgressValue(task.progress ?? 0);
|
|
3533
|
+
setEditingProgress(true);
|
|
3534
|
+
},
|
|
3535
|
+
[task.progress, task.locked]
|
|
3536
|
+
);
|
|
3296
3537
|
const handleProgressSave = useCallback4(() => {
|
|
3297
3538
|
if (progressConfirmedRef.current) {
|
|
3298
3539
|
progressConfirmedRef.current = false;
|
|
@@ -3315,28 +3556,36 @@ var TaskListRow = React9.memo(
|
|
|
3315
3556
|
setEditingProgress(false);
|
|
3316
3557
|
}, []);
|
|
3317
3558
|
const handleProgressAdjust = useCallback4((delta) => {
|
|
3318
|
-
setProgressValue(
|
|
3559
|
+
setProgressValue(
|
|
3560
|
+
(current) => Math.max(0, Math.min(100, current + delta))
|
|
3561
|
+
);
|
|
3319
3562
|
}, []);
|
|
3320
|
-
const handleProgressKeyDown = useCallback4(
|
|
3321
|
-
e
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3563
|
+
const handleProgressKeyDown = useCallback4(
|
|
3564
|
+
(e) => {
|
|
3565
|
+
e.stopPropagation();
|
|
3566
|
+
if (e.key === "Enter") {
|
|
3567
|
+
progressConfirmedRef.current = true;
|
|
3568
|
+
const clampedValue = Math.max(0, Math.min(100, progressValue));
|
|
3569
|
+
if ((clampedValue === 100 || clampedValue === 0) && isTaskParent(task.id, allTasks)) {
|
|
3570
|
+
const children = getChildren(task.id, allTasks);
|
|
3571
|
+
const updatedTasks = [
|
|
3572
|
+
{ ...task, progress: clampedValue },
|
|
3573
|
+
...children.map((child) => ({
|
|
3574
|
+
...child,
|
|
3575
|
+
progress: clampedValue
|
|
3576
|
+
}))
|
|
3577
|
+
];
|
|
3578
|
+
onTasksChange?.(updatedTasks);
|
|
3579
|
+
} else {
|
|
3580
|
+
onTasksChange?.([{ ...task, progress: clampedValue }]);
|
|
3581
|
+
}
|
|
3582
|
+
setEditingProgress(false);
|
|
3583
|
+
} else if (e.key === "Escape") {
|
|
3584
|
+
handleProgressCancel();
|
|
3334
3585
|
}
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
}
|
|
3339
|
-
}, [progressValue, task, onTasksChange, handleProgressCancel, allTasks]);
|
|
3586
|
+
},
|
|
3587
|
+
[progressValue, task, onTasksChange, handleProgressCancel, allTasks]
|
|
3588
|
+
);
|
|
3340
3589
|
useEffect4(() => {
|
|
3341
3590
|
if (editingProgress && progressInputRef.current) {
|
|
3342
3591
|
progressInputRef.current.focus();
|
|
@@ -3352,77 +3601,111 @@ var TaskListRow = React9.memo(
|
|
|
3352
3601
|
durationInputRef.current.select();
|
|
3353
3602
|
}
|
|
3354
3603
|
}, [editingDuration]);
|
|
3355
|
-
const handleStartDateChange = useCallback4(
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
newDateISO,
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3604
|
+
const handleStartDateChange = useCallback4(
|
|
3605
|
+
(newDateISO) => {
|
|
3606
|
+
if (!newDateISO) return;
|
|
3607
|
+
const origStart = parseUTCDate(task.startDate);
|
|
3608
|
+
const origEnd = parseUTCDate(task.endDate);
|
|
3609
|
+
const durationMs = origEnd.getTime() - origStart.getTime();
|
|
3610
|
+
const newStart = /* @__PURE__ */ new Date(newDateISO + "T00:00:00Z");
|
|
3611
|
+
const newEnd = new Date(newStart.getTime() + durationMs);
|
|
3612
|
+
const { startDate: normalizedStart, endDate: normalizedEnd } = normalizeTaskDates(newDateISO, newEnd.toISOString().split("T")[0]);
|
|
3613
|
+
onTasksChange?.([
|
|
3614
|
+
{ ...task, startDate: normalizedStart, endDate: normalizedEnd }
|
|
3615
|
+
]);
|
|
3616
|
+
},
|
|
3617
|
+
[task, onTasksChange]
|
|
3618
|
+
);
|
|
3619
|
+
const handleEndDateChange = useCallback4(
|
|
3620
|
+
(newDateISO) => {
|
|
3621
|
+
if (!newDateISO) return;
|
|
3622
|
+
const origStart = parseUTCDate(task.startDate);
|
|
3623
|
+
const origEnd = parseUTCDate(task.endDate);
|
|
3624
|
+
const durationMs = origEnd.getTime() - origStart.getTime();
|
|
3625
|
+
const newEnd = /* @__PURE__ */ new Date(newDateISO + "T00:00:00Z");
|
|
3626
|
+
const newStart = new Date(newEnd.getTime() - durationMs);
|
|
3627
|
+
const { startDate: normalizedStart, endDate: normalizedEnd } = normalizeTaskDates(newStart.toISOString().split("T")[0], newDateISO);
|
|
3628
|
+
onTasksChange?.([
|
|
3629
|
+
{ ...task, startDate: normalizedStart, endDate: normalizedEnd }
|
|
3630
|
+
]);
|
|
3631
|
+
},
|
|
3632
|
+
[task, onTasksChange]
|
|
3633
|
+
);
|
|
3381
3634
|
const handleRowClickInternal = useCallback4(() => {
|
|
3382
3635
|
onRowClick?.(task.id);
|
|
3383
3636
|
}, [task.id, onRowClick]);
|
|
3384
|
-
const handleNumberClick = useCallback4(
|
|
3385
|
-
e
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
const
|
|
3406
|
-
e
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
onSetSelectingPredecessorFor
|
|
3418
|
-
|
|
3637
|
+
const handleNumberClick = useCallback4(
|
|
3638
|
+
(e) => {
|
|
3639
|
+
e.stopPropagation();
|
|
3640
|
+
onRowClick?.(task.id);
|
|
3641
|
+
},
|
|
3642
|
+
[task.id, onRowClick]
|
|
3643
|
+
);
|
|
3644
|
+
const handleToggleCollapse = useCallback4(
|
|
3645
|
+
(e) => {
|
|
3646
|
+
e.stopPropagation();
|
|
3647
|
+
onToggleCollapse?.(task.id);
|
|
3648
|
+
},
|
|
3649
|
+
[task.id, onToggleCollapse]
|
|
3650
|
+
);
|
|
3651
|
+
const handlePromote = useCallback4(
|
|
3652
|
+
(e) => {
|
|
3653
|
+
e.stopPropagation();
|
|
3654
|
+
onPromoteTask?.(task.id);
|
|
3655
|
+
},
|
|
3656
|
+
[task.id, onPromoteTask]
|
|
3657
|
+
);
|
|
3658
|
+
const handleDemote = useCallback4(
|
|
3659
|
+
(e) => {
|
|
3660
|
+
e.stopPropagation();
|
|
3661
|
+
onDemoteTask?.(task.id, "");
|
|
3662
|
+
},
|
|
3663
|
+
[task.id, onDemoteTask]
|
|
3664
|
+
);
|
|
3665
|
+
const handleAddClick = useCallback4(
|
|
3666
|
+
(e) => {
|
|
3667
|
+
e.stopPropagation();
|
|
3668
|
+
onSetSelectingPredecessorFor?.(task.id);
|
|
3669
|
+
},
|
|
3670
|
+
[task.id, onSetSelectingPredecessorFor]
|
|
3671
|
+
);
|
|
3672
|
+
const handlePredecessorPick = useCallback4(
|
|
3673
|
+
(e) => {
|
|
3674
|
+
e.stopPropagation();
|
|
3675
|
+
if (!isPicking || isSourceRow) return;
|
|
3676
|
+
if (!selectingPredecessorFor || !activeLinkType) return;
|
|
3677
|
+
onAddDependency?.(task.id, selectingPredecessorFor, activeLinkType);
|
|
3678
|
+
},
|
|
3679
|
+
[
|
|
3680
|
+
isPicking,
|
|
3681
|
+
isSourceRow,
|
|
3682
|
+
selectingPredecessorFor,
|
|
3683
|
+
task.id,
|
|
3684
|
+
activeLinkType,
|
|
3685
|
+
onAddDependency
|
|
3686
|
+
]
|
|
3687
|
+
);
|
|
3688
|
+
const handleCancelPicking = useCallback4(
|
|
3689
|
+
(e) => {
|
|
3690
|
+
e.stopPropagation();
|
|
3691
|
+
onSetSelectingPredecessorFor?.(null);
|
|
3692
|
+
},
|
|
3693
|
+
[onSetSelectingPredecessorFor]
|
|
3694
|
+
);
|
|
3419
3695
|
const isSelectedPredecessor = selectedChip != null && selectedChip.predecessorId === task.id;
|
|
3420
|
-
const handleDeleteSelected = useCallback4(
|
|
3421
|
-
e
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3696
|
+
const handleDeleteSelected = useCallback4(
|
|
3697
|
+
(e) => {
|
|
3698
|
+
e.stopPropagation();
|
|
3699
|
+
if (!selectedChip) return;
|
|
3700
|
+
onRemoveDependency?.(
|
|
3701
|
+
selectedChip.successorId,
|
|
3702
|
+
selectedChip.predecessorId,
|
|
3703
|
+
selectedChip.linkType
|
|
3704
|
+
);
|
|
3705
|
+
onChipSelect?.(null);
|
|
3706
|
+
},
|
|
3707
|
+
[selectedChip, onRemoveDependency, onChipSelect]
|
|
3708
|
+
);
|
|
3426
3709
|
const startDateISO = toISODate(task.startDate);
|
|
3427
3710
|
const endDateISO = editingDuration ? getEndDateFromDuration(task.startDate, durationValue) : toISODate(task.endDate);
|
|
3428
3711
|
return /* @__PURE__ */ jsxs9(
|
|
@@ -3475,13 +3758,78 @@ var TaskListRow = React9.memo(
|
|
|
3475
3758
|
}
|
|
3476
3759
|
),
|
|
3477
3760
|
/* @__PURE__ */ jsxs9("div", { className: "gantt-tl-cell gantt-tl-cell-name", children: [
|
|
3478
|
-
isChild && !editingName && /* @__PURE__ */
|
|
3761
|
+
isChild && !editingName && /* @__PURE__ */ jsxs9(Fragment2, { children: [
|
|
3762
|
+
ancestorContinues.map(
|
|
3763
|
+
(continues, idx) => continues ? /* @__PURE__ */ jsx12(
|
|
3764
|
+
"span",
|
|
3765
|
+
{
|
|
3766
|
+
style: {
|
|
3767
|
+
position: "absolute",
|
|
3768
|
+
left: `${idx * 20 + 9}px`,
|
|
3769
|
+
top: 0,
|
|
3770
|
+
height: `${rowHeight}px`,
|
|
3771
|
+
width: "1.5px",
|
|
3772
|
+
background: "#d4bceb",
|
|
3773
|
+
borderRadius: "1px",
|
|
3774
|
+
pointerEvents: "none"
|
|
3775
|
+
}
|
|
3776
|
+
},
|
|
3777
|
+
idx
|
|
3778
|
+
) : null
|
|
3779
|
+
),
|
|
3780
|
+
/* @__PURE__ */ jsx12(
|
|
3781
|
+
"span",
|
|
3782
|
+
{
|
|
3783
|
+
style: {
|
|
3784
|
+
position: "absolute",
|
|
3785
|
+
left: `${(nestingDepth - 1) * 20 + 9}px`,
|
|
3786
|
+
top: 0,
|
|
3787
|
+
height: isLastChild ? `${rowHeight / 2}px` : `${rowHeight}px`,
|
|
3788
|
+
width: "1.5px",
|
|
3789
|
+
background: "#d4bceb",
|
|
3790
|
+
borderRadius: "1px",
|
|
3791
|
+
pointerEvents: "none"
|
|
3792
|
+
}
|
|
3793
|
+
}
|
|
3794
|
+
),
|
|
3795
|
+
/* @__PURE__ */ jsx12(
|
|
3796
|
+
"span",
|
|
3797
|
+
{
|
|
3798
|
+
style: {
|
|
3799
|
+
position: "absolute",
|
|
3800
|
+
left: `${(nestingDepth - 1) * 20 + 9}px`,
|
|
3801
|
+
top: `${rowHeight / 2 - 0.75}px`,
|
|
3802
|
+
width: "8px",
|
|
3803
|
+
height: "1.5px",
|
|
3804
|
+
background: "#d4bceb",
|
|
3805
|
+
borderRadius: "1px",
|
|
3806
|
+
pointerEvents: "none"
|
|
3807
|
+
}
|
|
3808
|
+
}
|
|
3809
|
+
),
|
|
3810
|
+
/* @__PURE__ */ jsx12(
|
|
3811
|
+
"span",
|
|
3812
|
+
{
|
|
3813
|
+
style: {
|
|
3814
|
+
position: "absolute",
|
|
3815
|
+
left: `${(nestingDepth - 1) * 20 + 15}px`,
|
|
3816
|
+
top: `${rowHeight / 2 - 2}px`,
|
|
3817
|
+
width: "4px",
|
|
3818
|
+
height: "4px",
|
|
3819
|
+
borderRadius: "50%",
|
|
3820
|
+
background: "#d4bceb",
|
|
3821
|
+
pointerEvents: "none"
|
|
3822
|
+
}
|
|
3823
|
+
}
|
|
3824
|
+
)
|
|
3825
|
+
] }),
|
|
3479
3826
|
isParent && !editingName && /* @__PURE__ */ jsx12(
|
|
3480
3827
|
"button",
|
|
3481
3828
|
{
|
|
3482
3829
|
type: "button",
|
|
3483
3830
|
className: `gantt-tl-collapse-btn ${isCollapsed ? "gantt-tl-collapse-btn-collapsed" : ""}`,
|
|
3484
3831
|
onClick: handleToggleCollapse,
|
|
3832
|
+
style: { left: `${nestingDepth * 20 + 4}px` },
|
|
3485
3833
|
"aria-label": isCollapsed ? "Expand children" : "Collapse children",
|
|
3486
3834
|
children: /* @__PURE__ */ jsx12(ChevronRightIcon, {})
|
|
3487
3835
|
}
|
|
@@ -3495,7 +3843,10 @@ var TaskListRow = React9.memo(
|
|
|
3495
3843
|
onChange: (e) => setNameValue(e.target.value),
|
|
3496
3844
|
onBlur: handleNameSave,
|
|
3497
3845
|
onKeyDown: handleNameKeyDown,
|
|
3498
|
-
className:
|
|
3846
|
+
className: "gantt-tl-name-input",
|
|
3847
|
+
style: {
|
|
3848
|
+
paddingLeft: nestingDepth > 0 ? `${nestingDepth * 20 + 24}px` : void 0
|
|
3849
|
+
},
|
|
3499
3850
|
onClick: (e) => e.stopPropagation()
|
|
3500
3851
|
}
|
|
3501
3852
|
),
|
|
@@ -3505,14 +3856,15 @@ var TaskListRow = React9.memo(
|
|
|
3505
3856
|
type: "button",
|
|
3506
3857
|
className: [
|
|
3507
3858
|
"gantt-tl-name-trigger",
|
|
3508
|
-
disableTaskNameEditing ? "gantt-tl-name-locked" : ""
|
|
3509
|
-
isParent ? "gantt-tl-name-trigger-parent" : "",
|
|
3510
|
-
isChild ? "gantt-tl-name-trigger-child" : ""
|
|
3859
|
+
disableTaskNameEditing ? "gantt-tl-name-locked" : ""
|
|
3511
3860
|
].filter(Boolean).join(" "),
|
|
3512
3861
|
title: task.name,
|
|
3513
3862
|
onClick: handleNameClick,
|
|
3514
3863
|
onDoubleClick: handleNameDoubleClick,
|
|
3515
|
-
style:
|
|
3864
|
+
style: {
|
|
3865
|
+
paddingLeft: nestingDepth > 0 ? `${nestingDepth * 20 + (isParent ? 26 : 8)}px` : isParent ? "26px" : void 0,
|
|
3866
|
+
...editingName ? { visibility: "hidden", pointerEvents: "none" } : void 0
|
|
3867
|
+
},
|
|
3516
3868
|
children: task.name
|
|
3517
3869
|
}
|
|
3518
3870
|
),
|
|
@@ -3525,16 +3877,20 @@ var TaskListRow = React9.memo(
|
|
|
3525
3877
|
onClick: (e) => {
|
|
3526
3878
|
e.stopPropagation();
|
|
3527
3879
|
const now = /* @__PURE__ */ new Date();
|
|
3528
|
-
const todayISO = new Date(
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
3880
|
+
const todayISO = new Date(
|
|
3881
|
+
Date.UTC(
|
|
3882
|
+
now.getUTCFullYear(),
|
|
3883
|
+
now.getUTCMonth(),
|
|
3884
|
+
now.getUTCDate()
|
|
3885
|
+
)
|
|
3886
|
+
).toISOString().split("T")[0];
|
|
3887
|
+
const endISO = new Date(
|
|
3888
|
+
Date.UTC(
|
|
3889
|
+
now.getUTCFullYear(),
|
|
3890
|
+
now.getUTCMonth(),
|
|
3891
|
+
now.getUTCDate() + 7
|
|
3892
|
+
)
|
|
3893
|
+
).toISOString().split("T")[0];
|
|
3538
3894
|
const newTask = {
|
|
3539
3895
|
id: crypto.randomUUID(),
|
|
3540
3896
|
name: "\u041D\u043E\u0432\u0430\u044F \u0437\u0430\u0434\u0430\u0447\u0430",
|
|
@@ -3570,7 +3926,6 @@ var TaskListRow = React9.memo(
|
|
|
3570
3926
|
HierarchyButton,
|
|
3571
3927
|
{
|
|
3572
3928
|
isChild,
|
|
3573
|
-
isParent,
|
|
3574
3929
|
rowIndex,
|
|
3575
3930
|
onPromote: onPromoteTask ? handlePromote : void 0,
|
|
3576
3931
|
onDemote: onDemoteTask ? handleDemote : void 0
|
|
@@ -3578,113 +3933,234 @@ var TaskListRow = React9.memo(
|
|
|
3578
3933
|
)
|
|
3579
3934
|
] })
|
|
3580
3935
|
] }),
|
|
3581
|
-
/* @__PURE__ */ jsx12(
|
|
3582
|
-
|
|
3936
|
+
/* @__PURE__ */ jsx12(
|
|
3937
|
+
"div",
|
|
3583
3938
|
{
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3939
|
+
className: "gantt-tl-cell gantt-tl-cell-date",
|
|
3940
|
+
onClick: (e) => e.stopPropagation(),
|
|
3941
|
+
children: /* @__PURE__ */ jsx12(
|
|
3942
|
+
DatePicker,
|
|
3943
|
+
{
|
|
3944
|
+
value: startDateISO,
|
|
3945
|
+
onChange: handleStartDateChange,
|
|
3946
|
+
format: "dd.MM.yy",
|
|
3947
|
+
portal: true,
|
|
3948
|
+
disabled: task.locked,
|
|
3949
|
+
weekends,
|
|
3950
|
+
workdays,
|
|
3951
|
+
isWeekend: isWeekend3
|
|
3952
|
+
}
|
|
3953
|
+
)
|
|
3589
3954
|
}
|
|
3590
|
-
)
|
|
3591
|
-
/* @__PURE__ */ jsx12(
|
|
3592
|
-
|
|
3955
|
+
),
|
|
3956
|
+
/* @__PURE__ */ jsx12(
|
|
3957
|
+
"div",
|
|
3593
3958
|
{
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
disabled: task.locked
|
|
3599
|
-
}
|
|
3600
|
-
) }),
|
|
3601
|
-
/* @__PURE__ */ jsxs9("div", { className: "gantt-tl-cell gantt-tl-cell-duration", onClick: handleDurationClick, children: [
|
|
3602
|
-
editingDuration && /* @__PURE__ */ jsxs9("div", { className: "gantt-tl-number-editor", onClick: (e) => e.stopPropagation(), children: [
|
|
3603
|
-
/* @__PURE__ */ jsx12(
|
|
3604
|
-
Input,
|
|
3959
|
+
className: "gantt-tl-cell gantt-tl-cell-date",
|
|
3960
|
+
onClick: (e) => e.stopPropagation(),
|
|
3961
|
+
children: /* @__PURE__ */ jsx12(
|
|
3962
|
+
DatePicker,
|
|
3605
3963
|
{
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
className: "gantt-tl-number-input"
|
|
3964
|
+
value: endDateISO,
|
|
3965
|
+
onChange: handleEndDateChange,
|
|
3966
|
+
format: "dd.MM.yy",
|
|
3967
|
+
portal: true,
|
|
3968
|
+
disabled: task.locked,
|
|
3969
|
+
weekends,
|
|
3970
|
+
workdays,
|
|
3971
|
+
isWeekend: isWeekend3
|
|
3615
3972
|
}
|
|
3616
|
-
)
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3973
|
+
)
|
|
3974
|
+
}
|
|
3975
|
+
),
|
|
3976
|
+
/* @__PURE__ */ jsxs9(
|
|
3977
|
+
"div",
|
|
3978
|
+
{
|
|
3979
|
+
className: "gantt-tl-cell gantt-tl-cell-duration",
|
|
3980
|
+
onClick: handleDurationClick,
|
|
3981
|
+
children: [
|
|
3982
|
+
editingDuration && /* @__PURE__ */ jsxs9(
|
|
3983
|
+
"div",
|
|
3620
3984
|
{
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3985
|
+
className: "gantt-tl-number-editor",
|
|
3986
|
+
onClick: (e) => e.stopPropagation(),
|
|
3987
|
+
children: [
|
|
3988
|
+
/* @__PURE__ */ jsx12(
|
|
3989
|
+
Input,
|
|
3990
|
+
{
|
|
3991
|
+
ref: durationInputRef,
|
|
3992
|
+
type: "number",
|
|
3993
|
+
min: 1,
|
|
3994
|
+
step: 1,
|
|
3995
|
+
value: durationValue,
|
|
3996
|
+
onChange: (e) => applyDurationChange(parseInt(e.target.value, 10) || 1),
|
|
3997
|
+
onBlur: handleDurationSave,
|
|
3998
|
+
onKeyDown: handleDurationKeyDown,
|
|
3999
|
+
className: "gantt-tl-number-input"
|
|
4000
|
+
}
|
|
4001
|
+
),
|
|
4002
|
+
/* @__PURE__ */ jsxs9("div", { className: "gantt-tl-number-steppers", "aria-hidden": "true", children: [
|
|
4003
|
+
/* @__PURE__ */ jsx12(
|
|
4004
|
+
"button",
|
|
4005
|
+
{
|
|
4006
|
+
type: "button",
|
|
4007
|
+
className: "gantt-tl-number-stepper",
|
|
4008
|
+
tabIndex: -1,
|
|
4009
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
4010
|
+
onClick: () => handleDurationAdjust(1),
|
|
4011
|
+
children: /* @__PURE__ */ jsx12(
|
|
4012
|
+
"svg",
|
|
4013
|
+
{
|
|
4014
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
4015
|
+
width: "10",
|
|
4016
|
+
height: "10",
|
|
4017
|
+
viewBox: "0 0 24 24",
|
|
4018
|
+
fill: "none",
|
|
4019
|
+
stroke: "currentColor",
|
|
4020
|
+
strokeWidth: "2",
|
|
4021
|
+
strokeLinecap: "round",
|
|
4022
|
+
strokeLinejoin: "round",
|
|
4023
|
+
children: /* @__PURE__ */ jsx12("path", { d: "m18 15-6-6-6 6" })
|
|
4024
|
+
}
|
|
4025
|
+
)
|
|
4026
|
+
}
|
|
4027
|
+
),
|
|
4028
|
+
/* @__PURE__ */ jsx12(
|
|
4029
|
+
"button",
|
|
4030
|
+
{
|
|
4031
|
+
type: "button",
|
|
4032
|
+
className: "gantt-tl-number-stepper",
|
|
4033
|
+
tabIndex: -1,
|
|
4034
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
4035
|
+
onClick: () => handleDurationAdjust(-1),
|
|
4036
|
+
children: /* @__PURE__ */ jsx12(
|
|
4037
|
+
"svg",
|
|
4038
|
+
{
|
|
4039
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
4040
|
+
width: "10",
|
|
4041
|
+
height: "10",
|
|
4042
|
+
viewBox: "0 0 24 24",
|
|
4043
|
+
fill: "none",
|
|
4044
|
+
stroke: "currentColor",
|
|
4045
|
+
strokeWidth: "2",
|
|
4046
|
+
strokeLinecap: "round",
|
|
4047
|
+
strokeLinejoin: "round",
|
|
4048
|
+
children: /* @__PURE__ */ jsx12("path", { d: "m6 9 6 6 6-6" })
|
|
4049
|
+
}
|
|
4050
|
+
)
|
|
4051
|
+
}
|
|
4052
|
+
)
|
|
4053
|
+
] })
|
|
4054
|
+
]
|
|
3627
4055
|
}
|
|
3628
4056
|
),
|
|
3629
4057
|
/* @__PURE__ */ jsx12(
|
|
3630
|
-
"
|
|
4058
|
+
"span",
|
|
3631
4059
|
{
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
tabIndex: -1,
|
|
3635
|
-
onMouseDown: (e) => e.preventDefault(),
|
|
3636
|
-
onClick: () => handleDurationAdjust(-1),
|
|
3637
|
-
children: /* @__PURE__ */ jsx12("svg", { xmlns: "http://www.w3.org/2000/svg", width: "10", height: "10", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx12("path", { d: "m6 9 6 6 6-6" }) })
|
|
4060
|
+
style: editingDuration ? { visibility: "hidden", pointerEvents: "none" } : void 0,
|
|
4061
|
+
children: getInclusiveDurationDays(task.startDate, task.endDate)
|
|
3638
4062
|
}
|
|
3639
4063
|
)
|
|
3640
|
-
]
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
min: 0,
|
|
3652
|
-
max: 100,
|
|
3653
|
-
step: 1,
|
|
3654
|
-
value: progressValue,
|
|
3655
|
-
onChange: (e) => setProgressValue(parseInt(e.target.value, 10) || 0),
|
|
3656
|
-
onBlur: handleProgressSave,
|
|
3657
|
-
onKeyDown: handleProgressKeyDown,
|
|
3658
|
-
className: "gantt-tl-number-input"
|
|
3659
|
-
}
|
|
3660
|
-
),
|
|
3661
|
-
/* @__PURE__ */ jsxs9("div", { className: "gantt-tl-number-steppers", "aria-hidden": "true", children: [
|
|
3662
|
-
/* @__PURE__ */ jsx12(
|
|
3663
|
-
"button",
|
|
4064
|
+
]
|
|
4065
|
+
}
|
|
4066
|
+
),
|
|
4067
|
+
/* @__PURE__ */ jsxs9(
|
|
4068
|
+
"div",
|
|
4069
|
+
{
|
|
4070
|
+
className: "gantt-tl-cell gantt-tl-cell-progress",
|
|
4071
|
+
onClick: handleProgressClick,
|
|
4072
|
+
children: [
|
|
4073
|
+
editingProgress && /* @__PURE__ */ jsxs9(
|
|
4074
|
+
"div",
|
|
3664
4075
|
{
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
4076
|
+
className: "gantt-tl-number-editor",
|
|
4077
|
+
onClick: (e) => e.stopPropagation(),
|
|
4078
|
+
children: [
|
|
4079
|
+
/* @__PURE__ */ jsx12(
|
|
4080
|
+
Input,
|
|
4081
|
+
{
|
|
4082
|
+
ref: progressInputRef,
|
|
4083
|
+
type: "number",
|
|
4084
|
+
min: 0,
|
|
4085
|
+
max: 100,
|
|
4086
|
+
step: 1,
|
|
4087
|
+
value: progressValue,
|
|
4088
|
+
onChange: (e) => setProgressValue(parseInt(e.target.value, 10) || 0),
|
|
4089
|
+
onBlur: handleProgressSave,
|
|
4090
|
+
onKeyDown: handleProgressKeyDown,
|
|
4091
|
+
className: "gantt-tl-number-input"
|
|
4092
|
+
}
|
|
4093
|
+
),
|
|
4094
|
+
/* @__PURE__ */ jsxs9("div", { className: "gantt-tl-number-steppers", "aria-hidden": "true", children: [
|
|
4095
|
+
/* @__PURE__ */ jsx12(
|
|
4096
|
+
"button",
|
|
4097
|
+
{
|
|
4098
|
+
type: "button",
|
|
4099
|
+
className: "gantt-tl-number-stepper",
|
|
4100
|
+
tabIndex: -1,
|
|
4101
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
4102
|
+
onClick: () => handleProgressAdjust(1),
|
|
4103
|
+
children: /* @__PURE__ */ jsx12(
|
|
4104
|
+
"svg",
|
|
4105
|
+
{
|
|
4106
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
4107
|
+
width: "10",
|
|
4108
|
+
height: "10",
|
|
4109
|
+
viewBox: "0 0 24 24",
|
|
4110
|
+
fill: "none",
|
|
4111
|
+
stroke: "currentColor",
|
|
4112
|
+
strokeWidth: "2",
|
|
4113
|
+
strokeLinecap: "round",
|
|
4114
|
+
strokeLinejoin: "round",
|
|
4115
|
+
children: /* @__PURE__ */ jsx12("path", { d: "m18 15-6-6-6 6" })
|
|
4116
|
+
}
|
|
4117
|
+
)
|
|
4118
|
+
}
|
|
4119
|
+
),
|
|
4120
|
+
/* @__PURE__ */ jsx12(
|
|
4121
|
+
"button",
|
|
4122
|
+
{
|
|
4123
|
+
type: "button",
|
|
4124
|
+
className: "gantt-tl-number-stepper",
|
|
4125
|
+
tabIndex: -1,
|
|
4126
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
4127
|
+
onClick: () => handleProgressAdjust(-1),
|
|
4128
|
+
children: /* @__PURE__ */ jsx12(
|
|
4129
|
+
"svg",
|
|
4130
|
+
{
|
|
4131
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
4132
|
+
width: "10",
|
|
4133
|
+
height: "10",
|
|
4134
|
+
viewBox: "0 0 24 24",
|
|
4135
|
+
fill: "none",
|
|
4136
|
+
stroke: "currentColor",
|
|
4137
|
+
strokeWidth: "2",
|
|
4138
|
+
strokeLinecap: "round",
|
|
4139
|
+
strokeLinejoin: "round",
|
|
4140
|
+
children: /* @__PURE__ */ jsx12("path", { d: "m6 9 6 6 6-6" })
|
|
4141
|
+
}
|
|
4142
|
+
)
|
|
4143
|
+
}
|
|
4144
|
+
)
|
|
4145
|
+
] })
|
|
4146
|
+
]
|
|
3671
4147
|
}
|
|
3672
4148
|
),
|
|
3673
4149
|
/* @__PURE__ */ jsx12(
|
|
3674
|
-
"
|
|
4150
|
+
"span",
|
|
3675
4151
|
{
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
4152
|
+
style: editingProgress ? { visibility: "hidden", pointerEvents: "none" } : task.progress === 100 ? {
|
|
4153
|
+
backgroundColor: "#17c864",
|
|
4154
|
+
borderRadius: "4px",
|
|
4155
|
+
padding: "2px 4px",
|
|
4156
|
+
color: "#ffffff"
|
|
4157
|
+
} : void 0,
|
|
4158
|
+
children: task.progress ? Math.round(task.progress) === 100 ? "100" : `${Math.round(task.progress)}%` : "0%"
|
|
3682
4159
|
}
|
|
3683
4160
|
)
|
|
3684
|
-
]
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
] }),
|
|
4161
|
+
]
|
|
4162
|
+
}
|
|
4163
|
+
),
|
|
3688
4164
|
/* @__PURE__ */ jsx12(
|
|
3689
4165
|
"div",
|
|
3690
4166
|
{
|
|
@@ -3725,26 +4201,33 @@ var TaskListRow = React9.memo(
|
|
|
3725
4201
|
]
|
|
3726
4202
|
}
|
|
3727
4203
|
) }),
|
|
3728
|
-
/* @__PURE__ */ jsx12(PopoverContent, { portal: true, align: "start", children: /* @__PURE__ */ jsx12(
|
|
3729
|
-
|
|
4204
|
+
/* @__PURE__ */ jsx12(PopoverContent, { portal: true, align: "start", children: /* @__PURE__ */ jsx12(
|
|
4205
|
+
"div",
|
|
3730
4206
|
{
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
4207
|
+
className: "gantt-tl-dep-overflow-list",
|
|
4208
|
+
onClick: (e) => e.stopPropagation(),
|
|
4209
|
+
children: chips.map(({ dep, lag, predecessorName }) => /* @__PURE__ */ jsx12(
|
|
4210
|
+
DepChip,
|
|
4211
|
+
{
|
|
4212
|
+
lag,
|
|
4213
|
+
dep,
|
|
4214
|
+
taskId: task.id,
|
|
4215
|
+
predecessorName,
|
|
4216
|
+
selectedChip,
|
|
4217
|
+
disableDependencyEditing,
|
|
4218
|
+
onChipSelect,
|
|
4219
|
+
onRowClick,
|
|
4220
|
+
onScrollToTask,
|
|
4221
|
+
onRemoveDependency,
|
|
4222
|
+
onChipSelectClear: () => onChipSelect?.(null),
|
|
4223
|
+
task,
|
|
4224
|
+
allTasks,
|
|
4225
|
+
onTasksChange
|
|
4226
|
+
},
|
|
4227
|
+
`${dep.taskId}-${dep.type}`
|
|
4228
|
+
))
|
|
4229
|
+
}
|
|
4230
|
+
) })
|
|
3748
4231
|
] })
|
|
3749
4232
|
) : chips.length === 1 ? (
|
|
3750
4233
|
/* Single chip — unified DepChip */
|
|
@@ -3909,7 +4392,10 @@ var TaskList = ({
|
|
|
3909
4392
|
collapsedParentIds: externalCollapsedParentIds,
|
|
3910
4393
|
onToggleCollapse: externalOnToggleCollapse,
|
|
3911
4394
|
onPromoteTask,
|
|
3912
|
-
onDemoteTask
|
|
4395
|
+
onDemoteTask,
|
|
4396
|
+
weekends,
|
|
4397
|
+
workdays,
|
|
4398
|
+
isWeekend: isWeekend3
|
|
3913
4399
|
}) => {
|
|
3914
4400
|
const [internalCollapsedParentIds, setInternalCollapsedParentIds] = useState6(/* @__PURE__ */ new Set());
|
|
3915
4401
|
const collapsedParentIds = externalCollapsedParentIds ?? internalCollapsedParentIds;
|
|
@@ -3943,6 +4429,25 @@ var TaskList = ({
|
|
|
3943
4429
|
() => visibleTasks.length * rowHeight,
|
|
3944
4430
|
[visibleTasks.length, rowHeight]
|
|
3945
4431
|
);
|
|
4432
|
+
const nestingDepthMap = useMemo8(() => {
|
|
4433
|
+
const depthMap = /* @__PURE__ */ new Map();
|
|
4434
|
+
const taskById = new Map(tasks.map((t) => [t.id, t]));
|
|
4435
|
+
function getDepth(taskId) {
|
|
4436
|
+
if (depthMap.has(taskId)) return depthMap.get(taskId);
|
|
4437
|
+
const task = taskById.get(taskId);
|
|
4438
|
+
if (!task || !task.parentId || !taskById.has(task.parentId)) {
|
|
4439
|
+
depthMap.set(taskId, 0);
|
|
4440
|
+
return 0;
|
|
4441
|
+
}
|
|
4442
|
+
const depth = getDepth(task.parentId) + 1;
|
|
4443
|
+
depthMap.set(taskId, depth);
|
|
4444
|
+
return depth;
|
|
4445
|
+
}
|
|
4446
|
+
for (const task of tasks) {
|
|
4447
|
+
getDepth(task.id);
|
|
4448
|
+
}
|
|
4449
|
+
return depthMap;
|
|
4450
|
+
}, [tasks]);
|
|
3946
4451
|
const lastChildIds = useMemo8(() => {
|
|
3947
4452
|
const last = /* @__PURE__ */ new Set();
|
|
3948
4453
|
const seenParents = /* @__PURE__ */ new Set();
|
|
@@ -3955,6 +4460,20 @@ var TaskList = ({
|
|
|
3955
4460
|
}
|
|
3956
4461
|
return last;
|
|
3957
4462
|
}, [visibleTasks]);
|
|
4463
|
+
const ancestorContinuesMap = useMemo8(() => {
|
|
4464
|
+
const taskById = new Map(tasks.map((t) => [t.id, t]));
|
|
4465
|
+
const map = /* @__PURE__ */ new Map();
|
|
4466
|
+
for (const task of visibleTasks) {
|
|
4467
|
+
const continues = [];
|
|
4468
|
+
let current = taskById.get(task.id);
|
|
4469
|
+
while (current?.parentId && taskById.has(current.parentId)) {
|
|
4470
|
+
continues.unshift(!lastChildIds.has(current.id));
|
|
4471
|
+
current = taskById.get(current.parentId);
|
|
4472
|
+
}
|
|
4473
|
+
map.set(task.id, continues.slice(0, -1));
|
|
4474
|
+
}
|
|
4475
|
+
return map;
|
|
4476
|
+
}, [tasks, visibleTasks, lastChildIds]);
|
|
3958
4477
|
const handleRowClick = useCallback5((taskId) => {
|
|
3959
4478
|
onTaskSelect?.(taskId);
|
|
3960
4479
|
}, [onTaskSelect]);
|
|
@@ -4065,9 +4584,6 @@ var TaskList = ({
|
|
|
4065
4584
|
if (dropTarget.parentId === draggedTaskId) {
|
|
4066
4585
|
return false;
|
|
4067
4586
|
}
|
|
4068
|
-
if (dropTarget.parentId) {
|
|
4069
|
-
return false;
|
|
4070
|
-
}
|
|
4071
4587
|
const draggedTask = orderedTasks.find((t) => t.id === draggedTaskId);
|
|
4072
4588
|
if (!draggedTask) return true;
|
|
4073
4589
|
const descendants = getAllDescendants(draggedTaskId, orderedTasks);
|
|
@@ -4213,6 +4729,52 @@ var TaskList = ({
|
|
|
4213
4729
|
setIsCreating(false);
|
|
4214
4730
|
}, [onAdd]);
|
|
4215
4731
|
const handleCancelNewTask = useCallback5(() => setIsCreating(false), []);
|
|
4732
|
+
function getTaskDepth(task, tasks2) {
|
|
4733
|
+
if (!task) return 0;
|
|
4734
|
+
let depth = 0;
|
|
4735
|
+
let current = task;
|
|
4736
|
+
while (current) {
|
|
4737
|
+
if (!current.parentId) break;
|
|
4738
|
+
depth++;
|
|
4739
|
+
const parentId = current.parentId;
|
|
4740
|
+
current = tasks2.find((t) => t.id === parentId);
|
|
4741
|
+
}
|
|
4742
|
+
return depth;
|
|
4743
|
+
}
|
|
4744
|
+
const handleDemoteWrapper = useCallback5((taskId, _newParentId) => {
|
|
4745
|
+
const taskIndex = visibleTasks.findIndex((t) => t.id === taskId);
|
|
4746
|
+
const currentTask = visibleTasks[taskIndex];
|
|
4747
|
+
const currentDepth = getTaskDepth(currentTask, orderedTasks);
|
|
4748
|
+
if (taskIndex > 0) {
|
|
4749
|
+
for (let i = taskIndex - 1; i >= 0; i--) {
|
|
4750
|
+
const previousTask = visibleTasks[i];
|
|
4751
|
+
const previousDepth = getTaskDepth(previousTask, orderedTasks);
|
|
4752
|
+
if (previousDepth === currentDepth) {
|
|
4753
|
+
onDemoteTask?.(taskId, previousTask.id);
|
|
4754
|
+
return;
|
|
4755
|
+
}
|
|
4756
|
+
if (previousDepth < currentDepth) {
|
|
4757
|
+
break;
|
|
4758
|
+
}
|
|
4759
|
+
}
|
|
4760
|
+
return;
|
|
4761
|
+
}
|
|
4762
|
+
const demotedTask = orderedTasks.find((t) => t.id === taskId);
|
|
4763
|
+
if (!demotedTask) return;
|
|
4764
|
+
const newSectionTask = {
|
|
4765
|
+
id: crypto.randomUUID(),
|
|
4766
|
+
name: "\u041D\u043E\u0432\u044B\u0439 \u0440\u0430\u0437\u0434\u0435\u043B",
|
|
4767
|
+
startDate: demotedTask.startDate,
|
|
4768
|
+
endDate: demotedTask.endDate
|
|
4769
|
+
};
|
|
4770
|
+
const updatedTasks = [
|
|
4771
|
+
newSectionTask,
|
|
4772
|
+
...orderedTasks.map(
|
|
4773
|
+
(t) => t.id === taskId ? { ...t, parentId: newSectionTask.id } : t
|
|
4774
|
+
)
|
|
4775
|
+
];
|
|
4776
|
+
onReorder?.(updatedTasks, taskId, newSectionTask.id);
|
|
4777
|
+
}, [visibleTasks, orderedTasks, onDemoteTask, onReorder]);
|
|
4216
4778
|
const effectiveTaskListWidth = Math.max(taskListWidth, MIN_TASK_LIST_WIDTH);
|
|
4217
4779
|
return /* @__PURE__ */ jsx14(
|
|
4218
4780
|
"div",
|
|
@@ -4296,8 +4858,13 @@ var TaskList = ({
|
|
|
4296
4858
|
collapsedParentIds,
|
|
4297
4859
|
onToggleCollapse: handleToggleCollapse,
|
|
4298
4860
|
onPromoteTask,
|
|
4299
|
-
onDemoteTask,
|
|
4300
|
-
isLastChild: lastChildIds.has(task.id)
|
|
4861
|
+
onDemoteTask: onDemoteTask ? handleDemoteWrapper : void 0,
|
|
4862
|
+
isLastChild: lastChildIds.has(task.id),
|
|
4863
|
+
nestingDepth: nestingDepthMap.get(task.id) ?? 0,
|
|
4864
|
+
ancestorContinues: ancestorContinuesMap.get(task.id) ?? [],
|
|
4865
|
+
weekends,
|
|
4866
|
+
workdays,
|
|
4867
|
+
isWeekend: isWeekend3
|
|
4301
4868
|
},
|
|
4302
4869
|
task.id
|
|
4303
4870
|
)) }),
|
|
@@ -4365,7 +4932,10 @@ var GanttChart = forwardRef(({
|
|
|
4365
4932
|
onPromoteTask,
|
|
4366
4933
|
onDemoteTask,
|
|
4367
4934
|
enableAddTask = true,
|
|
4368
|
-
viewMode = "day"
|
|
4935
|
+
viewMode = "day",
|
|
4936
|
+
weekends,
|
|
4937
|
+
workdays,
|
|
4938
|
+
isWeekend: isWeekend3
|
|
4369
4939
|
}, ref) => {
|
|
4370
4940
|
const scrollContainerRef = useRef7(null);
|
|
4371
4941
|
const [selectedTaskId, setSelectedTaskId] = useState7(null);
|
|
@@ -4374,6 +4944,10 @@ var GanttChart = forwardRef(({
|
|
|
4374
4944
|
const [collapsedParentIds, setCollapsedParentIds] = useState7(/* @__PURE__ */ new Set());
|
|
4375
4945
|
const [editingTaskId, setEditingTaskId] = useState7(null);
|
|
4376
4946
|
const normalizedTasks = useMemo9(() => normalizeHierarchyTasks(tasks), [tasks]);
|
|
4947
|
+
const isCustomWeekend = useMemo9(
|
|
4948
|
+
() => createIsWeekendPredicate({ weekends, workdays, isWeekend: isWeekend3 }),
|
|
4949
|
+
[weekends, workdays, isWeekend3]
|
|
4950
|
+
);
|
|
4377
4951
|
const dateRange = useMemo9(() => getMultiMonthDays(normalizedTasks), [normalizedTasks]);
|
|
4378
4952
|
const [validationResult, setValidationResult] = useState7(null);
|
|
4379
4953
|
const [cascadeOverrides, setCascadeOverrides] = useState7(/* @__PURE__ */ new Map());
|
|
@@ -4606,6 +5180,17 @@ var GanttChart = forwardRef(({
|
|
|
4606
5180
|
}),
|
|
4607
5181
|
[scrollToToday, scrollToTask, handleCollapseAll, handleExpandAll]
|
|
4608
5182
|
);
|
|
5183
|
+
function getTaskDepth(taskId, tasks2) {
|
|
5184
|
+
let depth = 0;
|
|
5185
|
+
let current = tasks2.find((t) => t.id === taskId);
|
|
5186
|
+
while (current) {
|
|
5187
|
+
if (!current.parentId) break;
|
|
5188
|
+
depth++;
|
|
5189
|
+
const parentId = current.parentId;
|
|
5190
|
+
current = tasks2.find((t) => t.id === parentId);
|
|
5191
|
+
}
|
|
5192
|
+
return depth;
|
|
5193
|
+
}
|
|
4609
5194
|
const handlePromoteTask = useCallback6((taskId) => {
|
|
4610
5195
|
if (onPromoteTask) {
|
|
4611
5196
|
onPromoteTask(taskId);
|
|
@@ -4615,20 +5200,20 @@ var GanttChart = forwardRef(({
|
|
|
4615
5200
|
if (!taskToPromote || !taskToPromote.parentId) {
|
|
4616
5201
|
return;
|
|
4617
5202
|
}
|
|
4618
|
-
const
|
|
4619
|
-
const
|
|
5203
|
+
const depth = getTaskDepth(taskId, tasks);
|
|
5204
|
+
const grandparentId = depth > 1 ? tasks.find((t) => t.id === taskToPromote.parentId)?.parentId : void 0;
|
|
5205
|
+
const currentParentId = taskToPromote.parentId;
|
|
5206
|
+
const siblings = tasks.filter((t) => t.parentId === currentParentId);
|
|
5207
|
+
const promotedTask = { ...taskToPromote, parentId: grandparentId };
|
|
4620
5208
|
if (siblings.length <= 1) {
|
|
4621
|
-
|
|
4622
|
-
onTasksChange?.([promotedTask2]);
|
|
5209
|
+
onTasksChange?.([promotedTask]);
|
|
4623
5210
|
return;
|
|
4624
5211
|
}
|
|
4625
|
-
const lastSiblingIndex = tasks.map((t, i) => ({ task: t, index: i })).filter(({ task }) => task.parentId ===
|
|
5212
|
+
const lastSiblingIndex = tasks.map((t, i) => ({ task: t, index: i })).filter(({ task }) => task.parentId === currentParentId).sort((a, b) => b.index - a.index)[0];
|
|
4626
5213
|
if (!lastSiblingIndex) {
|
|
4627
|
-
|
|
4628
|
-
onTasksChange?.([promotedTask2]);
|
|
5214
|
+
onTasksChange?.([promotedTask]);
|
|
4629
5215
|
return;
|
|
4630
5216
|
}
|
|
4631
|
-
const promotedTask = { ...taskToPromote, parentId: void 0 };
|
|
4632
5217
|
const reorderedTasks = normalizeHierarchyTasks([
|
|
4633
5218
|
...tasks.filter((t) => t.id !== taskId).slice(0, lastSiblingIndex.index + 1),
|
|
4634
5219
|
promotedTask,
|
|
@@ -4754,7 +5339,10 @@ var GanttChart = forwardRef(({
|
|
|
4754
5339
|
collapsedParentIds,
|
|
4755
5340
|
onToggleCollapse: handleToggleCollapse,
|
|
4756
5341
|
onPromoteTask: onPromoteTask ?? handlePromoteTask,
|
|
4757
|
-
onDemoteTask: onDemoteTask ?? handleDemoteTask
|
|
5342
|
+
onDemoteTask: onDemoteTask ?? handleDemoteTask,
|
|
5343
|
+
weekends,
|
|
5344
|
+
workdays,
|
|
5345
|
+
isWeekend: isWeekend3
|
|
4758
5346
|
}
|
|
4759
5347
|
),
|
|
4760
5348
|
/* @__PURE__ */ jsxs12("div", { style: { minWidth: `${gridWidth}px`, flex: 1 }, children: [
|
|
@@ -4764,7 +5352,8 @@ var GanttChart = forwardRef(({
|
|
|
4764
5352
|
days: dateRange,
|
|
4765
5353
|
dayWidth,
|
|
4766
5354
|
headerHeight,
|
|
4767
|
-
viewMode
|
|
5355
|
+
viewMode,
|
|
5356
|
+
isCustomWeekend
|
|
4768
5357
|
}
|
|
4769
5358
|
) }),
|
|
4770
5359
|
/* @__PURE__ */ jsxs12(
|
|
@@ -4782,7 +5371,8 @@ var GanttChart = forwardRef(({
|
|
|
4782
5371
|
dateRange,
|
|
4783
5372
|
dayWidth,
|
|
4784
5373
|
totalHeight: totalGridHeight,
|
|
4785
|
-
viewMode
|
|
5374
|
+
viewMode,
|
|
5375
|
+
isCustomWeekend
|
|
4786
5376
|
}
|
|
4787
5377
|
),
|
|
4788
5378
|
todayInRange && /* @__PURE__ */ jsx15(TodayIndicator_default, { monthStart, dayWidth }),
|
|
@@ -4896,6 +5486,8 @@ export {
|
|
|
4896
5486
|
computeLagFromDates,
|
|
4897
5487
|
computeParentDates,
|
|
4898
5488
|
computeParentProgress,
|
|
5489
|
+
createDateKey,
|
|
5490
|
+
createIsWeekendPredicate,
|
|
4899
5491
|
detectCycles,
|
|
4900
5492
|
detectEdgeZone,
|
|
4901
5493
|
findParentId,
|