gantt-lib 0.81.0 → 0.83.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/scheduling/index.d.mts +1 -1
- package/dist/core/scheduling/index.d.ts +1 -1
- package/dist/{index-p-aPnDwQ.d.mts → index-DGOZyXZt.d.mts} +5 -0
- package/dist/{index-p-aPnDwQ.d.ts → index-DGOZyXZt.d.ts} +5 -0
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +594 -79
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +594 -79
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +408 -19
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -7023,6 +7023,7 @@ var TaskList = ({
|
|
|
7023
7023
|
[resolvedColumns]
|
|
7024
7024
|
);
|
|
7025
7025
|
const effectiveTaskListWidth = Math.max(taskListWidth, MIN_TASK_LIST_WIDTH, resolvedColumnWidthTotal);
|
|
7026
|
+
const tableHeaderHeight = headerHeight + 1;
|
|
7026
7027
|
return /* @__PURE__ */ jsx14(
|
|
7027
7028
|
"div",
|
|
7028
7029
|
{
|
|
@@ -7030,7 +7031,7 @@ var TaskList = ({
|
|
|
7030
7031
|
className: `gantt-tl-overlay${show ? "" : " gantt-tl-hidden"}${hasRightShadow ? " gantt-tl-overlay-shadowed" : ""}`,
|
|
7031
7032
|
style: { "--tasklist-width": `${effectiveTaskListWidth}px` },
|
|
7032
7033
|
children: /* @__PURE__ */ jsxs11("div", { className: "gantt-tl-table", children: [
|
|
7033
|
-
/* @__PURE__ */ jsx14("div", { className: "gantt-tl-header", style: { height: `${
|
|
7034
|
+
/* @__PURE__ */ jsx14("div", { className: "gantt-tl-header", style: { height: `${tableHeaderHeight}px` }, children: resolvedColumns.map((col) => {
|
|
7034
7035
|
if (col.id === "dependencies") {
|
|
7035
7036
|
return /* @__PURE__ */ jsxs11(
|
|
7036
7037
|
"div",
|
|
@@ -7214,7 +7215,7 @@ var TaskList = ({
|
|
|
7214
7215
|
};
|
|
7215
7216
|
|
|
7216
7217
|
// src/components/ResourceTimelineChart/ResourceTimelineChart.tsx
|
|
7217
|
-
import { useCallback as useCallback7, useEffect as useEffect8, useMemo as useMemo9, useRef as useRef8, useState as useState8 } from "react";
|
|
7218
|
+
import React12, { useCallback as useCallback7, useEffect as useEffect8, useMemo as useMemo9, useRef as useRef8, useState as useState8 } from "react";
|
|
7218
7219
|
|
|
7219
7220
|
// src/utils/resourceTimelineLayout.ts
|
|
7220
7221
|
var isInvalidDate = (date) => Number.isNaN(date.getTime());
|
|
@@ -7632,8 +7633,9 @@ import { Fragment as Fragment3, jsx as jsx15, jsxs as jsxs12 } from "react/jsx-r
|
|
|
7632
7633
|
var DEFAULT_DAY_WIDTH = 40;
|
|
7633
7634
|
var DEFAULT_HEADER_HEIGHT = 40;
|
|
7634
7635
|
var DEFAULT_LANE_HEIGHT = 40;
|
|
7635
|
-
var DEFAULT_ROW_HEADER_WIDTH =
|
|
7636
|
+
var DEFAULT_ROW_HEADER_WIDTH = 420;
|
|
7636
7637
|
var DEFAULT_RESOURCE_ROW_GAP = 8;
|
|
7638
|
+
var DEFAULT_RESOURCE_GROUP_HEIGHT = 28;
|
|
7637
7639
|
var ITEM_OUTER_VERTICAL_INSET = 2;
|
|
7638
7640
|
var ITEM_INNER_VERTICAL_INSET = 1;
|
|
7639
7641
|
var ITEM_START_HORIZONTAL_INSET = 2;
|
|
@@ -7720,21 +7722,114 @@ var clampOverlaySegments = (segments2, maxWidth) => segments2.flatMap((segment)
|
|
|
7720
7722
|
return width > 0 ? [{ left, width }] : [];
|
|
7721
7723
|
});
|
|
7722
7724
|
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);
|
|
7725
|
+
var RESOURCE_TYPE_OPTIONS = ["\u041B\u044E\u0434\u0438", "\u041E\u0431\u043E\u0440\u0443\u0434\u043E\u0432\u0430\u043D\u0438\u0435", "\u041C\u0430\u0442\u0435\u0440\u0438\u0430\u043B\u044B", "\u0414\u0440\u0443\u0433\u043E\u0435"];
|
|
7726
|
+
var RESOURCE_SCOPE_OPTIONS = ["Shared", "Project"];
|
|
7727
|
+
var RESOURCE_SCOPE_LABELS = {
|
|
7728
|
+
Shared: "\u041E\u0431\u0449\u0438\u0439",
|
|
7729
|
+
Project: "\u041F\u0440\u043E\u0435\u043A\u0442"
|
|
7730
|
+
};
|
|
7731
|
+
var RESOURCE_TYPE_CLASS_NAMES = {
|
|
7732
|
+
\u041B\u044E\u0434\u0438: "People",
|
|
7733
|
+
\u041E\u0431\u043E\u0440\u0443\u0434\u043E\u0432\u0430\u043D\u0438\u0435: "Equipment",
|
|
7734
|
+
\u041C\u0430\u0442\u0435\u0440\u0438\u0430\u043B\u044B: "Materials",
|
|
7735
|
+
\u0414\u0440\u0443\u0433\u043E\u0435: "Other"
|
|
7736
|
+
};
|
|
7737
|
+
var RESOURCE_TYPE_ORDER = {
|
|
7738
|
+
\u041B\u044E\u0434\u0438: 0,
|
|
7739
|
+
\u041E\u0431\u043E\u0440\u0443\u0434\u043E\u0432\u0430\u043D\u0438\u0435: 1,
|
|
7740
|
+
\u041C\u0430\u0442\u0435\u0440\u0438\u0430\u043B\u044B: 2,
|
|
7741
|
+
\u0414\u0440\u0443\u0433\u043E\u0435: 3
|
|
7742
|
+
};
|
|
7743
|
+
var RESOURCE_SCOPE_ORDER = {
|
|
7744
|
+
Shared: 0,
|
|
7745
|
+
Project: 1
|
|
7746
|
+
};
|
|
7747
|
+
var getResourceType = (resource) => resource.type ?? "\u0414\u0440\u0443\u0433\u043E\u0435";
|
|
7748
|
+
var getResourceScopeOrder = (resource) => RESOURCE_SCOPE_ORDER[resource.scope ?? "Project"] ?? 99;
|
|
7749
|
+
var orderResourcesByType = (resources) => {
|
|
7750
|
+
return resources.map((resource, index) => ({ resource, index })).sort((left, right) => {
|
|
7751
|
+
const leftType = getResourceType(left.resource);
|
|
7752
|
+
const rightType = getResourceType(right.resource);
|
|
7753
|
+
const typeDiff = (RESOURCE_TYPE_ORDER[leftType] ?? 99) - (RESOURCE_TYPE_ORDER[rightType] ?? 99);
|
|
7754
|
+
if (typeDiff !== 0) {
|
|
7755
|
+
return typeDiff;
|
|
7756
|
+
}
|
|
7757
|
+
const scopeDiff = getResourceScopeOrder(left.resource) - getResourceScopeOrder(right.resource);
|
|
7758
|
+
return scopeDiff !== 0 ? scopeDiff : left.index - right.index;
|
|
7759
|
+
}).map(({ resource }) => resource);
|
|
7760
|
+
};
|
|
7761
|
+
var ResourceTypeIcon = ({ type }) => {
|
|
7762
|
+
if (type === "\u041B\u044E\u0434\u0438") {
|
|
7763
|
+
return /* @__PURE__ */ jsxs12("svg", { className: "gantt-resourceTimeline-resourceTypeIcon gantt-resourceTimeline-resourceTypeIconPeople", width: "16", height: "16", viewBox: "0 0 24 24", "aria-hidden": "true", children: [
|
|
7764
|
+
/* @__PURE__ */ jsx15("path", { d: "M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" }),
|
|
7765
|
+
/* @__PURE__ */ jsx15("circle", { cx: "9", cy: "7", r: "4" }),
|
|
7766
|
+
/* @__PURE__ */ jsx15("path", { d: "M22 21v-2a4 4 0 0 0-3-3.87" }),
|
|
7767
|
+
/* @__PURE__ */ jsx15("path", { d: "M16 3.13a4 4 0 0 1 0 7.75" })
|
|
7768
|
+
] });
|
|
7769
|
+
}
|
|
7770
|
+
if (type === "\u041E\u0431\u043E\u0440\u0443\u0434\u043E\u0432\u0430\u043D\u0438\u0435") {
|
|
7771
|
+
return /* @__PURE__ */ jsxs12("svg", { className: "gantt-resourceTimeline-resourceTypeIcon gantt-resourceTimeline-resourceTypeIconEquipment", width: "16", height: "16", viewBox: "0 0 24 24", "aria-hidden": "true", children: [
|
|
7772
|
+
/* @__PURE__ */ jsx15("path", { d: "m15 12-9.373 9.373a1 1 0 0 1-3.001-3L12 9" }),
|
|
7773
|
+
/* @__PURE__ */ jsx15("path", { d: "m18 15 4-4" }),
|
|
7774
|
+
/* @__PURE__ */ jsx15("path", { d: "m21.5 11.5-1.914-1.914A2 2 0 0 1 19 8.172v-.344a2 2 0 0 0-.586-1.414l-1.657-1.657A6 6 0 0 0 12.516 3H9l1.243 1.243A6 6 0 0 1 12 8.485V10l2 2h1.172a2 2 0 0 1 1.414.586L18.5 14.5" })
|
|
7775
|
+
] });
|
|
7776
|
+
}
|
|
7777
|
+
if (type === "\u041C\u0430\u0442\u0435\u0440\u0438\u0430\u043B\u044B") {
|
|
7778
|
+
return /* @__PURE__ */ jsxs12("svg", { className: "gantt-resourceTimeline-resourceTypeIcon gantt-resourceTimeline-resourceTypeIconMaterials", width: "16", height: "16", viewBox: "0 0 24 24", "aria-hidden": "true", children: [
|
|
7779
|
+
/* @__PURE__ */ jsx15("path", { d: "M10 22v-8" }),
|
|
7780
|
+
/* @__PURE__ */ jsx15("path", { d: "M2.336 8.89 10 14l11.715-7.029" }),
|
|
7781
|
+
/* @__PURE__ */ jsx15("path", { d: "M22 14a2 2 0 0 1-.971 1.715l-10 6a2 2 0 0 1-2.138-.05l-6-4A2 2 0 0 1 2 16v-6a2 2 0 0 1 .971-1.715l10-6a2 2 0 0 1 2.138.05l6 4A2 2 0 0 1 22 8z" })
|
|
7782
|
+
] });
|
|
7783
|
+
}
|
|
7784
|
+
return /* @__PURE__ */ jsxs12("svg", { className: "gantt-resourceTimeline-resourceTypeIcon gantt-resourceTimeline-resourceTypeIconOther", width: "16", height: "16", viewBox: "0 0 24 24", "aria-hidden": "true", children: [
|
|
7785
|
+
/* @__PURE__ */ jsx15("circle", { cx: "12", cy: "12", r: "9" }),
|
|
7786
|
+
/* @__PURE__ */ jsx15("path", { d: "M12 8v4" }),
|
|
7787
|
+
/* @__PURE__ */ jsx15("path", { d: "M12 16h.01" })
|
|
7788
|
+
] });
|
|
7789
|
+
};
|
|
7723
7790
|
var ResourceHeader = ({
|
|
7724
7791
|
resource,
|
|
7725
7792
|
resourceId,
|
|
7793
|
+
rowIndex,
|
|
7726
7794
|
conflictCount,
|
|
7795
|
+
workedDays,
|
|
7796
|
+
assignmentCount,
|
|
7727
7797
|
height,
|
|
7728
7798
|
paddingBottom,
|
|
7729
7799
|
menuCommands,
|
|
7800
|
+
onResourceChange,
|
|
7801
|
+
onResourceNameClick,
|
|
7730
7802
|
onConflictBadgeClick
|
|
7731
7803
|
}) => {
|
|
7732
7804
|
const [menuOpen, setMenuOpen] = useState8(false);
|
|
7805
|
+
const [typeMenuOpen, setTypeMenuOpen] = useState8(false);
|
|
7806
|
+
const [scopeMenuOpen, setScopeMenuOpen] = useState8(false);
|
|
7807
|
+
const [editingName, setEditingName] = useState8(false);
|
|
7808
|
+
const [nameValue, setNameValue] = useState8(resource.name);
|
|
7809
|
+
const nameInputRef = useRef8(null);
|
|
7810
|
+
const nameConfirmedRef = useRef8(false);
|
|
7733
7811
|
const visibleCommands = useMemo9(
|
|
7734
7812
|
() => menuCommands.filter((command) => command.isVisible?.(resource) ?? true),
|
|
7735
7813
|
[menuCommands, resource]
|
|
7736
7814
|
);
|
|
7737
7815
|
const hasMenu = visibleCommands.length > 0;
|
|
7816
|
+
const type = resource.type ?? "\u0414\u0440\u0443\u0433\u043E\u0435";
|
|
7817
|
+
const scope = resource.scope ?? "Project";
|
|
7818
|
+
const scopeLabel = RESOURCE_SCOPE_LABELS[scope] ?? scope;
|
|
7819
|
+
const applyResourcePatch = useCallback7((patch) => {
|
|
7820
|
+
onResourceChange?.({ ...resource, ...patch });
|
|
7821
|
+
}, [onResourceChange, resource]);
|
|
7822
|
+
useEffect8(() => {
|
|
7823
|
+
if (!editingName) {
|
|
7824
|
+
setNameValue(resource.name);
|
|
7825
|
+
}
|
|
7826
|
+
}, [editingName, resource.name]);
|
|
7827
|
+
useEffect8(() => {
|
|
7828
|
+
if (editingName && nameInputRef.current) {
|
|
7829
|
+
nameInputRef.current.focus();
|
|
7830
|
+
nameInputRef.current.select();
|
|
7831
|
+
}
|
|
7832
|
+
}, [editingName]);
|
|
7738
7833
|
const handleCommandClick = (command, event) => {
|
|
7739
7834
|
event.stopPropagation();
|
|
7740
7835
|
if (command.closeOnSelect !== false) {
|
|
@@ -7742,6 +7837,42 @@ var ResourceHeader = ({
|
|
|
7742
7837
|
}
|
|
7743
7838
|
command.onSelect(resource);
|
|
7744
7839
|
};
|
|
7840
|
+
const handleNameDoubleClick = useCallback7((event) => {
|
|
7841
|
+
if (!onResourceChange) {
|
|
7842
|
+
return;
|
|
7843
|
+
}
|
|
7844
|
+
event.stopPropagation();
|
|
7845
|
+
nameConfirmedRef.current = false;
|
|
7846
|
+
setNameValue(resource.name);
|
|
7847
|
+
setEditingName(true);
|
|
7848
|
+
}, [onResourceChange, resource.name]);
|
|
7849
|
+
const handleNameSave = useCallback7(() => {
|
|
7850
|
+
if (nameConfirmedRef.current) {
|
|
7851
|
+
nameConfirmedRef.current = false;
|
|
7852
|
+
return;
|
|
7853
|
+
}
|
|
7854
|
+
const nextName = nameValue.trim();
|
|
7855
|
+
if (nextName && nextName !== resource.name) {
|
|
7856
|
+
applyResourcePatch({ name: nextName });
|
|
7857
|
+
}
|
|
7858
|
+
setEditingName(false);
|
|
7859
|
+
}, [applyResourcePatch, nameValue, resource.name]);
|
|
7860
|
+
const handleNameCancel = useCallback7(() => {
|
|
7861
|
+
setNameValue(resource.name);
|
|
7862
|
+
setEditingName(false);
|
|
7863
|
+
}, [resource.name]);
|
|
7864
|
+
const handleNameKeyDown = useCallback7((event) => {
|
|
7865
|
+
if (event.key === "Enter") {
|
|
7866
|
+
nameConfirmedRef.current = true;
|
|
7867
|
+
const nextName = nameValue.trim();
|
|
7868
|
+
if (nextName && nextName !== resource.name) {
|
|
7869
|
+
applyResourcePatch({ name: nextName });
|
|
7870
|
+
}
|
|
7871
|
+
setEditingName(false);
|
|
7872
|
+
} else if (event.key === "Escape") {
|
|
7873
|
+
handleNameCancel();
|
|
7874
|
+
}
|
|
7875
|
+
}, [applyResourcePatch, handleNameCancel, nameValue, resource.name]);
|
|
7745
7876
|
return /* @__PURE__ */ jsxs12(
|
|
7746
7877
|
"div",
|
|
7747
7878
|
{
|
|
@@ -7752,49 +7883,167 @@ var ResourceHeader = ({
|
|
|
7752
7883
|
paddingBottom: `${paddingBottom}px`
|
|
7753
7884
|
},
|
|
7754
7885
|
children: [
|
|
7755
|
-
/* @__PURE__ */ jsx15("span", { className: "gantt-resourceTimeline-
|
|
7756
|
-
|
|
7757
|
-
|
|
7758
|
-
|
|
7759
|
-
|
|
7760
|
-
|
|
7761
|
-
|
|
7762
|
-
|
|
7763
|
-
|
|
7764
|
-
|
|
7765
|
-
|
|
7766
|
-
|
|
7767
|
-
|
|
7768
|
-
|
|
7769
|
-
|
|
7770
|
-
|
|
7886
|
+
/* @__PURE__ */ jsx15("span", { className: "gantt-resourceTimeline-resourceNumber", children: rowIndex + 1 }),
|
|
7887
|
+
/* @__PURE__ */ jsxs12("span", { className: "gantt-resourceTimeline-resourceName", children: [
|
|
7888
|
+
/* @__PURE__ */ jsxs12(Popover, { open: typeMenuOpen, onOpenChange: setTypeMenuOpen, children: [
|
|
7889
|
+
/* @__PURE__ */ jsx15(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx15(
|
|
7890
|
+
"button",
|
|
7891
|
+
{
|
|
7892
|
+
type: "button",
|
|
7893
|
+
className: `gantt-resourceTimeline-resourceTypeIconButton gantt-resourceTimeline-resourceTypeIconButton${RESOURCE_TYPE_CLASS_NAMES[type] ?? "Other"}`,
|
|
7894
|
+
disabled: !onResourceChange,
|
|
7895
|
+
"aria-label": `\u0422\u0438\u043F \u0440\u0435\u0441\u0443\u0440\u0441\u0430 ${resource.name}: ${type}`,
|
|
7896
|
+
title: type,
|
|
7897
|
+
onClick: (event) => {
|
|
7898
|
+
event.stopPropagation();
|
|
7899
|
+
setTypeMenuOpen((open) => !open);
|
|
7900
|
+
},
|
|
7901
|
+
children: /* @__PURE__ */ jsx15(ResourceTypeIcon, { type })
|
|
7902
|
+
}
|
|
7903
|
+
) }),
|
|
7904
|
+
/* @__PURE__ */ jsx15(PopoverContent, { className: "gantt-resourceTimeline-resourceOptionMenu", portal: true, align: "start", children: RESOURCE_TYPE_OPTIONS.map((option) => /* @__PURE__ */ jsxs12(
|
|
7905
|
+
"button",
|
|
7906
|
+
{
|
|
7907
|
+
type: "button",
|
|
7908
|
+
className: `gantt-resourceTimeline-resourceOption${type === option ? " gantt-resourceTimeline-resourceOptionActive" : ""}`,
|
|
7909
|
+
onClick: (event) => {
|
|
7910
|
+
event.stopPropagation();
|
|
7911
|
+
setTypeMenuOpen(false);
|
|
7912
|
+
applyResourcePatch({ type: option });
|
|
7913
|
+
},
|
|
7914
|
+
children: [
|
|
7915
|
+
/* @__PURE__ */ jsx15("span", { className: "gantt-resourceTimeline-resourceOptionIcon", children: /* @__PURE__ */ jsx15(ResourceTypeIcon, { type: option }) }),
|
|
7916
|
+
option
|
|
7917
|
+
]
|
|
7918
|
+
},
|
|
7919
|
+
option
|
|
7920
|
+
)) })
|
|
7921
|
+
] }),
|
|
7922
|
+
editingName ? /* @__PURE__ */ jsx15(
|
|
7923
|
+
Input,
|
|
7924
|
+
{
|
|
7925
|
+
ref: nameInputRef,
|
|
7926
|
+
value: nameValue,
|
|
7927
|
+
onChange: (event) => setNameValue(event.target.value),
|
|
7928
|
+
onBlur: handleNameSave,
|
|
7929
|
+
onKeyDown: handleNameKeyDown,
|
|
7930
|
+
onClick: (event) => event.stopPropagation(),
|
|
7931
|
+
"aria-label": `\u041D\u043E\u0432\u043E\u0435 \u043D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u0430 ${resource.name}`,
|
|
7932
|
+
className: "gantt-tl-name-input gantt-resourceTimeline-resourceNameInput"
|
|
7933
|
+
}
|
|
7934
|
+
) : /* @__PURE__ */ jsx15(
|
|
7935
|
+
"button",
|
|
7936
|
+
{
|
|
7937
|
+
type: "button",
|
|
7938
|
+
className: "gantt-resourceTimeline-resourceNameButton",
|
|
7939
|
+
"aria-label": `\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u0430 ${resource.name}`,
|
|
7940
|
+
title: resource.name,
|
|
7941
|
+
onClick: (event) => {
|
|
7942
|
+
event.stopPropagation();
|
|
7943
|
+
onResourceNameClick?.(resourceId);
|
|
7944
|
+
},
|
|
7945
|
+
onDoubleClick: handleNameDoubleClick,
|
|
7946
|
+
children: resource.name
|
|
7947
|
+
}
|
|
7948
|
+
)
|
|
7949
|
+
] }),
|
|
7950
|
+
/* @__PURE__ */ jsxs12(Popover, { open: scopeMenuOpen, onOpenChange: setScopeMenuOpen, children: [
|
|
7771
7951
|
/* @__PURE__ */ jsx15(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx15(
|
|
7772
7952
|
"button",
|
|
7773
7953
|
{
|
|
7774
|
-
className: "gantt-resourceTimeline-resourceMenuButton",
|
|
7775
7954
|
type: "button",
|
|
7776
|
-
|
|
7955
|
+
className: `gantt-resourceTimeline-resourceScopeChip gantt-resourceTimeline-resourceScope${scope === "Shared" ? "Shared" : "Project"}`,
|
|
7956
|
+
disabled: !onResourceChange,
|
|
7957
|
+
"aria-label": `\u0414\u043E\u0441\u0442\u0443\u043F\u043D\u043E\u0441\u0442\u044C \u0440\u0435\u0441\u0443\u0440\u0441\u0430 ${resource.name}`,
|
|
7777
7958
|
onClick: (event) => {
|
|
7778
7959
|
event.stopPropagation();
|
|
7779
|
-
|
|
7960
|
+
setScopeMenuOpen((open) => !open);
|
|
7780
7961
|
},
|
|
7781
|
-
children: /* @__PURE__ */ jsx15("span", {
|
|
7962
|
+
children: /* @__PURE__ */ jsx15("span", { children: scopeLabel })
|
|
7782
7963
|
}
|
|
7783
7964
|
) }),
|
|
7784
|
-
/* @__PURE__ */ jsx15(PopoverContent, { className: "gantt-resourceTimeline-
|
|
7965
|
+
/* @__PURE__ */ jsx15(PopoverContent, { className: "gantt-resourceTimeline-resourceOptionMenu", portal: true, align: "start", children: RESOURCE_SCOPE_OPTIONS.map((option) => /* @__PURE__ */ jsxs12(
|
|
7785
7966
|
"button",
|
|
7786
7967
|
{
|
|
7787
7968
|
type: "button",
|
|
7788
|
-
className: `gantt-resourceTimeline-
|
|
7789
|
-
|
|
7790
|
-
|
|
7969
|
+
className: `gantt-resourceTimeline-resourceOption${scope === option ? " gantt-resourceTimeline-resourceOptionActive" : ""}`,
|
|
7970
|
+
onClick: (event) => {
|
|
7971
|
+
event.stopPropagation();
|
|
7972
|
+
setScopeMenuOpen(false);
|
|
7973
|
+
applyResourcePatch({ scope: option });
|
|
7974
|
+
},
|
|
7791
7975
|
children: [
|
|
7792
|
-
|
|
7793
|
-
|
|
7976
|
+
/* @__PURE__ */ jsx15("span", { className: `gantt-resourceTimeline-resourceOptionScopeDot gantt-resourceTimeline-resourceScope${option}` }),
|
|
7977
|
+
RESOURCE_SCOPE_LABELS[option] ?? option
|
|
7794
7978
|
]
|
|
7795
7979
|
},
|
|
7796
|
-
|
|
7980
|
+
option
|
|
7797
7981
|
)) })
|
|
7982
|
+
] }),
|
|
7983
|
+
/* @__PURE__ */ jsxs12(
|
|
7984
|
+
"span",
|
|
7985
|
+
{
|
|
7986
|
+
className: "gantt-resourceTimeline-resourceAssignments",
|
|
7987
|
+
"aria-label": `\u041D\u0430\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F \u0440\u0435\u0441\u0443\u0440\u0441\u0430 ${resource.name}: ${assignmentCount}, ${workedDays} \u0434\u043D.`,
|
|
7988
|
+
children: [
|
|
7989
|
+
/* @__PURE__ */ jsxs12("span", { className: "gantt-resourceTimeline-resourceWorkedDays", children: [
|
|
7990
|
+
/* @__PURE__ */ jsx15("span", { className: "gantt-resourceTimeline-resourceMetricValue", children: workedDays > 0 ? workedDays : "-" }),
|
|
7991
|
+
/* @__PURE__ */ jsx15("span", { className: "gantt-resourceTimeline-resourceMetricLabel", children: workedDays > 0 ? "\u0434\u043D." : "" })
|
|
7992
|
+
] }),
|
|
7993
|
+
/* @__PURE__ */ jsxs12("span", { className: "gantt-resourceTimeline-resourceAssignmentCount", children: [
|
|
7994
|
+
/* @__PURE__ */ jsx15("span", { className: "gantt-resourceTimeline-resourceMetricValue", children: assignmentCount > 0 ? assignmentCount : "" }),
|
|
7995
|
+
assignmentCount > 0 && /* @__PURE__ */ jsxs12("svg", { className: "gantt-resourceTimeline-resourceAssignmentIcon", width: "14", height: "14", viewBox: "0 0 24 24", "aria-hidden": "true", children: [
|
|
7996
|
+
/* @__PURE__ */ jsx15("rect", { width: "15", height: "5", x: "4", y: "5", rx: "2" }),
|
|
7997
|
+
/* @__PURE__ */ jsx15("rect", { width: "10", height: "5", x: "4", y: "14", rx: "2" })
|
|
7998
|
+
] })
|
|
7999
|
+
] })
|
|
8000
|
+
]
|
|
8001
|
+
}
|
|
8002
|
+
),
|
|
8003
|
+
/* @__PURE__ */ jsxs12("span", { className: "gantt-resourceTimeline-resourceActions", children: [
|
|
8004
|
+
conflictCount > 0 && /* @__PURE__ */ jsx15(
|
|
8005
|
+
"button",
|
|
8006
|
+
{
|
|
8007
|
+
type: "button",
|
|
8008
|
+
className: "gantt-resourceTimeline-conflictBadge",
|
|
8009
|
+
"aria-label": formatOverlapCount(conflictCount),
|
|
8010
|
+
title: formatOverlapCount(conflictCount),
|
|
8011
|
+
onClick: (event) => {
|
|
8012
|
+
event.stopPropagation();
|
|
8013
|
+
onConflictBadgeClick?.(resourceId);
|
|
8014
|
+
},
|
|
8015
|
+
children: conflictCount
|
|
8016
|
+
}
|
|
8017
|
+
),
|
|
8018
|
+
hasMenu && /* @__PURE__ */ jsxs12(Popover, { open: menuOpen, onOpenChange: setMenuOpen, children: [
|
|
8019
|
+
/* @__PURE__ */ jsx15(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx15(
|
|
8020
|
+
"button",
|
|
8021
|
+
{
|
|
8022
|
+
className: "gantt-resourceTimeline-resourceMenuButton",
|
|
8023
|
+
type: "button",
|
|
8024
|
+
"aria-label": "\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u044F \u0440\u0435\u0441\u0443\u0440\u0441\u0430",
|
|
8025
|
+
onClick: (event) => {
|
|
8026
|
+
event.stopPropagation();
|
|
8027
|
+
setMenuOpen((open) => !open);
|
|
8028
|
+
},
|
|
8029
|
+
children: /* @__PURE__ */ jsx15("span", { "aria-hidden": "true", children: "\u22EE" })
|
|
8030
|
+
}
|
|
8031
|
+
) }),
|
|
8032
|
+
/* @__PURE__ */ jsx15(PopoverContent, { className: "gantt-resourceTimeline-resourceMenu", portal: true, align: "end", children: visibleCommands.map((command) => /* @__PURE__ */ jsxs12(
|
|
8033
|
+
"button",
|
|
8034
|
+
{
|
|
8035
|
+
type: "button",
|
|
8036
|
+
className: `gantt-resourceTimeline-resourceMenuItem${command.danger ? " gantt-resourceTimeline-resourceMenuItemDanger" : ""}`,
|
|
8037
|
+
disabled: command.isDisabled?.(resource) ?? false,
|
|
8038
|
+
onClick: (event) => handleCommandClick(command, event),
|
|
8039
|
+
children: [
|
|
8040
|
+
command.icon,
|
|
8041
|
+
command.label
|
|
8042
|
+
]
|
|
8043
|
+
},
|
|
8044
|
+
command.id
|
|
8045
|
+
)) })
|
|
8046
|
+
] })
|
|
7798
8047
|
] })
|
|
7799
8048
|
]
|
|
7800
8049
|
}
|
|
@@ -7833,7 +8082,7 @@ var NewResourceRow = ({ height, onConfirm, onCancel }) => {
|
|
|
7833
8082
|
handleConfirm();
|
|
7834
8083
|
}
|
|
7835
8084
|
};
|
|
7836
|
-
return /* @__PURE__ */
|
|
8085
|
+
return /* @__PURE__ */ jsxs12(
|
|
7837
8086
|
"div",
|
|
7838
8087
|
{
|
|
7839
8088
|
className: "gantt-resourceTimeline-resourceHeader gantt-resourceTimeline-resourceHeaderNew",
|
|
@@ -7841,18 +8090,21 @@ var NewResourceRow = ({ height, onConfirm, onCancel }) => {
|
|
|
7841
8090
|
height: `${height}px`,
|
|
7842
8091
|
paddingBottom: `${DEFAULT_RESOURCE_ROW_GAP}px`
|
|
7843
8092
|
},
|
|
7844
|
-
children:
|
|
7845
|
-
|
|
7846
|
-
|
|
7847
|
-
|
|
7848
|
-
|
|
7849
|
-
|
|
7850
|
-
|
|
7851
|
-
|
|
7852
|
-
|
|
7853
|
-
|
|
7854
|
-
|
|
7855
|
-
|
|
8093
|
+
children: [
|
|
8094
|
+
/* @__PURE__ */ jsx15("span", { className: "gantt-resourceTimeline-resourceNumber", children: "+" }),
|
|
8095
|
+
/* @__PURE__ */ jsx15(
|
|
8096
|
+
Input,
|
|
8097
|
+
{
|
|
8098
|
+
ref: inputRef,
|
|
8099
|
+
value: nameValue,
|
|
8100
|
+
onChange: (event) => setNameValue(event.target.value),
|
|
8101
|
+
onKeyDown: handleKeyDown,
|
|
8102
|
+
onBlur: handleBlur,
|
|
8103
|
+
placeholder: "\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u0430",
|
|
8104
|
+
className: "gantt-resourceTimeline-resourceInput"
|
|
8105
|
+
}
|
|
8106
|
+
)
|
|
8107
|
+
]
|
|
7856
8108
|
}
|
|
7857
8109
|
);
|
|
7858
8110
|
};
|
|
@@ -7868,6 +8120,7 @@ function ResourceTimelineChart({
|
|
|
7868
8120
|
customDays,
|
|
7869
8121
|
isWeekend: isWeekend3,
|
|
7870
8122
|
businessDays = true,
|
|
8123
|
+
resourceGrouping = false,
|
|
7871
8124
|
readonly,
|
|
7872
8125
|
disableResourceReassignment,
|
|
7873
8126
|
renderItem,
|
|
@@ -7876,6 +8129,7 @@ function ResourceTimelineChart({
|
|
|
7876
8129
|
onResourceItemMenuClick,
|
|
7877
8130
|
activeResourceItemId,
|
|
7878
8131
|
onResourceItemMove,
|
|
8132
|
+
onResourceChange,
|
|
7879
8133
|
onAddResource,
|
|
7880
8134
|
enableAddResource = true,
|
|
7881
8135
|
resourceMenuCommands = []
|
|
@@ -7884,9 +8138,12 @@ function ResourceTimelineChart({
|
|
|
7884
8138
|
const gridRef = useRef8(null);
|
|
7885
8139
|
const panStateRef = useRef8(null);
|
|
7886
8140
|
const conflictNavigationIndexRef = useRef8(/* @__PURE__ */ new Map());
|
|
8141
|
+
const resourceNavigationIndexRef = useRef8(/* @__PURE__ */ new Map());
|
|
7887
8142
|
const conflictHighlightTimeoutRef = useRef8(null);
|
|
7888
8143
|
const [isCreatingResource, setIsCreatingResource] = useState8(false);
|
|
8144
|
+
const [creatingResourceGroupType, setCreatingResourceGroupType] = useState8(null);
|
|
7889
8145
|
const [activeConflictItemId, setActiveConflictItemId] = useState8(null);
|
|
8146
|
+
const [resourceColumnHasRightShadow, setResourceColumnHasRightShadow] = useState8(false);
|
|
7890
8147
|
const validItems = useMemo9(() => collectValidItems(resources), [resources]);
|
|
7891
8148
|
const dateRange = useMemo9(() => getMultiMonthDays(validItems), [validItems]);
|
|
7892
8149
|
const monthStart = useMemo9(() => {
|
|
@@ -7898,15 +8155,112 @@ function ResourceTimelineChart({
|
|
|
7898
8155
|
[customDays, isWeekend3]
|
|
7899
8156
|
);
|
|
7900
8157
|
const gridWidth = useMemo9(() => Math.round(dateRange.length * dayWidth), [dateRange.length, dayWidth]);
|
|
8158
|
+
const effectiveRowHeaderWidth = Math.max(rowHeaderWidth, DEFAULT_ROW_HEADER_WIDTH);
|
|
8159
|
+
const orderedResources = useMemo9(
|
|
8160
|
+
() => resourceGrouping === "type" ? orderResourcesByType(resources) : resources,
|
|
8161
|
+
[resourceGrouping, resources]
|
|
8162
|
+
);
|
|
8163
|
+
const workedDaysByResourceId = useMemo9(() => {
|
|
8164
|
+
const map = /* @__PURE__ */ new Map();
|
|
8165
|
+
for (const resource of resources) {
|
|
8166
|
+
const workedDays = resource.items.reduce((sum, item) => {
|
|
8167
|
+
try {
|
|
8168
|
+
const startDate = parseUTCDate(item.startDate);
|
|
8169
|
+
const endDate = parseUTCDate(item.endDate);
|
|
8170
|
+
if (!isValidDate(startDate) || !isValidDate(endDate)) {
|
|
8171
|
+
return sum;
|
|
8172
|
+
}
|
|
8173
|
+
return sum + getDurationValue(startDate, endDate, businessDays, weekendPredicate);
|
|
8174
|
+
} catch {
|
|
8175
|
+
return sum;
|
|
8176
|
+
}
|
|
8177
|
+
}, 0);
|
|
8178
|
+
map.set(resource.id, workedDays);
|
|
8179
|
+
}
|
|
8180
|
+
return map;
|
|
8181
|
+
}, [businessDays, resources, weekendPredicate]);
|
|
7901
8182
|
const layout = useMemo9(
|
|
7902
|
-
() => layoutResourceTimelineItems(
|
|
8183
|
+
() => layoutResourceTimelineItems(orderedResources, {
|
|
7903
8184
|
monthStart,
|
|
7904
8185
|
dayWidth,
|
|
7905
8186
|
laneHeight,
|
|
7906
8187
|
rowGap: DEFAULT_RESOURCE_ROW_GAP
|
|
7907
8188
|
}),
|
|
7908
|
-
[
|
|
8189
|
+
[orderedResources, monthStart, dayWidth, laneHeight]
|
|
7909
8190
|
);
|
|
8191
|
+
const canAddResource = enableAddResource && Boolean(onAddResource);
|
|
8192
|
+
const resourceAddRowHeight = laneHeight + DEFAULT_RESOURCE_ROW_GAP;
|
|
8193
|
+
const displayLayout = useMemo9(() => {
|
|
8194
|
+
if (resourceGrouping !== "type") {
|
|
8195
|
+
return {
|
|
8196
|
+
rows: layout.rows,
|
|
8197
|
+
items: layout.items,
|
|
8198
|
+
groupHeaders: [],
|
|
8199
|
+
groupAddRows: [],
|
|
8200
|
+
totalHeight: layout.totalHeight
|
|
8201
|
+
};
|
|
8202
|
+
}
|
|
8203
|
+
const countsByType = /* @__PURE__ */ new Map();
|
|
8204
|
+
for (const row of layout.rows) {
|
|
8205
|
+
const type = getResourceType(row.resource);
|
|
8206
|
+
countsByType.set(type, (countsByType.get(type) ?? 0) + 1);
|
|
8207
|
+
}
|
|
8208
|
+
let offset = 0;
|
|
8209
|
+
let previousType = null;
|
|
8210
|
+
const rowTopOffsets = /* @__PURE__ */ new Map();
|
|
8211
|
+
const groupHeaders = [];
|
|
8212
|
+
const groupAddRows = [];
|
|
8213
|
+
const rows = layout.rows.map((row) => {
|
|
8214
|
+
const type = getResourceType(row.resource);
|
|
8215
|
+
if (type !== previousType) {
|
|
8216
|
+
if (previousType !== null && creatingResourceGroupType === previousType) {
|
|
8217
|
+
groupAddRows.push({
|
|
8218
|
+
key: previousType,
|
|
8219
|
+
top: row.resourceRowTop + offset,
|
|
8220
|
+
height: resourceAddRowHeight
|
|
8221
|
+
});
|
|
8222
|
+
offset += resourceAddRowHeight;
|
|
8223
|
+
}
|
|
8224
|
+
groupHeaders.push({
|
|
8225
|
+
key: type,
|
|
8226
|
+
label: type,
|
|
8227
|
+
count: countsByType.get(type) ?? 0,
|
|
8228
|
+
top: row.resourceRowTop + offset,
|
|
8229
|
+
height: DEFAULT_RESOURCE_GROUP_HEIGHT
|
|
8230
|
+
});
|
|
8231
|
+
offset += DEFAULT_RESOURCE_GROUP_HEIGHT;
|
|
8232
|
+
previousType = type;
|
|
8233
|
+
}
|
|
8234
|
+
rowTopOffsets.set(row.resourceId, offset);
|
|
8235
|
+
return {
|
|
8236
|
+
...row,
|
|
8237
|
+
resourceRowTop: row.resourceRowTop + offset
|
|
8238
|
+
};
|
|
8239
|
+
});
|
|
8240
|
+
if (previousType !== null && creatingResourceGroupType === previousType) {
|
|
8241
|
+
groupAddRows.push({
|
|
8242
|
+
key: previousType,
|
|
8243
|
+
top: layout.totalHeight + offset,
|
|
8244
|
+
height: resourceAddRowHeight
|
|
8245
|
+
});
|
|
8246
|
+
offset += resourceAddRowHeight;
|
|
8247
|
+
}
|
|
8248
|
+
const items = layout.items.map((item) => {
|
|
8249
|
+
const itemOffset = rowTopOffsets.get(item.resourceId) ?? 0;
|
|
8250
|
+
return {
|
|
8251
|
+
...item,
|
|
8252
|
+
resourceRowTop: item.resourceRowTop + itemOffset,
|
|
8253
|
+
top: item.top + itemOffset
|
|
8254
|
+
};
|
|
8255
|
+
});
|
|
8256
|
+
return {
|
|
8257
|
+
rows,
|
|
8258
|
+
items,
|
|
8259
|
+
groupHeaders,
|
|
8260
|
+
groupAddRows,
|
|
8261
|
+
totalHeight: layout.totalHeight + offset
|
|
8262
|
+
};
|
|
8263
|
+
}, [creatingResourceGroupType, layout, resourceAddRowHeight, resourceGrouping]);
|
|
7910
8264
|
const todayInRange = useMemo9(() => {
|
|
7911
8265
|
const now = /* @__PURE__ */ new Date();
|
|
7912
8266
|
const today = new Date(Date.UTC(now.getFullYear(), now.getMonth(), now.getDate()));
|
|
@@ -7914,16 +8268,16 @@ function ResourceTimelineChart({
|
|
|
7914
8268
|
}, [dateRange]);
|
|
7915
8269
|
const itemsByResourceId = useMemo9(() => {
|
|
7916
8270
|
const map = /* @__PURE__ */ new Map();
|
|
7917
|
-
for (const item of
|
|
8271
|
+
for (const item of displayLayout.items) {
|
|
7918
8272
|
const next = map.get(item.resourceId) ?? [];
|
|
7919
8273
|
next.push(item);
|
|
7920
8274
|
map.set(item.resourceId, next);
|
|
7921
8275
|
}
|
|
7922
8276
|
return map;
|
|
7923
|
-
}, [
|
|
8277
|
+
}, [displayLayout.items]);
|
|
7924
8278
|
const conflictItemsByResourceId = useMemo9(() => {
|
|
7925
8279
|
const map = /* @__PURE__ */ new Map();
|
|
7926
|
-
for (const item of
|
|
8280
|
+
for (const item of displayLayout.items) {
|
|
7927
8281
|
if (item.conflictRanges.length === 0) {
|
|
7928
8282
|
continue;
|
|
7929
8283
|
}
|
|
@@ -7937,19 +8291,28 @@ function ResourceTimelineChart({
|
|
|
7937
8291
|
);
|
|
7938
8292
|
}
|
|
7939
8293
|
return map;
|
|
7940
|
-
}, [
|
|
7941
|
-
const
|
|
7942
|
-
const
|
|
7943
|
-
const displayTotalHeight = layout.totalHeight + (canAddResource ? resourceAddRowHeight : 0);
|
|
8294
|
+
}, [displayLayout.items]);
|
|
8295
|
+
const displayTotalHeight = displayLayout.totalHeight + (canAddResource ? resourceAddRowHeight : 0);
|
|
8296
|
+
const timelineHeaderHeight = headerHeight + 1;
|
|
7944
8297
|
const handleConfirmNewResource = useCallback7((name) => {
|
|
7945
8298
|
onAddResource?.({
|
|
7946
8299
|
id: crypto.randomUUID(),
|
|
7947
8300
|
name,
|
|
8301
|
+
type: creatingResourceGroupType ?? "\u0414\u0440\u0443\u0433\u043E\u0435",
|
|
8302
|
+
scope: "Project",
|
|
7948
8303
|
items: []
|
|
7949
8304
|
});
|
|
7950
8305
|
setIsCreatingResource(false);
|
|
7951
|
-
|
|
7952
|
-
|
|
8306
|
+
setCreatingResourceGroupType(null);
|
|
8307
|
+
}, [creatingResourceGroupType, onAddResource]);
|
|
8308
|
+
const handleStartAddResourceToGroup = useCallback7((type) => {
|
|
8309
|
+
setIsCreatingResource(false);
|
|
8310
|
+
setCreatingResourceGroupType(type);
|
|
8311
|
+
}, []);
|
|
8312
|
+
const handleCancelNewResource = useCallback7(() => {
|
|
8313
|
+
setIsCreatingResource(false);
|
|
8314
|
+
setCreatingResourceGroupType(null);
|
|
8315
|
+
}, []);
|
|
7953
8316
|
const handleConflictBadgeClick = useCallback7((resourceId) => {
|
|
7954
8317
|
const conflictItems = conflictItemsByResourceId.get(resourceId) ?? [];
|
|
7955
8318
|
if (conflictItems.length === 0) {
|
|
@@ -7975,10 +8338,31 @@ function ResourceTimelineChart({
|
|
|
7975
8338
|
conflictHighlightTimeoutRef.current = null;
|
|
7976
8339
|
}, 1600);
|
|
7977
8340
|
}, [conflictItemsByResourceId, dayWidth, laneHeight]);
|
|
8341
|
+
const handleResourceNameClick = useCallback7((resourceId) => {
|
|
8342
|
+
const resourceItems = itemsByResourceId.get(resourceId) ?? [];
|
|
8343
|
+
if (resourceItems.length === 0) {
|
|
8344
|
+
return;
|
|
8345
|
+
}
|
|
8346
|
+
const orderedItems = [...resourceItems].sort(
|
|
8347
|
+
(left, right) => left.left - right.left || left.top - right.top || left.itemId.localeCompare(right.itemId)
|
|
8348
|
+
);
|
|
8349
|
+
const currentIndex = resourceNavigationIndexRef.current.get(resourceId) ?? 0;
|
|
8350
|
+
const targetItem = orderedItems[currentIndex % orderedItems.length];
|
|
8351
|
+
resourceNavigationIndexRef.current.set(resourceId, (currentIndex + 1) % orderedItems.length);
|
|
8352
|
+
const container = scrollContainerRef.current;
|
|
8353
|
+
if (!container || !targetItem) {
|
|
8354
|
+
return;
|
|
8355
|
+
}
|
|
8356
|
+
container.scrollTo({
|
|
8357
|
+
left: Math.max(0, Math.round(targetItem.left - dayWidth * 2)),
|
|
8358
|
+
top: Math.max(0, Math.round(targetItem.top - laneHeight)),
|
|
8359
|
+
behavior: "smooth"
|
|
8360
|
+
});
|
|
8361
|
+
}, [dayWidth, itemsByResourceId, laneHeight]);
|
|
7978
8362
|
const { preview, startDrag } = useResourceItemDrag({
|
|
7979
8363
|
dayWidth,
|
|
7980
8364
|
monthStart,
|
|
7981
|
-
rows:
|
|
8365
|
+
rows: displayLayout.rows,
|
|
7982
8366
|
gridElementRef: gridRef,
|
|
7983
8367
|
readonly,
|
|
7984
8368
|
disableResourceReassignment,
|
|
@@ -7986,6 +8370,18 @@ function ResourceTimelineChart({
|
|
|
7986
8370
|
weekendPredicate,
|
|
7987
8371
|
onResourceItemMove
|
|
7988
8372
|
});
|
|
8373
|
+
useEffect8(() => {
|
|
8374
|
+
const container = scrollContainerRef.current;
|
|
8375
|
+
if (!container) return;
|
|
8376
|
+
const updateShadow = () => {
|
|
8377
|
+
setResourceColumnHasRightShadow(container.scrollLeft > 0);
|
|
8378
|
+
};
|
|
8379
|
+
updateShadow();
|
|
8380
|
+
container.addEventListener("scroll", updateShadow, { passive: true });
|
|
8381
|
+
return () => {
|
|
8382
|
+
container.removeEventListener("scroll", updateShadow);
|
|
8383
|
+
};
|
|
8384
|
+
}, []);
|
|
7989
8385
|
const handlePanStart = useCallback7((event) => {
|
|
7990
8386
|
if (event.button !== 0) {
|
|
7991
8387
|
return;
|
|
@@ -8043,6 +8439,16 @@ function ResourceTimelineChart({
|
|
|
8043
8439
|
window.removeEventListener("mouseup", handlePanEnd);
|
|
8044
8440
|
};
|
|
8045
8441
|
}, [allowVerticalPan]);
|
|
8442
|
+
useEffect8(() => {
|
|
8443
|
+
const nextNavigation = /* @__PURE__ */ new Map();
|
|
8444
|
+
for (const [resourceId, resourceItems] of itemsByResourceId.entries()) {
|
|
8445
|
+
if (resourceItems.length === 0) {
|
|
8446
|
+
continue;
|
|
8447
|
+
}
|
|
8448
|
+
nextNavigation.set(resourceId, (resourceNavigationIndexRef.current.get(resourceId) ?? 0) % resourceItems.length);
|
|
8449
|
+
}
|
|
8450
|
+
resourceNavigationIndexRef.current = nextNavigation;
|
|
8451
|
+
}, [itemsByResourceId]);
|
|
8046
8452
|
useEffect8(() => {
|
|
8047
8453
|
return () => {
|
|
8048
8454
|
if (conflictHighlightTimeoutRef.current) {
|
|
@@ -8066,25 +8472,92 @@ function ResourceTimelineChart({
|
|
|
8066
8472
|
/* @__PURE__ */ jsxs12(
|
|
8067
8473
|
"div",
|
|
8068
8474
|
{
|
|
8069
|
-
className:
|
|
8070
|
-
style: { width: `${
|
|
8475
|
+
className: `gantt-resourceTimeline-resourceColumn${resourceColumnHasRightShadow ? " gantt-resourceTimeline-resourceColumnShadowed" : ""}`,
|
|
8476
|
+
style: { width: `${effectiveRowHeaderWidth}px`, minWidth: `${effectiveRowHeaderWidth}px` },
|
|
8071
8477
|
children: [
|
|
8072
|
-
/* @__PURE__ */
|
|
8478
|
+
/* @__PURE__ */ jsxs12(
|
|
8073
8479
|
"div",
|
|
8074
8480
|
{
|
|
8075
8481
|
className: "gantt-resourceTimeline-corner",
|
|
8076
|
-
style: { height: `${
|
|
8482
|
+
style: { height: `${timelineHeaderHeight}px` },
|
|
8483
|
+
children: [
|
|
8484
|
+
/* @__PURE__ */ jsx15("span", { className: "gantt-resourceTimeline-resourceHeaderCell gantt-resourceTimeline-resourceHeaderNumber", children: "#" }),
|
|
8485
|
+
/* @__PURE__ */ jsx15("span", { className: "gantt-resourceTimeline-resourceHeaderCell gantt-resourceTimeline-resourceHeaderName", children: "\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435" }),
|
|
8486
|
+
/* @__PURE__ */ jsx15("span", { className: "gantt-resourceTimeline-resourceHeaderCell", "aria-label": "\u0414\u043E\u0441\u0442\u0443\u043F\u043D\u043E\u0441\u0442\u044C" }),
|
|
8487
|
+
/* @__PURE__ */ jsx15("span", { className: "gantt-resourceTimeline-resourceHeaderCell", children: "\u041D\u0430\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F" }),
|
|
8488
|
+
/* @__PURE__ */ jsx15("span", { className: "gantt-resourceTimeline-resourceHeaderCell gantt-resourceTimeline-resourceHeaderActions", "aria-label": "\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u044F" })
|
|
8489
|
+
]
|
|
8077
8490
|
}
|
|
8078
8491
|
),
|
|
8079
|
-
|
|
8492
|
+
displayLayout.groupHeaders.length > 0 ? displayLayout.groupHeaders.map((group) => /* @__PURE__ */ jsxs12(React12.Fragment, { children: [
|
|
8493
|
+
/* @__PURE__ */ jsxs12(
|
|
8494
|
+
"div",
|
|
8495
|
+
{
|
|
8496
|
+
className: "gantt-resourceTimeline-resourceGroupHeader",
|
|
8497
|
+
style: { height: `${group.height}px` },
|
|
8498
|
+
children: [
|
|
8499
|
+
/* @__PURE__ */ jsx15("span", { className: "gantt-resourceTimeline-resourceGroupTitle", children: group.label }),
|
|
8500
|
+
/* @__PURE__ */ jsx15("span", { className: "gantt-resourceTimeline-resourceGroupCount", children: group.count }),
|
|
8501
|
+
canAddResource && /* @__PURE__ */ jsx15(
|
|
8502
|
+
"button",
|
|
8503
|
+
{
|
|
8504
|
+
type: "button",
|
|
8505
|
+
className: "gantt-resourceTimeline-resourceGroupAddButton",
|
|
8506
|
+
"aria-label": `\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0440\u0435\u0441\u0443\u0440\u0441 \u0432 \u0433\u0440\u0443\u043F\u043F\u0443 ${group.label}`,
|
|
8507
|
+
title: `\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0440\u0435\u0441\u0443\u0440\u0441 \u0432 \u0433\u0440\u0443\u043F\u043F\u0443 ${group.label}`,
|
|
8508
|
+
onClick: (event) => {
|
|
8509
|
+
event.stopPropagation();
|
|
8510
|
+
handleStartAddResourceToGroup(group.key);
|
|
8511
|
+
},
|
|
8512
|
+
children: "+"
|
|
8513
|
+
}
|
|
8514
|
+
)
|
|
8515
|
+
]
|
|
8516
|
+
}
|
|
8517
|
+
),
|
|
8518
|
+
displayLayout.rows.filter((row) => getResourceType(row.resource) === group.key).map((row) => {
|
|
8519
|
+
const rowIndex = displayLayout.rows.findIndex((candidate) => candidate.resourceId === row.resourceId);
|
|
8520
|
+
return /* @__PURE__ */ jsx15(
|
|
8521
|
+
ResourceHeader,
|
|
8522
|
+
{
|
|
8523
|
+
resource: row.resource,
|
|
8524
|
+
resourceId: row.resourceId,
|
|
8525
|
+
rowIndex,
|
|
8526
|
+
conflictCount: row.conflictCount,
|
|
8527
|
+
workedDays: workedDaysByResourceId.get(row.resourceId) ?? 0,
|
|
8528
|
+
assignmentCount: row.resource.items.length,
|
|
8529
|
+
height: row.resourceRowHeight + DEFAULT_RESOURCE_ROW_GAP,
|
|
8530
|
+
paddingBottom: DEFAULT_RESOURCE_ROW_GAP,
|
|
8531
|
+
menuCommands: resourceMenuCommands,
|
|
8532
|
+
onResourceChange,
|
|
8533
|
+
onResourceNameClick: handleResourceNameClick,
|
|
8534
|
+
onConflictBadgeClick: handleConflictBadgeClick
|
|
8535
|
+
},
|
|
8536
|
+
row.resourceId
|
|
8537
|
+
);
|
|
8538
|
+
}),
|
|
8539
|
+
displayLayout.groupAddRows.some((row) => row.key === group.key) && /* @__PURE__ */ jsx15(
|
|
8540
|
+
NewResourceRow,
|
|
8541
|
+
{
|
|
8542
|
+
height: resourceAddRowHeight,
|
|
8543
|
+
onConfirm: handleConfirmNewResource,
|
|
8544
|
+
onCancel: handleCancelNewResource
|
|
8545
|
+
}
|
|
8546
|
+
)
|
|
8547
|
+
] }, group.key)) : displayLayout.rows.map((row, rowIndex) => /* @__PURE__ */ jsx15(
|
|
8080
8548
|
ResourceHeader,
|
|
8081
8549
|
{
|
|
8082
8550
|
resource: row.resource,
|
|
8083
8551
|
resourceId: row.resourceId,
|
|
8552
|
+
rowIndex,
|
|
8084
8553
|
conflictCount: row.conflictCount,
|
|
8554
|
+
workedDays: workedDaysByResourceId.get(row.resourceId) ?? 0,
|
|
8555
|
+
assignmentCount: row.resource.items.length,
|
|
8085
8556
|
height: row.resourceRowHeight + DEFAULT_RESOURCE_ROW_GAP,
|
|
8086
8557
|
paddingBottom: DEFAULT_RESOURCE_ROW_GAP,
|
|
8087
8558
|
menuCommands: resourceMenuCommands,
|
|
8559
|
+
onResourceChange,
|
|
8560
|
+
onResourceNameClick: handleResourceNameClick,
|
|
8088
8561
|
onConflictBadgeClick: handleConflictBadgeClick
|
|
8089
8562
|
},
|
|
8090
8563
|
row.resourceId
|
|
@@ -8102,7 +8575,10 @@ function ResourceTimelineChart({
|
|
|
8102
8575
|
className: "gantt-resourceTimeline-addResourceButton",
|
|
8103
8576
|
type: "button",
|
|
8104
8577
|
style: { height: `${resourceAddRowHeight}px` },
|
|
8105
|
-
onClick: () =>
|
|
8578
|
+
onClick: () => {
|
|
8579
|
+
setCreatingResourceGroupType(null);
|
|
8580
|
+
setIsCreatingResource(true);
|
|
8581
|
+
},
|
|
8106
8582
|
children: "+ \u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0440\u0435\u0441\u0443\u0440\u0441"
|
|
8107
8583
|
}
|
|
8108
8584
|
))
|
|
@@ -8115,16 +8591,23 @@ function ResourceTimelineChart({
|
|
|
8115
8591
|
className: "gantt-resourceTimeline-chartSurface",
|
|
8116
8592
|
style: { minWidth: `${gridWidth}px` },
|
|
8117
8593
|
children: [
|
|
8118
|
-
/* @__PURE__ */ jsx15(
|
|
8119
|
-
|
|
8594
|
+
/* @__PURE__ */ jsx15(
|
|
8595
|
+
"div",
|
|
8120
8596
|
{
|
|
8121
|
-
|
|
8122
|
-
|
|
8123
|
-
|
|
8124
|
-
|
|
8125
|
-
|
|
8597
|
+
className: "gantt-resourceTimeline-stickyHeader",
|
|
8598
|
+
style: { width: `${gridWidth}px`, height: `${timelineHeaderHeight}px` },
|
|
8599
|
+
children: /* @__PURE__ */ jsx15(
|
|
8600
|
+
TimeScaleHeader_default,
|
|
8601
|
+
{
|
|
8602
|
+
days: dateRange,
|
|
8603
|
+
dayWidth,
|
|
8604
|
+
headerHeight,
|
|
8605
|
+
viewMode,
|
|
8606
|
+
isCustomWeekend: weekendPredicate
|
|
8607
|
+
}
|
|
8608
|
+
)
|
|
8126
8609
|
}
|
|
8127
|
-
)
|
|
8610
|
+
),
|
|
8128
8611
|
/* @__PURE__ */ jsxs12(
|
|
8129
8612
|
"div",
|
|
8130
8613
|
{
|
|
@@ -8143,7 +8626,19 @@ function ResourceTimelineChart({
|
|
|
8143
8626
|
}
|
|
8144
8627
|
),
|
|
8145
8628
|
todayInRange && /* @__PURE__ */ jsx15(TodayIndicator_default, { monthStart, dayWidth }),
|
|
8146
|
-
|
|
8629
|
+
displayLayout.groupHeaders.map((group) => /* @__PURE__ */ jsx15(
|
|
8630
|
+
"div",
|
|
8631
|
+
{
|
|
8632
|
+
className: "gantt-resourceTimeline-row gantt-resourceTimeline-groupRow",
|
|
8633
|
+
"data-resource-group": group.key,
|
|
8634
|
+
style: {
|
|
8635
|
+
top: `${group.top}px`,
|
|
8636
|
+
height: `${group.height}px`
|
|
8637
|
+
}
|
|
8638
|
+
},
|
|
8639
|
+
`group-row-${group.key}`
|
|
8640
|
+
)),
|
|
8641
|
+
displayLayout.rows.map((row) => /* @__PURE__ */ jsx15(
|
|
8147
8642
|
"div",
|
|
8148
8643
|
{
|
|
8149
8644
|
className: "gantt-resourceTimeline-row",
|
|
@@ -8161,11 +8656,23 @@ function ResourceTimelineChart({
|
|
|
8161
8656
|
className: "gantt-resourceTimeline-row gantt-resourceTimeline-rowNew",
|
|
8162
8657
|
"data-resource-add-row": "true",
|
|
8163
8658
|
style: {
|
|
8164
|
-
top: `${
|
|
8659
|
+
top: `${displayLayout.totalHeight}px`,
|
|
8165
8660
|
height: `${resourceAddRowHeight}px`
|
|
8166
8661
|
}
|
|
8167
8662
|
}
|
|
8168
8663
|
),
|
|
8664
|
+
displayLayout.groupAddRows.map((row) => /* @__PURE__ */ jsx15(
|
|
8665
|
+
"div",
|
|
8666
|
+
{
|
|
8667
|
+
className: "gantt-resourceTimeline-row gantt-resourceTimeline-rowNew",
|
|
8668
|
+
"data-resource-group-add-row": row.key,
|
|
8669
|
+
style: {
|
|
8670
|
+
top: `${row.top}px`,
|
|
8671
|
+
height: `${row.height}px`
|
|
8672
|
+
}
|
|
8673
|
+
},
|
|
8674
|
+
`group-add-row-${row.key}`
|
|
8675
|
+
)),
|
|
8169
8676
|
Array.from(itemsByResourceId.values()).flatMap(
|
|
8170
8677
|
(resourceItems) => resourceItems.map((layoutItem) => {
|
|
8171
8678
|
const customClassName = getItemClassName?.(layoutItem.item);
|
|
@@ -8772,6 +9279,7 @@ function TaskGanttChartInner(props, ref) {
|
|
|
8772
9279
|
() => visibleTasks.length * rowHeight,
|
|
8773
9280
|
[visibleTasks.length, rowHeight]
|
|
8774
9281
|
);
|
|
9282
|
+
const timelineHeaderHeight = headerHeight + 1;
|
|
8775
9283
|
const monthStart = useMemo10(() => {
|
|
8776
9284
|
if (dateRange.length === 0) {
|
|
8777
9285
|
return new Date(Date.UTC((/* @__PURE__ */ new Date()).getUTCFullYear(), (/* @__PURE__ */ new Date()).getUTCMonth(), 1));
|
|
@@ -9254,16 +9762,23 @@ function TaskGanttChartInner(props, ref) {
|
|
|
9254
9762
|
className: showChart ? "gantt-chartSurface" : "gantt-chartSurface gantt-chart-hidden",
|
|
9255
9763
|
style: { minWidth: `${gridWidth}px`, flex: 1, display: showChart ? void 0 : "none" },
|
|
9256
9764
|
children: [
|
|
9257
|
-
/* @__PURE__ */ jsx16(
|
|
9258
|
-
|
|
9765
|
+
/* @__PURE__ */ jsx16(
|
|
9766
|
+
"div",
|
|
9259
9767
|
{
|
|
9260
|
-
|
|
9261
|
-
|
|
9262
|
-
|
|
9263
|
-
|
|
9264
|
-
|
|
9768
|
+
className: "gantt-stickyHeader",
|
|
9769
|
+
style: { width: `${gridWidth}px`, height: `${timelineHeaderHeight}px` },
|
|
9770
|
+
children: /* @__PURE__ */ jsx16(
|
|
9771
|
+
TimeScaleHeader_default,
|
|
9772
|
+
{
|
|
9773
|
+
days: dateRange,
|
|
9774
|
+
dayWidth,
|
|
9775
|
+
headerHeight,
|
|
9776
|
+
viewMode,
|
|
9777
|
+
isCustomWeekend
|
|
9778
|
+
}
|
|
9779
|
+
)
|
|
9265
9780
|
}
|
|
9266
|
-
)
|
|
9781
|
+
),
|
|
9267
9782
|
/* @__PURE__ */ jsxs13(
|
|
9268
9783
|
"div",
|
|
9269
9784
|
{
|