gantt-lib 0.79.0 → 0.80.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/dist/core/scheduling/index.d.mts +1 -1
- package/dist/core/scheduling/index.d.ts +1 -1
- package/dist/{index-CZzZrxn-.d.mts → index-DAfJyZbj.d.mts} +14 -1
- package/dist/{index-CZzZrxn-.d.ts → index-DAfJyZbj.d.ts} +14 -1
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +13 -3
- package/dist/index.d.ts +13 -3
- package/dist/index.js +252 -66
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +264 -78
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +209 -11
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React$1, { ReactNode } from 'react';
|
|
2
|
-
import { T as Task$1, R as ResourceTimelineItem, V as ValidationResult, a as ResourcePlannerChartProps, b as ResourceTimelineResource } from './index-
|
|
3
|
-
export { D as DAY_MS, c as DependencyError, G as GanttChartMode, d as GanttDateRange, e as GridConfig, f as GridLine, L as LinkType, M as MonthSpan, g as ResourceTimelineMove, h as TaskBarGeometry, W as WeekendBlock,
|
|
2
|
+
import { T as Task$1, R as ResourceTimelineItem, V as ValidationResult, a as ResourcePlannerChartProps, b as ResourceTimelineResource } from './index-DAfJyZbj.mjs';
|
|
3
|
+
export { D as DAY_MS, c as DependencyError, G as GanttChartMode, d as GanttDateRange, e as GridConfig, f as GridLine, L as LinkType, M as MonthSpan, g as ResourceTimelineMove, h as ResourceTimelineResourceMenuCommand, i as TaskBarGeometry, W as WeekendBlock, j as alignToWorkingDay, k as areTasksHierarchicallyRelated, l as buildAdjacencyList, m as buildTaskRangeFromEnd, n as buildTaskRangeFromStart, o as calculateSuccessorDate, p as cascadeByLinks, q as clampTaskRangeForIncomingFS, r as computeLagFromDates, s as computeParentDates, t as computeParentProgress, u as detectCycles, v as findParentId, w as getAllDependencyEdges, x as getAllDescendants, y as getBusinessDayOffset, z as getChildren, A as getDependencyLag, B as getSuccessorChain, C as getTaskDuration, E as getTransitiveCascadeChain, F as isAncestorTask, H as isTaskParent, I as moveTaskRange, J as moveTaskWithCascade, K as normalizeDependencyLag, N as normalizePredecessorDates, O as normalizeUTCDate, P as parseDateOnly, Q as recalculateIncomingLags, S as recalculateProjectSchedule, U as recalculateTaskFromDependencies, X as reflowTasksOnModeSwitch, Y as removeDependenciesBetweenTasks, Z as resizeTaskWithCascade, _ as shiftBusinessDayOffset, $ as universalCascade, a0 as validateDependencies } from './index-DAfJyZbj.mjs';
|
|
4
4
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
5
5
|
import * as RadixPopover from '@radix-ui/react-popover';
|
|
6
6
|
|
|
@@ -263,6 +263,10 @@ declare const not: (predicate: TaskPredicate) => TaskPredicate;
|
|
|
263
263
|
interface WithoutDepsOptions {
|
|
264
264
|
/** If true, only child tasks (tasks with parentId) can match. */
|
|
265
265
|
onlyChildren?: boolean;
|
|
266
|
+
/** Full task list, required when excluding parent rows. */
|
|
267
|
+
tasks?: Task$1[];
|
|
268
|
+
/** If true, only non-parent regular tasks can match. Requires tasks. */
|
|
269
|
+
onlyLeafTasks?: boolean;
|
|
266
270
|
}
|
|
267
271
|
/**
|
|
268
272
|
* Filter tasks that have no dependencies
|
|
@@ -545,7 +549,7 @@ declare const GanttChart: <TTask extends Task = Task, TItem extends ResourceTime
|
|
|
545
549
|
ref?: React$1.Ref<GanttChartHandle>;
|
|
546
550
|
}) => React$1.ReactElement;
|
|
547
551
|
|
|
548
|
-
declare function ResourceTimelineChart<TItem extends ResourceTimelineItem = ResourceTimelineItem>({ resources, dayWidth, viewMode, rowHeaderWidth, laneHeight, headerHeight, containerHeight, allowVerticalPan, customDays, isWeekend, businessDays, readonly, disableResourceReassignment, renderItem, getItemClassName, onResourceItemClick, onResourceItemMove, }: ResourcePlannerChartProps<TItem>): react_jsx_runtime.JSX.Element;
|
|
552
|
+
declare function ResourceTimelineChart<TItem extends ResourceTimelineItem = ResourceTimelineItem>({ resources, dayWidth, viewMode, rowHeaderWidth, laneHeight, headerHeight, containerHeight, allowVerticalPan, customDays, isWeekend, businessDays, readonly, disableResourceReassignment, renderItem, getItemClassName, onResourceItemClick, onResourceItemMove, onAddResource, enableAddResource, resourceMenuCommands, }: ResourcePlannerChartProps<TItem>): react_jsx_runtime.JSX.Element;
|
|
549
553
|
|
|
550
554
|
interface TaskRowProps {
|
|
551
555
|
/** Task data to render */
|
|
@@ -648,6 +652,12 @@ interface GridBackgroundProps {
|
|
|
648
652
|
viewMode?: 'day' | 'week' | 'month';
|
|
649
653
|
/** Optional predicate for custom weekend logic (e.g., holidays, shift patterns) */
|
|
650
654
|
isCustomWeekend?: (date: Date) => boolean;
|
|
655
|
+
/** Optional extra class for layered rendering contexts. */
|
|
656
|
+
className?: string;
|
|
657
|
+
/** Whether to render weekend background blocks. */
|
|
658
|
+
showWeekendBlocks?: boolean;
|
|
659
|
+
/** Whether to render vertical grid lines. */
|
|
660
|
+
showGridLines?: boolean;
|
|
651
661
|
}
|
|
652
662
|
/**
|
|
653
663
|
* GridBackground component - renders vertical grid lines and weekend background highlighting
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React$1, { ReactNode } from 'react';
|
|
2
|
-
import { T as Task$1, R as ResourceTimelineItem, V as ValidationResult, a as ResourcePlannerChartProps, b as ResourceTimelineResource } from './index-
|
|
3
|
-
export { D as DAY_MS, c as DependencyError, G as GanttChartMode, d as GanttDateRange, e as GridConfig, f as GridLine, L as LinkType, M as MonthSpan, g as ResourceTimelineMove, h as TaskBarGeometry, W as WeekendBlock,
|
|
2
|
+
import { T as Task$1, R as ResourceTimelineItem, V as ValidationResult, a as ResourcePlannerChartProps, b as ResourceTimelineResource } from './index-DAfJyZbj.js';
|
|
3
|
+
export { D as DAY_MS, c as DependencyError, G as GanttChartMode, d as GanttDateRange, e as GridConfig, f as GridLine, L as LinkType, M as MonthSpan, g as ResourceTimelineMove, h as ResourceTimelineResourceMenuCommand, i as TaskBarGeometry, W as WeekendBlock, j as alignToWorkingDay, k as areTasksHierarchicallyRelated, l as buildAdjacencyList, m as buildTaskRangeFromEnd, n as buildTaskRangeFromStart, o as calculateSuccessorDate, p as cascadeByLinks, q as clampTaskRangeForIncomingFS, r as computeLagFromDates, s as computeParentDates, t as computeParentProgress, u as detectCycles, v as findParentId, w as getAllDependencyEdges, x as getAllDescendants, y as getBusinessDayOffset, z as getChildren, A as getDependencyLag, B as getSuccessorChain, C as getTaskDuration, E as getTransitiveCascadeChain, F as isAncestorTask, H as isTaskParent, I as moveTaskRange, J as moveTaskWithCascade, K as normalizeDependencyLag, N as normalizePredecessorDates, O as normalizeUTCDate, P as parseDateOnly, Q as recalculateIncomingLags, S as recalculateProjectSchedule, U as recalculateTaskFromDependencies, X as reflowTasksOnModeSwitch, Y as removeDependenciesBetweenTasks, Z as resizeTaskWithCascade, _ as shiftBusinessDayOffset, $ as universalCascade, a0 as validateDependencies } from './index-DAfJyZbj.js';
|
|
4
4
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
5
5
|
import * as RadixPopover from '@radix-ui/react-popover';
|
|
6
6
|
|
|
@@ -263,6 +263,10 @@ declare const not: (predicate: TaskPredicate) => TaskPredicate;
|
|
|
263
263
|
interface WithoutDepsOptions {
|
|
264
264
|
/** If true, only child tasks (tasks with parentId) can match. */
|
|
265
265
|
onlyChildren?: boolean;
|
|
266
|
+
/** Full task list, required when excluding parent rows. */
|
|
267
|
+
tasks?: Task$1[];
|
|
268
|
+
/** If true, only non-parent regular tasks can match. Requires tasks. */
|
|
269
|
+
onlyLeafTasks?: boolean;
|
|
266
270
|
}
|
|
267
271
|
/**
|
|
268
272
|
* Filter tasks that have no dependencies
|
|
@@ -545,7 +549,7 @@ declare const GanttChart: <TTask extends Task = Task, TItem extends ResourceTime
|
|
|
545
549
|
ref?: React$1.Ref<GanttChartHandle>;
|
|
546
550
|
}) => React$1.ReactElement;
|
|
547
551
|
|
|
548
|
-
declare function ResourceTimelineChart<TItem extends ResourceTimelineItem = ResourceTimelineItem>({ resources, dayWidth, viewMode, rowHeaderWidth, laneHeight, headerHeight, containerHeight, allowVerticalPan, customDays, isWeekend, businessDays, readonly, disableResourceReassignment, renderItem, getItemClassName, onResourceItemClick, onResourceItemMove, }: ResourcePlannerChartProps<TItem>): react_jsx_runtime.JSX.Element;
|
|
552
|
+
declare function ResourceTimelineChart<TItem extends ResourceTimelineItem = ResourceTimelineItem>({ resources, dayWidth, viewMode, rowHeaderWidth, laneHeight, headerHeight, containerHeight, allowVerticalPan, customDays, isWeekend, businessDays, readonly, disableResourceReassignment, renderItem, getItemClassName, onResourceItemClick, onResourceItemMove, onAddResource, enableAddResource, resourceMenuCommands, }: ResourcePlannerChartProps<TItem>): react_jsx_runtime.JSX.Element;
|
|
549
553
|
|
|
550
554
|
interface TaskRowProps {
|
|
551
555
|
/** Task data to render */
|
|
@@ -648,6 +652,12 @@ interface GridBackgroundProps {
|
|
|
648
652
|
viewMode?: 'day' | 'week' | 'month';
|
|
649
653
|
/** Optional predicate for custom weekend logic (e.g., holidays, shift patterns) */
|
|
650
654
|
isCustomWeekend?: (date: Date) => boolean;
|
|
655
|
+
/** Optional extra class for layered rendering contexts. */
|
|
656
|
+
className?: string;
|
|
657
|
+
/** Whether to render weekend background blocks. */
|
|
658
|
+
showWeekendBlocks?: boolean;
|
|
659
|
+
/** Whether to render vertical grid lines. */
|
|
660
|
+
showGridLines?: boolean;
|
|
651
661
|
}
|
|
652
662
|
/**
|
|
653
663
|
* GridBackground component - renders vertical grid lines and weekend background highlighting
|
package/dist/index.js
CHANGED
|
@@ -3137,7 +3137,7 @@ var arePropsEqual2 = (prevProps, nextProps) => {
|
|
|
3137
3137
|
prevProps.viewMode === nextProps.viewMode && prevProps.isCustomWeekend === nextProps.isCustomWeekend;
|
|
3138
3138
|
};
|
|
3139
3139
|
var GridBackground = import_react5.default.memo(
|
|
3140
|
-
({ dateRange, dayWidth, totalHeight, viewMode = "day", isCustomWeekend }) => {
|
|
3140
|
+
({ dateRange, dayWidth, totalHeight, viewMode = "day", isCustomWeekend, className, showWeekendBlocks = true, showGridLines = true }) => {
|
|
3141
3141
|
const weekGridLines = (0, import_react5.useMemo)(() => {
|
|
3142
3142
|
if (viewMode !== "week") return [];
|
|
3143
3143
|
return calculateWeekGridLines(dateRange, dayWidth);
|
|
@@ -3160,13 +3160,13 @@ var GridBackground = import_react5.default.memo(
|
|
|
3160
3160
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
3161
3161
|
"div",
|
|
3162
3162
|
{
|
|
3163
|
-
className: "gantt-gb-gridBackground",
|
|
3163
|
+
className: ["gantt-gb-gridBackground", className].filter(Boolean).join(" "),
|
|
3164
3164
|
style: {
|
|
3165
3165
|
width: `${gridWidth}px`,
|
|
3166
3166
|
height: `${totalHeight}px`
|
|
3167
3167
|
},
|
|
3168
3168
|
children: [
|
|
3169
|
-
weekendBlocks.map((block, index) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
3169
|
+
showWeekendBlocks && weekendBlocks.map((block, index) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
3170
3170
|
"div",
|
|
3171
3171
|
{
|
|
3172
3172
|
className: "gantt-gb-weekendBlock",
|
|
@@ -3177,7 +3177,7 @@ var GridBackground = import_react5.default.memo(
|
|
|
3177
3177
|
},
|
|
3178
3178
|
`weekend-${index}`
|
|
3179
3179
|
)),
|
|
3180
|
-
viewMode === "week" ? (
|
|
3180
|
+
showGridLines && (viewMode === "week" ? (
|
|
3181
3181
|
// Week-view: one line per week column boundary
|
|
3182
3182
|
weekGridLines.map((line, index) => {
|
|
3183
3183
|
const lineClass = line.isMonthStart ? "gantt-gb-monthSeparator" : "gantt-gb-weekSeparator";
|
|
@@ -3218,7 +3218,7 @@ var GridBackground = import_react5.default.memo(
|
|
|
3218
3218
|
`gridline-${index}`
|
|
3219
3219
|
);
|
|
3220
3220
|
})
|
|
3221
|
-
)
|
|
3221
|
+
))
|
|
3222
3222
|
]
|
|
3223
3223
|
}
|
|
3224
3224
|
);
|
|
@@ -5542,19 +5542,6 @@ var TaskListRow = import_react10.default.memo(
|
|
|
5542
5542
|
);
|
|
5543
5543
|
const isSelectedPredecessor = selectedChip != null && selectedChip.predecessorId === task.id;
|
|
5544
5544
|
const isSelectedDependencyOwner = selectedChip != null && selectedChip.successorId === task.id;
|
|
5545
|
-
const handleDeleteSelected = (0, import_react10.useCallback)(
|
|
5546
|
-
(e) => {
|
|
5547
|
-
e.stopPropagation();
|
|
5548
|
-
if (!selectedChip) return;
|
|
5549
|
-
onRemoveDependency?.(
|
|
5550
|
-
selectedChip.successorId,
|
|
5551
|
-
selectedChip.predecessorId,
|
|
5552
|
-
selectedChip.linkType
|
|
5553
|
-
);
|
|
5554
|
-
onChipSelect?.(null);
|
|
5555
|
-
},
|
|
5556
|
-
[selectedChip?.successorId, selectedChip?.predecessorId, selectedChip?.linkType, onRemoveDependency, onChipSelect]
|
|
5557
|
-
);
|
|
5558
5545
|
const startDateISO = toISODate2(normalizedTask.startDate);
|
|
5559
5546
|
const endDateISO = editingDuration ? getEndDate(normalizedTask.startDate, durationValue) : toISODate2(normalizedTask.endDate);
|
|
5560
5547
|
const numberCell = /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
@@ -5766,7 +5753,7 @@ var TaskListRow = import_react10.default.memo(
|
|
|
5766
5753
|
"aria-hidden": "true"
|
|
5767
5754
|
}
|
|
5768
5755
|
),
|
|
5769
|
-
!editingName && (onInsertAfter || onDelete || onPromoteTask || onDemoteTask || onUngroupTask || onDuplicateTask || onTasksChange || hasContextMenu) && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "gantt-tl-name-actions"
|
|
5756
|
+
!editingName && (onInsertAfter || onDelete || onPromoteTask || onDemoteTask || onUngroupTask || onDuplicateTask || onTasksChange || hasContextMenu) && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: `gantt-tl-name-actions${contextMenuOpen ? " gantt-tl-name-actions-open" : ""}`, children: [
|
|
5770
5757
|
onInsertAfter && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
5771
5758
|
"button",
|
|
5772
5759
|
{
|
|
@@ -6182,22 +6169,7 @@ var TaskListRow = import_react10.default.memo(
|
|
|
6182
6169
|
}
|
|
6183
6170
|
),
|
|
6184
6171
|
sourcePickerContent
|
|
6185
|
-
] }) :
|
|
6186
|
-
/* Full-replacement: "Зависит от [name]" → hover → "Удалить" */
|
|
6187
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
6188
|
-
"button",
|
|
6189
|
-
{
|
|
6190
|
-
type: "button",
|
|
6191
|
-
className: "gantt-tl-dep-delete-label",
|
|
6192
|
-
onClick: handleDeleteSelected,
|
|
6193
|
-
"aria-label": "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0441\u0432\u044F\u0437\u044C",
|
|
6194
|
-
children: [
|
|
6195
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "gantt-tl-dep-delete-label-default", children: "\u0421\u0432\u044F\u0437\u0430\u043D\u043E \u0441" }),
|
|
6196
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "gantt-tl-dep-delete-label-hover", children: "\xD7 \u0443\u0434\u0430\u043B\u0438\u0442\u044C" })
|
|
6197
|
-
]
|
|
6198
|
-
}
|
|
6199
|
-
)
|
|
6200
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
|
|
6172
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
|
|
6201
6173
|
chips.length >= 2 ? (
|
|
6202
6174
|
/* 2+ deps — show only "N связей" summary chip that opens a popover */
|
|
6203
6175
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Popover, { open: overflowOpen, onOpenChange: setOverflowOpen, children: [
|
|
@@ -7447,6 +7419,33 @@ var calculateConflictInfo = (parsedItems) => {
|
|
|
7447
7419
|
}
|
|
7448
7420
|
return result;
|
|
7449
7421
|
};
|
|
7422
|
+
var countConflictOverlaps = (items) => {
|
|
7423
|
+
const conflictsByItemId = new Map(items.map((item) => [item.itemId, item.conflictsWith]));
|
|
7424
|
+
const visited = /* @__PURE__ */ new Set();
|
|
7425
|
+
let overlapCount = 0;
|
|
7426
|
+
for (const item of items) {
|
|
7427
|
+
if (visited.has(item.itemId) || item.conflictsWith.length === 0) {
|
|
7428
|
+
continue;
|
|
7429
|
+
}
|
|
7430
|
+
const stack = [item.itemId];
|
|
7431
|
+
let componentSize = 0;
|
|
7432
|
+
while (stack.length > 0) {
|
|
7433
|
+
const itemId = stack.pop();
|
|
7434
|
+
if (visited.has(itemId)) {
|
|
7435
|
+
continue;
|
|
7436
|
+
}
|
|
7437
|
+
visited.add(itemId);
|
|
7438
|
+
componentSize += 1;
|
|
7439
|
+
for (const conflictId of conflictsByItemId.get(itemId) ?? []) {
|
|
7440
|
+
if (!visited.has(conflictId)) {
|
|
7441
|
+
stack.push(conflictId);
|
|
7442
|
+
}
|
|
7443
|
+
}
|
|
7444
|
+
}
|
|
7445
|
+
overlapCount += Math.max(0, componentSize - 1);
|
|
7446
|
+
}
|
|
7447
|
+
return overlapCount;
|
|
7448
|
+
};
|
|
7450
7449
|
var layoutResourceTimelineItems = (resources, options) => {
|
|
7451
7450
|
const rows = [];
|
|
7452
7451
|
const items = [];
|
|
@@ -7506,7 +7505,7 @@ var layoutResourceTimelineItems = (resources, options) => {
|
|
|
7506
7505
|
}
|
|
7507
7506
|
const laneCount = Math.max(1, laneEndDays.length);
|
|
7508
7507
|
const resourceRowHeight = laneCount * options.laneHeight;
|
|
7509
|
-
const conflictCount = laidOutItems
|
|
7508
|
+
const conflictCount = countConflictOverlaps(laidOutItems);
|
|
7510
7509
|
const row = {
|
|
7511
7510
|
resource,
|
|
7512
7511
|
resourceId: resource.id,
|
|
@@ -7751,7 +7750,8 @@ var DEFAULT_ROW_HEADER_WIDTH = 240;
|
|
|
7751
7750
|
var DEFAULT_RESOURCE_ROW_GAP = 8;
|
|
7752
7751
|
var ITEM_OUTER_VERTICAL_INSET = 2;
|
|
7753
7752
|
var ITEM_INNER_VERTICAL_INSET = 1;
|
|
7754
|
-
var
|
|
7753
|
+
var ITEM_START_HORIZONTAL_INSET = 2;
|
|
7754
|
+
var ITEM_END_HORIZONTAL_INSET = 1;
|
|
7755
7755
|
var isValidDate = (date) => !Number.isNaN(date.getTime());
|
|
7756
7756
|
var collectValidItems = (resources) => {
|
|
7757
7757
|
return resources.flatMap(
|
|
@@ -7773,12 +7773,18 @@ var getVisualItemGeometry = (geometry, laneIndex, laneCount) => {
|
|
|
7773
7773
|
const topInset = laneIndex === 0 ? ITEM_OUTER_VERTICAL_INSET : ITEM_INNER_VERTICAL_INSET;
|
|
7774
7774
|
const bottomInset = laneIndex === laneCount - 1 ? ITEM_OUTER_VERTICAL_INSET : ITEM_INNER_VERTICAL_INSET;
|
|
7775
7775
|
return {
|
|
7776
|
-
left: geometry.left +
|
|
7776
|
+
left: geometry.left + ITEM_START_HORIZONTAL_INSET,
|
|
7777
7777
|
top: geometry.top + topInset,
|
|
7778
|
-
width: Math.max(
|
|
7778
|
+
width: Math.max(1, geometry.width - ITEM_START_HORIZONTAL_INSET - ITEM_END_HORIZONTAL_INSET),
|
|
7779
7779
|
height: Math.max(0, geometry.height - topInset - bottomInset)
|
|
7780
7780
|
};
|
|
7781
7781
|
};
|
|
7782
|
+
var formatOverlapCount = (count) => {
|
|
7783
|
+
const mod10 = count % 10;
|
|
7784
|
+
const mod100 = count % 100;
|
|
7785
|
+
const word = mod10 === 1 && mod100 !== 11 ? "\u043D\u0430\u043B\u043E\u0436\u0435\u043D\u0438\u0435" : mod10 >= 2 && mod10 <= 4 && (mod100 < 12 || mod100 > 14) ? "\u043D\u0430\u043B\u043E\u0436\u0435\u043D\u0438\u044F" : "\u043D\u0430\u043B\u043E\u0436\u0435\u043D\u0438\u0439";
|
|
7786
|
+
return `${count} ${word}`;
|
|
7787
|
+
};
|
|
7782
7788
|
var getWeekendOverlaySegments = (startDate, endDate, dayWidth, weekendPredicate) => {
|
|
7783
7789
|
const segments2 = [];
|
|
7784
7790
|
const current = new Date(Date.UTC(startDate.getUTCFullYear(), startDate.getUTCMonth(), startDate.getUTCDate()));
|
|
@@ -7821,7 +7827,143 @@ var getRangeOverlaySegments = (itemStartDate, ranges, dayWidth) => {
|
|
|
7821
7827
|
};
|
|
7822
7828
|
});
|
|
7823
7829
|
};
|
|
7830
|
+
var clampOverlaySegments = (segments2, maxWidth) => segments2.flatMap((segment) => {
|
|
7831
|
+
const left = Math.max(0, Math.min(segment.left, maxWidth));
|
|
7832
|
+
const right = Math.max(left, Math.min(segment.left + segment.width, maxWidth));
|
|
7833
|
+
const width = right - left;
|
|
7834
|
+
return width > 0 ? [{ left, width }] : [];
|
|
7835
|
+
});
|
|
7824
7836
|
var getDurationValue = (startDate, endDate, businessDays, weekendPredicate) => businessDays ? getBusinessDaysCount(startDate, endDate, weekendPredicate) : Math.max(1, Math.round((endDate.getTime() - startDate.getTime()) / (24 * 60 * 60 * 1e3)) + 1);
|
|
7837
|
+
var ResourceHeader = ({
|
|
7838
|
+
resource,
|
|
7839
|
+
resourceId,
|
|
7840
|
+
conflictCount,
|
|
7841
|
+
height,
|
|
7842
|
+
paddingBottom,
|
|
7843
|
+
menuCommands
|
|
7844
|
+
}) => {
|
|
7845
|
+
const [menuOpen, setMenuOpen] = (0, import_react14.useState)(false);
|
|
7846
|
+
const visibleCommands = (0, import_react14.useMemo)(
|
|
7847
|
+
() => menuCommands.filter((command) => command.isVisible?.(resource) ?? true),
|
|
7848
|
+
[menuCommands, resource]
|
|
7849
|
+
);
|
|
7850
|
+
const hasMenu = visibleCommands.length > 0;
|
|
7851
|
+
const handleCommandClick = (command, event) => {
|
|
7852
|
+
event.stopPropagation();
|
|
7853
|
+
if (command.closeOnSelect !== false) {
|
|
7854
|
+
setMenuOpen(false);
|
|
7855
|
+
}
|
|
7856
|
+
command.onSelect(resource);
|
|
7857
|
+
};
|
|
7858
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
7859
|
+
"div",
|
|
7860
|
+
{
|
|
7861
|
+
className: `gantt-resourceTimeline-resourceHeader${menuOpen ? " gantt-resourceTimeline-resourceHeaderMenuOpen" : ""}`,
|
|
7862
|
+
"data-resource-row-id": resourceId,
|
|
7863
|
+
style: {
|
|
7864
|
+
height: `${height}px`,
|
|
7865
|
+
paddingBottom: `${paddingBottom}px`
|
|
7866
|
+
},
|
|
7867
|
+
children: [
|
|
7868
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "gantt-resourceTimeline-resourceName", children: resource.name }),
|
|
7869
|
+
conflictCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
7870
|
+
"span",
|
|
7871
|
+
{
|
|
7872
|
+
className: "gantt-resourceTimeline-conflictBadge",
|
|
7873
|
+
"aria-label": formatOverlapCount(conflictCount),
|
|
7874
|
+
title: formatOverlapCount(conflictCount),
|
|
7875
|
+
children: conflictCount
|
|
7876
|
+
}
|
|
7877
|
+
),
|
|
7878
|
+
hasMenu && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Popover, { open: menuOpen, onOpenChange: setMenuOpen, children: [
|
|
7879
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
7880
|
+
"button",
|
|
7881
|
+
{
|
|
7882
|
+
className: "gantt-resourceTimeline-resourceMenuButton",
|
|
7883
|
+
type: "button",
|
|
7884
|
+
"aria-label": "\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u044F \u0440\u0435\u0441\u0443\u0440\u0441\u0430",
|
|
7885
|
+
onClick: (event) => {
|
|
7886
|
+
event.stopPropagation();
|
|
7887
|
+
setMenuOpen((open) => !open);
|
|
7888
|
+
},
|
|
7889
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { "aria-hidden": "true", children: "\u22EE" })
|
|
7890
|
+
}
|
|
7891
|
+
) }),
|
|
7892
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(PopoverContent, { className: "gantt-resourceTimeline-resourceMenu", portal: true, align: "end", children: visibleCommands.map((command) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
7893
|
+
"button",
|
|
7894
|
+
{
|
|
7895
|
+
type: "button",
|
|
7896
|
+
className: `gantt-resourceTimeline-resourceMenuItem${command.danger ? " gantt-resourceTimeline-resourceMenuItemDanger" : ""}`,
|
|
7897
|
+
disabled: command.isDisabled?.(resource) ?? false,
|
|
7898
|
+
onClick: (event) => handleCommandClick(command, event),
|
|
7899
|
+
children: [
|
|
7900
|
+
command.icon,
|
|
7901
|
+
command.label
|
|
7902
|
+
]
|
|
7903
|
+
},
|
|
7904
|
+
command.id
|
|
7905
|
+
)) })
|
|
7906
|
+
] })
|
|
7907
|
+
]
|
|
7908
|
+
}
|
|
7909
|
+
);
|
|
7910
|
+
};
|
|
7911
|
+
var NewResourceRow = ({ height, onConfirm, onCancel }) => {
|
|
7912
|
+
const [nameValue, setNameValue] = (0, import_react14.useState)("");
|
|
7913
|
+
const inputRef = (0, import_react14.useRef)(null);
|
|
7914
|
+
const confirmedRef = (0, import_react14.useRef)(false);
|
|
7915
|
+
(0, import_react14.useEffect)(() => {
|
|
7916
|
+
inputRef.current?.focus();
|
|
7917
|
+
inputRef.current?.select();
|
|
7918
|
+
}, []);
|
|
7919
|
+
const handleCancel = () => {
|
|
7920
|
+
confirmedRef.current = true;
|
|
7921
|
+
onCancel();
|
|
7922
|
+
};
|
|
7923
|
+
const handleConfirm = () => {
|
|
7924
|
+
const name = nameValue.trim();
|
|
7925
|
+
if (!name) {
|
|
7926
|
+
handleCancel();
|
|
7927
|
+
return;
|
|
7928
|
+
}
|
|
7929
|
+
confirmedRef.current = true;
|
|
7930
|
+
onConfirm(name);
|
|
7931
|
+
};
|
|
7932
|
+
const handleKeyDown = (event) => {
|
|
7933
|
+
if (event.key === "Enter") {
|
|
7934
|
+
handleConfirm();
|
|
7935
|
+
} else if (event.key === "Escape") {
|
|
7936
|
+
handleCancel();
|
|
7937
|
+
}
|
|
7938
|
+
};
|
|
7939
|
+
const handleBlur = () => {
|
|
7940
|
+
if (!confirmedRef.current) {
|
|
7941
|
+
handleConfirm();
|
|
7942
|
+
}
|
|
7943
|
+
};
|
|
7944
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
7945
|
+
"div",
|
|
7946
|
+
{
|
|
7947
|
+
className: "gantt-resourceTimeline-resourceHeader gantt-resourceTimeline-resourceHeaderNew",
|
|
7948
|
+
style: {
|
|
7949
|
+
height: `${height}px`,
|
|
7950
|
+
paddingBottom: `${DEFAULT_RESOURCE_ROW_GAP}px`
|
|
7951
|
+
},
|
|
7952
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
7953
|
+
Input,
|
|
7954
|
+
{
|
|
7955
|
+
ref: inputRef,
|
|
7956
|
+
value: nameValue,
|
|
7957
|
+
onChange: (event) => setNameValue(event.target.value),
|
|
7958
|
+
onKeyDown: handleKeyDown,
|
|
7959
|
+
onBlur: handleBlur,
|
|
7960
|
+
placeholder: "\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u0430",
|
|
7961
|
+
className: "gantt-resourceTimeline-resourceInput"
|
|
7962
|
+
}
|
|
7963
|
+
)
|
|
7964
|
+
}
|
|
7965
|
+
);
|
|
7966
|
+
};
|
|
7825
7967
|
function ResourceTimelineChart({
|
|
7826
7968
|
resources,
|
|
7827
7969
|
dayWidth = DEFAULT_DAY_WIDTH,
|
|
@@ -7839,11 +7981,15 @@ function ResourceTimelineChart({
|
|
|
7839
7981
|
renderItem,
|
|
7840
7982
|
getItemClassName,
|
|
7841
7983
|
onResourceItemClick,
|
|
7842
|
-
onResourceItemMove
|
|
7984
|
+
onResourceItemMove,
|
|
7985
|
+
onAddResource,
|
|
7986
|
+
enableAddResource = true,
|
|
7987
|
+
resourceMenuCommands = []
|
|
7843
7988
|
}) {
|
|
7844
7989
|
const scrollContainerRef = (0, import_react14.useRef)(null);
|
|
7845
7990
|
const gridRef = (0, import_react14.useRef)(null);
|
|
7846
7991
|
const panStateRef = (0, import_react14.useRef)(null);
|
|
7992
|
+
const [isCreatingResource, setIsCreatingResource] = (0, import_react14.useState)(false);
|
|
7847
7993
|
const validItems = (0, import_react14.useMemo)(() => collectValidItems(resources), [resources]);
|
|
7848
7994
|
const dateRange = (0, import_react14.useMemo)(() => getMultiMonthDays(validItems), [validItems]);
|
|
7849
7995
|
const monthStart = (0, import_react14.useMemo)(() => {
|
|
@@ -7878,6 +8024,18 @@ function ResourceTimelineChart({
|
|
|
7878
8024
|
}
|
|
7879
8025
|
return map;
|
|
7880
8026
|
}, [layout.items]);
|
|
8027
|
+
const canAddResource = enableAddResource && Boolean(onAddResource);
|
|
8028
|
+
const resourceAddRowHeight = laneHeight + DEFAULT_RESOURCE_ROW_GAP;
|
|
8029
|
+
const displayTotalHeight = layout.totalHeight + (canAddResource ? resourceAddRowHeight : 0);
|
|
8030
|
+
const handleConfirmNewResource = (0, import_react14.useCallback)((name) => {
|
|
8031
|
+
onAddResource?.({
|
|
8032
|
+
id: crypto.randomUUID(),
|
|
8033
|
+
name,
|
|
8034
|
+
items: []
|
|
8035
|
+
});
|
|
8036
|
+
setIsCreatingResource(false);
|
|
8037
|
+
}, [onAddResource]);
|
|
8038
|
+
const handleCancelNewResource = (0, import_react14.useCallback)(() => setIsCreatingResource(false), []);
|
|
7881
8039
|
const { preview, startDrag } = useResourceItemDrag({
|
|
7882
8040
|
dayWidth,
|
|
7883
8041
|
monthStart,
|
|
@@ -7972,28 +8130,34 @@ function ResourceTimelineChart({
|
|
|
7972
8130
|
style: { height: `${headerHeight}px` }
|
|
7973
8131
|
}
|
|
7974
8132
|
),
|
|
7975
|
-
layout.rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime15.
|
|
7976
|
-
|
|
8133
|
+
layout.rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
8134
|
+
ResourceHeader,
|
|
7977
8135
|
{
|
|
7978
|
-
|
|
7979
|
-
|
|
7980
|
-
|
|
7981
|
-
|
|
7982
|
-
|
|
7983
|
-
|
|
7984
|
-
children: [
|
|
7985
|
-
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "gantt-resourceTimeline-resourceName", children: row.resource.name }),
|
|
7986
|
-
row.conflictCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
7987
|
-
"span",
|
|
7988
|
-
{
|
|
7989
|
-
className: "gantt-resourceTimeline-conflictBadge",
|
|
7990
|
-
"aria-label": `${row.conflictCount} \u043A\u043E\u043D\u0444\u043B\u0438\u043A\u0442\u043E\u0432`,
|
|
7991
|
-
children: row.conflictCount
|
|
7992
|
-
}
|
|
7993
|
-
)
|
|
7994
|
-
]
|
|
8136
|
+
resource: row.resource,
|
|
8137
|
+
resourceId: row.resourceId,
|
|
8138
|
+
conflictCount: row.conflictCount,
|
|
8139
|
+
height: row.resourceRowHeight + DEFAULT_RESOURCE_ROW_GAP,
|
|
8140
|
+
paddingBottom: DEFAULT_RESOURCE_ROW_GAP,
|
|
8141
|
+
menuCommands: resourceMenuCommands
|
|
7995
8142
|
},
|
|
7996
8143
|
row.resourceId
|
|
8144
|
+
)),
|
|
8145
|
+
canAddResource && (isCreatingResource ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
8146
|
+
NewResourceRow,
|
|
8147
|
+
{
|
|
8148
|
+
height: resourceAddRowHeight,
|
|
8149
|
+
onConfirm: handleConfirmNewResource,
|
|
8150
|
+
onCancel: handleCancelNewResource
|
|
8151
|
+
}
|
|
8152
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
8153
|
+
"button",
|
|
8154
|
+
{
|
|
8155
|
+
className: "gantt-resourceTimeline-addResourceButton",
|
|
8156
|
+
type: "button",
|
|
8157
|
+
style: { height: `${resourceAddRowHeight}px` },
|
|
8158
|
+
onClick: () => setIsCreatingResource(true),
|
|
8159
|
+
children: "+ \u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0440\u0435\u0441\u0443\u0440\u0441"
|
|
8160
|
+
}
|
|
7997
8161
|
))
|
|
7998
8162
|
]
|
|
7999
8163
|
}
|
|
@@ -8019,14 +8183,14 @@ function ResourceTimelineChart({
|
|
|
8019
8183
|
{
|
|
8020
8184
|
ref: gridRef,
|
|
8021
8185
|
className: "gantt-resourceTimeline-grid",
|
|
8022
|
-
style: { width: `${gridWidth}px`, height: `${
|
|
8186
|
+
style: { width: `${gridWidth}px`, height: `${displayTotalHeight}px` },
|
|
8023
8187
|
children: [
|
|
8024
8188
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
8025
8189
|
GridBackground_default,
|
|
8026
8190
|
{
|
|
8027
8191
|
dateRange,
|
|
8028
8192
|
dayWidth,
|
|
8029
|
-
totalHeight:
|
|
8193
|
+
totalHeight: displayTotalHeight,
|
|
8030
8194
|
viewMode,
|
|
8031
8195
|
isCustomWeekend: weekendPredicate
|
|
8032
8196
|
}
|
|
@@ -8044,6 +8208,17 @@ function ResourceTimelineChart({
|
|
|
8044
8208
|
},
|
|
8045
8209
|
row.resourceId
|
|
8046
8210
|
)),
|
|
8211
|
+
canAddResource && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
8212
|
+
"div",
|
|
8213
|
+
{
|
|
8214
|
+
className: "gantt-resourceTimeline-row gantt-resourceTimeline-rowNew",
|
|
8215
|
+
"data-resource-add-row": "true",
|
|
8216
|
+
style: {
|
|
8217
|
+
top: `${layout.totalHeight}px`,
|
|
8218
|
+
height: `${resourceAddRowHeight}px`
|
|
8219
|
+
}
|
|
8220
|
+
}
|
|
8221
|
+
),
|
|
8047
8222
|
Array.from(itemsByResourceId.values()).flatMap(
|
|
8048
8223
|
(resourceItems) => resourceItems.map((layoutItem) => {
|
|
8049
8224
|
const customClassName = getItemClassName?.(layoutItem.item);
|
|
@@ -8069,11 +8244,17 @@ function ResourceTimelineChart({
|
|
|
8069
8244
|
}, layoutItem.laneIndex, laneCount);
|
|
8070
8245
|
const overlayStartDate = isDraggingItem ? preview.startDate : layoutItem.startDate;
|
|
8071
8246
|
const overlayEndDate = isDraggingItem ? preview.endDate : layoutItem.endDate;
|
|
8072
|
-
const weekendOverlaySegments = businessDays ?
|
|
8073
|
-
|
|
8074
|
-
|
|
8075
|
-
|
|
8076
|
-
|
|
8247
|
+
const weekendOverlaySegments = businessDays ? clampOverlaySegments(
|
|
8248
|
+
getWeekendOverlaySegments(overlayStartDate, overlayEndDate, dayWidth, weekendPredicate),
|
|
8249
|
+
itemGeometry.width
|
|
8250
|
+
) : [];
|
|
8251
|
+
const conflictOverlaySegments = clampOverlaySegments(
|
|
8252
|
+
getRangeOverlaySegments(
|
|
8253
|
+
overlayStartDate,
|
|
8254
|
+
isDraggingItem ? [] : layoutItem.conflictRanges,
|
|
8255
|
+
dayWidth
|
|
8256
|
+
),
|
|
8257
|
+
itemGeometry.width
|
|
8077
8258
|
);
|
|
8078
8259
|
const durationValue = getDurationValue(
|
|
8079
8260
|
overlayStartDate,
|
|
@@ -9232,6 +9413,11 @@ var not = (predicate) => (task) => !predicate(task);
|
|
|
9232
9413
|
var withoutDeps = (options = {}) => (task) => {
|
|
9233
9414
|
if (!task) return false;
|
|
9234
9415
|
if (options.onlyChildren && !task.parentId) return false;
|
|
9416
|
+
if (options.onlyLeafTasks) {
|
|
9417
|
+
const isParent = (options.tasks ?? []).some((candidate) => candidate.parentId === task.id);
|
|
9418
|
+
const isRegularTask = task.type == null || task.type === "task";
|
|
9419
|
+
if (isParent || !isRegularTask) return false;
|
|
9420
|
+
}
|
|
9235
9421
|
return !task.dependencies || task.dependencies.length === 0;
|
|
9236
9422
|
};
|
|
9237
9423
|
var expired = (referenceDate = /* @__PURE__ */ new Date()) => (task) => isTaskExpired(task, referenceDate);
|