gantt-lib 0.80.1 → 0.82.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-DAfJyZbj.d.mts → index-BPStPBtF.d.mts} +6 -0
- package/dist/{index-DAfJyZbj.d.ts → index-BPStPBtF.d.ts} +6 -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 +342 -42
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +342 -42
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +345 -18
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -7632,7 +7632,7 @@ import { Fragment as Fragment3, jsx as jsx15, jsxs as jsxs12 } from "react/jsx-r
|
|
|
7632
7632
|
var DEFAULT_DAY_WIDTH = 40;
|
|
7633
7633
|
var DEFAULT_HEADER_HEIGHT = 40;
|
|
7634
7634
|
var DEFAULT_LANE_HEIGHT = 40;
|
|
7635
|
-
var DEFAULT_ROW_HEADER_WIDTH =
|
|
7635
|
+
var DEFAULT_ROW_HEADER_WIDTH = 420;
|
|
7636
7636
|
var DEFAULT_RESOURCE_ROW_GAP = 8;
|
|
7637
7637
|
var ITEM_OUTER_VERTICAL_INSET = 2;
|
|
7638
7638
|
var ITEM_INNER_VERTICAL_INSET = 1;
|
|
@@ -7720,20 +7720,97 @@ var clampOverlaySegments = (segments2, maxWidth) => segments2.flatMap((segment)
|
|
|
7720
7720
|
return width > 0 ? [{ left, width }] : [];
|
|
7721
7721
|
});
|
|
7722
7722
|
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);
|
|
7723
|
+
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"];
|
|
7724
|
+
var RESOURCE_SCOPE_OPTIONS = ["Shared", "Project"];
|
|
7725
|
+
var RESOURCE_SCOPE_LABELS = {
|
|
7726
|
+
Shared: "\u041E\u0431\u0449\u0438\u0439",
|
|
7727
|
+
Project: "\u041F\u0440\u043E\u0435\u043A\u0442"
|
|
7728
|
+
};
|
|
7729
|
+
var RESOURCE_TYPE_CLASS_NAMES = {
|
|
7730
|
+
\u041B\u044E\u0434\u0438: "People",
|
|
7731
|
+
\u041E\u0431\u043E\u0440\u0443\u0434\u043E\u0432\u0430\u043D\u0438\u0435: "Equipment",
|
|
7732
|
+
\u041C\u0430\u0442\u0435\u0440\u0438\u0430\u043B\u044B: "Materials",
|
|
7733
|
+
\u0414\u0440\u0443\u0433\u043E\u0435: "Other"
|
|
7734
|
+
};
|
|
7735
|
+
var ResourceTypeIcon = ({ type }) => {
|
|
7736
|
+
if (type === "\u041B\u044E\u0434\u0438") {
|
|
7737
|
+
return /* @__PURE__ */ jsxs12("svg", { className: "gantt-resourceTimeline-resourceTypeIcon gantt-resourceTimeline-resourceTypeIconPeople", width: "16", height: "16", viewBox: "0 0 24 24", "aria-hidden": "true", children: [
|
|
7738
|
+
/* @__PURE__ */ jsx15("path", { d: "M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" }),
|
|
7739
|
+
/* @__PURE__ */ jsx15("circle", { cx: "9", cy: "7", r: "4" }),
|
|
7740
|
+
/* @__PURE__ */ jsx15("path", { d: "M22 21v-2a4 4 0 0 0-3-3.87" }),
|
|
7741
|
+
/* @__PURE__ */ jsx15("path", { d: "M16 3.13a4 4 0 0 1 0 7.75" })
|
|
7742
|
+
] });
|
|
7743
|
+
}
|
|
7744
|
+
if (type === "\u041E\u0431\u043E\u0440\u0443\u0434\u043E\u0432\u0430\u043D\u0438\u0435") {
|
|
7745
|
+
return /* @__PURE__ */ jsxs12("svg", { className: "gantt-resourceTimeline-resourceTypeIcon gantt-resourceTimeline-resourceTypeIconEquipment", width: "16", height: "16", viewBox: "0 0 24 24", "aria-hidden": "true", children: [
|
|
7746
|
+
/* @__PURE__ */ jsx15("path", { d: "m15 12-9.373 9.373a1 1 0 0 1-3.001-3L12 9" }),
|
|
7747
|
+
/* @__PURE__ */ jsx15("path", { d: "m18 15 4-4" }),
|
|
7748
|
+
/* @__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" })
|
|
7749
|
+
] });
|
|
7750
|
+
}
|
|
7751
|
+
if (type === "\u041C\u0430\u0442\u0435\u0440\u0438\u0430\u043B\u044B") {
|
|
7752
|
+
return /* @__PURE__ */ jsxs12("svg", { className: "gantt-resourceTimeline-resourceTypeIcon gantt-resourceTimeline-resourceTypeIconMaterials", width: "16", height: "16", viewBox: "0 0 24 24", "aria-hidden": "true", children: [
|
|
7753
|
+
/* @__PURE__ */ jsx15("path", { d: "M10 22v-8" }),
|
|
7754
|
+
/* @__PURE__ */ jsx15("path", { d: "M2.336 8.89 10 14l11.715-7.029" }),
|
|
7755
|
+
/* @__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" })
|
|
7756
|
+
] });
|
|
7757
|
+
}
|
|
7758
|
+
return /* @__PURE__ */ jsxs12("svg", { className: "gantt-resourceTimeline-resourceTypeIcon gantt-resourceTimeline-resourceTypeIconOther", width: "16", height: "16", viewBox: "0 0 24 24", "aria-hidden": "true", children: [
|
|
7759
|
+
/* @__PURE__ */ jsx15("circle", { cx: "12", cy: "12", r: "9" }),
|
|
7760
|
+
/* @__PURE__ */ jsx15("path", { d: "M12 8v4" }),
|
|
7761
|
+
/* @__PURE__ */ jsx15("path", { d: "M12 16h.01" })
|
|
7762
|
+
] });
|
|
7763
|
+
};
|
|
7723
7764
|
var ResourceHeader = ({
|
|
7724
7765
|
resource,
|
|
7725
7766
|
resourceId,
|
|
7767
|
+
rowIndex,
|
|
7726
7768
|
conflictCount,
|
|
7769
|
+
workedDays,
|
|
7770
|
+
assignmentCount,
|
|
7727
7771
|
height,
|
|
7728
7772
|
paddingBottom,
|
|
7729
|
-
menuCommands
|
|
7773
|
+
menuCommands,
|
|
7774
|
+
onResourceChange,
|
|
7775
|
+
onConflictBadgeClick
|
|
7730
7776
|
}) => {
|
|
7731
7777
|
const [menuOpen, setMenuOpen] = useState8(false);
|
|
7778
|
+
const [typeMenuOpen, setTypeMenuOpen] = useState8(false);
|
|
7779
|
+
const [scopeMenuOpen, setScopeMenuOpen] = useState8(false);
|
|
7780
|
+
const [draftName, setDraftName] = useState8(resource.name);
|
|
7732
7781
|
const visibleCommands = useMemo9(
|
|
7733
7782
|
() => menuCommands.filter((command) => command.isVisible?.(resource) ?? true),
|
|
7734
7783
|
[menuCommands, resource]
|
|
7735
7784
|
);
|
|
7736
7785
|
const hasMenu = visibleCommands.length > 0;
|
|
7786
|
+
const type = resource.type ?? "\u0414\u0440\u0443\u0433\u043E\u0435";
|
|
7787
|
+
const scope = resource.scope ?? "Project";
|
|
7788
|
+
const scopeLabel = RESOURCE_SCOPE_LABELS[scope] ?? scope;
|
|
7789
|
+
useEffect8(() => {
|
|
7790
|
+
setDraftName(resource.name);
|
|
7791
|
+
}, [resource.name]);
|
|
7792
|
+
const applyResourcePatch = useCallback7((patch) => {
|
|
7793
|
+
onResourceChange?.({ ...resource, ...patch });
|
|
7794
|
+
}, [onResourceChange, resource]);
|
|
7795
|
+
const handleNameCommit = useCallback7(() => {
|
|
7796
|
+
const nextName = draftName.trim();
|
|
7797
|
+
if (!nextName) {
|
|
7798
|
+
setDraftName(resource.name);
|
|
7799
|
+
return;
|
|
7800
|
+
}
|
|
7801
|
+
if (nextName !== resource.name) {
|
|
7802
|
+
applyResourcePatch({ name: nextName });
|
|
7803
|
+
}
|
|
7804
|
+
}, [applyResourcePatch, draftName, resource.name]);
|
|
7805
|
+
const handleNameKeyDown = useCallback7((event) => {
|
|
7806
|
+
if (event.key === "Enter") {
|
|
7807
|
+
event.preventDefault();
|
|
7808
|
+
event.currentTarget.blur();
|
|
7809
|
+
} else if (event.key === "Escape") {
|
|
7810
|
+
setDraftName(resource.name);
|
|
7811
|
+
event.currentTarget.blur();
|
|
7812
|
+
}
|
|
7813
|
+
}, [resource.name]);
|
|
7737
7814
|
const handleCommandClick = (command, event) => {
|
|
7738
7815
|
event.stopPropagation();
|
|
7739
7816
|
if (command.closeOnSelect !== false) {
|
|
@@ -7751,44 +7828,154 @@ var ResourceHeader = ({
|
|
|
7751
7828
|
paddingBottom: `${paddingBottom}px`
|
|
7752
7829
|
},
|
|
7753
7830
|
children: [
|
|
7754
|
-
/* @__PURE__ */ jsx15("span", { className: "gantt-resourceTimeline-
|
|
7755
|
-
|
|
7756
|
-
|
|
7757
|
-
|
|
7758
|
-
|
|
7759
|
-
|
|
7760
|
-
|
|
7761
|
-
|
|
7762
|
-
|
|
7763
|
-
|
|
7764
|
-
|
|
7831
|
+
/* @__PURE__ */ jsx15("span", { className: "gantt-resourceTimeline-resourceNumber", children: rowIndex + 1 }),
|
|
7832
|
+
/* @__PURE__ */ jsxs12("span", { className: "gantt-resourceTimeline-resourceName", children: [
|
|
7833
|
+
/* @__PURE__ */ jsxs12(Popover, { open: typeMenuOpen, onOpenChange: setTypeMenuOpen, children: [
|
|
7834
|
+
/* @__PURE__ */ jsx15(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx15(
|
|
7835
|
+
"button",
|
|
7836
|
+
{
|
|
7837
|
+
type: "button",
|
|
7838
|
+
className: `gantt-resourceTimeline-resourceTypeIconButton gantt-resourceTimeline-resourceTypeIconButton${RESOURCE_TYPE_CLASS_NAMES[type] ?? "Other"}`,
|
|
7839
|
+
disabled: !onResourceChange,
|
|
7840
|
+
"aria-label": `\u0422\u0438\u043F \u0440\u0435\u0441\u0443\u0440\u0441\u0430 ${resource.name}: ${type}`,
|
|
7841
|
+
title: type,
|
|
7842
|
+
onClick: (event) => {
|
|
7843
|
+
event.stopPropagation();
|
|
7844
|
+
setTypeMenuOpen((open) => !open);
|
|
7845
|
+
},
|
|
7846
|
+
children: /* @__PURE__ */ jsx15(ResourceTypeIcon, { type })
|
|
7847
|
+
}
|
|
7848
|
+
) }),
|
|
7849
|
+
/* @__PURE__ */ jsx15(PopoverContent, { className: "gantt-resourceTimeline-resourceOptionMenu", portal: true, align: "start", children: RESOURCE_TYPE_OPTIONS.map((option) => /* @__PURE__ */ jsxs12(
|
|
7850
|
+
"button",
|
|
7851
|
+
{
|
|
7852
|
+
type: "button",
|
|
7853
|
+
className: `gantt-resourceTimeline-resourceOption${type === option ? " gantt-resourceTimeline-resourceOptionActive" : ""}`,
|
|
7854
|
+
onClick: (event) => {
|
|
7855
|
+
event.stopPropagation();
|
|
7856
|
+
setTypeMenuOpen(false);
|
|
7857
|
+
applyResourcePatch({ type: option });
|
|
7858
|
+
},
|
|
7859
|
+
children: [
|
|
7860
|
+
/* @__PURE__ */ jsx15("span", { className: "gantt-resourceTimeline-resourceOptionIcon", children: /* @__PURE__ */ jsx15(ResourceTypeIcon, { type: option }) }),
|
|
7861
|
+
option
|
|
7862
|
+
]
|
|
7863
|
+
},
|
|
7864
|
+
option
|
|
7865
|
+
)) })
|
|
7866
|
+
] }),
|
|
7867
|
+
/* @__PURE__ */ jsx15(
|
|
7868
|
+
"textarea",
|
|
7869
|
+
{
|
|
7870
|
+
className: "gantt-resourceTimeline-resourceNameInput",
|
|
7871
|
+
value: draftName,
|
|
7872
|
+
disabled: !onResourceChange,
|
|
7873
|
+
"aria-label": `\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u0430 ${resource.name}`,
|
|
7874
|
+
rows: 2,
|
|
7875
|
+
onChange: (event) => setDraftName(event.target.value),
|
|
7876
|
+
onBlur: handleNameCommit,
|
|
7877
|
+
onKeyDown: handleNameKeyDown,
|
|
7878
|
+
onClick: (event) => event.stopPropagation()
|
|
7879
|
+
}
|
|
7880
|
+
)
|
|
7881
|
+
] }),
|
|
7882
|
+
/* @__PURE__ */ jsxs12(Popover, { open: scopeMenuOpen, onOpenChange: setScopeMenuOpen, children: [
|
|
7765
7883
|
/* @__PURE__ */ jsx15(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx15(
|
|
7766
7884
|
"button",
|
|
7767
7885
|
{
|
|
7768
|
-
className: "gantt-resourceTimeline-resourceMenuButton",
|
|
7769
7886
|
type: "button",
|
|
7770
|
-
|
|
7887
|
+
className: `gantt-resourceTimeline-resourceScopeChip gantt-resourceTimeline-resourceScope${scope === "Shared" ? "Shared" : "Project"}`,
|
|
7888
|
+
disabled: !onResourceChange,
|
|
7889
|
+
"aria-label": `\u0414\u043E\u0441\u0442\u0443\u043F\u043D\u043E\u0441\u0442\u044C \u0440\u0435\u0441\u0443\u0440\u0441\u0430 ${resource.name}`,
|
|
7771
7890
|
onClick: (event) => {
|
|
7772
7891
|
event.stopPropagation();
|
|
7773
|
-
|
|
7892
|
+
setScopeMenuOpen((open) => !open);
|
|
7774
7893
|
},
|
|
7775
|
-
children: /* @__PURE__ */ jsx15("span", {
|
|
7894
|
+
children: /* @__PURE__ */ jsx15("span", { children: scopeLabel })
|
|
7776
7895
|
}
|
|
7777
7896
|
) }),
|
|
7778
|
-
/* @__PURE__ */ jsx15(PopoverContent, { className: "gantt-resourceTimeline-
|
|
7897
|
+
/* @__PURE__ */ jsx15(PopoverContent, { className: "gantt-resourceTimeline-resourceOptionMenu", portal: true, align: "start", children: RESOURCE_SCOPE_OPTIONS.map((option) => /* @__PURE__ */ jsxs12(
|
|
7779
7898
|
"button",
|
|
7780
7899
|
{
|
|
7781
7900
|
type: "button",
|
|
7782
|
-
className: `gantt-resourceTimeline-
|
|
7783
|
-
|
|
7784
|
-
|
|
7901
|
+
className: `gantt-resourceTimeline-resourceOption${scope === option ? " gantt-resourceTimeline-resourceOptionActive" : ""}`,
|
|
7902
|
+
onClick: (event) => {
|
|
7903
|
+
event.stopPropagation();
|
|
7904
|
+
setScopeMenuOpen(false);
|
|
7905
|
+
applyResourcePatch({ scope: option });
|
|
7906
|
+
},
|
|
7785
7907
|
children: [
|
|
7786
|
-
|
|
7787
|
-
|
|
7908
|
+
/* @__PURE__ */ jsx15("span", { className: `gantt-resourceTimeline-resourceOptionScopeDot gantt-resourceTimeline-resourceScope${option}` }),
|
|
7909
|
+
RESOURCE_SCOPE_LABELS[option] ?? option
|
|
7788
7910
|
]
|
|
7789
7911
|
},
|
|
7790
|
-
|
|
7912
|
+
option
|
|
7791
7913
|
)) })
|
|
7914
|
+
] }),
|
|
7915
|
+
/* @__PURE__ */ jsxs12(
|
|
7916
|
+
"span",
|
|
7917
|
+
{
|
|
7918
|
+
className: "gantt-resourceTimeline-resourceAssignments",
|
|
7919
|
+
"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.`,
|
|
7920
|
+
children: [
|
|
7921
|
+
/* @__PURE__ */ jsxs12("span", { className: "gantt-resourceTimeline-resourceWorkedDays", children: [
|
|
7922
|
+
workedDays,
|
|
7923
|
+
" \u0434\u043D."
|
|
7924
|
+
] }),
|
|
7925
|
+
/* @__PURE__ */ jsxs12("span", { className: "gantt-resourceTimeline-resourceAssignmentCount", children: [
|
|
7926
|
+
/* @__PURE__ */ jsxs12("svg", { className: "gantt-resourceTimeline-resourceAssignmentIcon", width: "14", height: "14", viewBox: "0 0 24 24", "aria-hidden": "true", children: [
|
|
7927
|
+
/* @__PURE__ */ jsx15("rect", { width: "15", height: "5", x: "4", y: "5", rx: "2" }),
|
|
7928
|
+
/* @__PURE__ */ jsx15("rect", { width: "10", height: "5", x: "4", y: "14", rx: "2" })
|
|
7929
|
+
] }),
|
|
7930
|
+
/* @__PURE__ */ jsx15("span", { children: assignmentCount })
|
|
7931
|
+
] })
|
|
7932
|
+
]
|
|
7933
|
+
}
|
|
7934
|
+
),
|
|
7935
|
+
/* @__PURE__ */ jsxs12("span", { className: "gantt-resourceTimeline-resourceActions", children: [
|
|
7936
|
+
conflictCount > 0 && /* @__PURE__ */ jsx15(
|
|
7937
|
+
"button",
|
|
7938
|
+
{
|
|
7939
|
+
type: "button",
|
|
7940
|
+
className: "gantt-resourceTimeline-conflictBadge",
|
|
7941
|
+
"aria-label": formatOverlapCount(conflictCount),
|
|
7942
|
+
title: formatOverlapCount(conflictCount),
|
|
7943
|
+
onClick: (event) => {
|
|
7944
|
+
event.stopPropagation();
|
|
7945
|
+
onConflictBadgeClick?.(resourceId);
|
|
7946
|
+
},
|
|
7947
|
+
children: conflictCount
|
|
7948
|
+
}
|
|
7949
|
+
),
|
|
7950
|
+
hasMenu && /* @__PURE__ */ jsxs12(Popover, { open: menuOpen, onOpenChange: setMenuOpen, children: [
|
|
7951
|
+
/* @__PURE__ */ jsx15(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx15(
|
|
7952
|
+
"button",
|
|
7953
|
+
{
|
|
7954
|
+
className: "gantt-resourceTimeline-resourceMenuButton",
|
|
7955
|
+
type: "button",
|
|
7956
|
+
"aria-label": "\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u044F \u0440\u0435\u0441\u0443\u0440\u0441\u0430",
|
|
7957
|
+
onClick: (event) => {
|
|
7958
|
+
event.stopPropagation();
|
|
7959
|
+
setMenuOpen((open) => !open);
|
|
7960
|
+
},
|
|
7961
|
+
children: /* @__PURE__ */ jsx15("span", { "aria-hidden": "true", children: "\u22EE" })
|
|
7962
|
+
}
|
|
7963
|
+
) }),
|
|
7964
|
+
/* @__PURE__ */ jsx15(PopoverContent, { className: "gantt-resourceTimeline-resourceMenu", portal: true, align: "end", children: visibleCommands.map((command) => /* @__PURE__ */ jsxs12(
|
|
7965
|
+
"button",
|
|
7966
|
+
{
|
|
7967
|
+
type: "button",
|
|
7968
|
+
className: `gantt-resourceTimeline-resourceMenuItem${command.danger ? " gantt-resourceTimeline-resourceMenuItemDanger" : ""}`,
|
|
7969
|
+
disabled: command.isDisabled?.(resource) ?? false,
|
|
7970
|
+
onClick: (event) => handleCommandClick(command, event),
|
|
7971
|
+
children: [
|
|
7972
|
+
command.icon,
|
|
7973
|
+
command.label
|
|
7974
|
+
]
|
|
7975
|
+
},
|
|
7976
|
+
command.id
|
|
7977
|
+
)) })
|
|
7978
|
+
] })
|
|
7792
7979
|
] })
|
|
7793
7980
|
]
|
|
7794
7981
|
}
|
|
@@ -7827,7 +8014,7 @@ var NewResourceRow = ({ height, onConfirm, onCancel }) => {
|
|
|
7827
8014
|
handleConfirm();
|
|
7828
8015
|
}
|
|
7829
8016
|
};
|
|
7830
|
-
return /* @__PURE__ */
|
|
8017
|
+
return /* @__PURE__ */ jsxs12(
|
|
7831
8018
|
"div",
|
|
7832
8019
|
{
|
|
7833
8020
|
className: "gantt-resourceTimeline-resourceHeader gantt-resourceTimeline-resourceHeaderNew",
|
|
@@ -7835,18 +8022,21 @@ var NewResourceRow = ({ height, onConfirm, onCancel }) => {
|
|
|
7835
8022
|
height: `${height}px`,
|
|
7836
8023
|
paddingBottom: `${DEFAULT_RESOURCE_ROW_GAP}px`
|
|
7837
8024
|
},
|
|
7838
|
-
children:
|
|
7839
|
-
|
|
7840
|
-
|
|
7841
|
-
|
|
7842
|
-
|
|
7843
|
-
|
|
7844
|
-
|
|
7845
|
-
|
|
7846
|
-
|
|
7847
|
-
|
|
7848
|
-
|
|
7849
|
-
|
|
8025
|
+
children: [
|
|
8026
|
+
/* @__PURE__ */ jsx15("span", { className: "gantt-resourceTimeline-resourceNumber", children: "+" }),
|
|
8027
|
+
/* @__PURE__ */ jsx15(
|
|
8028
|
+
Input,
|
|
8029
|
+
{
|
|
8030
|
+
ref: inputRef,
|
|
8031
|
+
value: nameValue,
|
|
8032
|
+
onChange: (event) => setNameValue(event.target.value),
|
|
8033
|
+
onKeyDown: handleKeyDown,
|
|
8034
|
+
onBlur: handleBlur,
|
|
8035
|
+
placeholder: "\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u0430",
|
|
8036
|
+
className: "gantt-resourceTimeline-resourceInput"
|
|
8037
|
+
}
|
|
8038
|
+
)
|
|
8039
|
+
]
|
|
7850
8040
|
}
|
|
7851
8041
|
);
|
|
7852
8042
|
};
|
|
@@ -7867,7 +8057,10 @@ function ResourceTimelineChart({
|
|
|
7867
8057
|
renderItem,
|
|
7868
8058
|
getItemClassName,
|
|
7869
8059
|
onResourceItemClick,
|
|
8060
|
+
onResourceItemMenuClick,
|
|
8061
|
+
activeResourceItemId,
|
|
7870
8062
|
onResourceItemMove,
|
|
8063
|
+
onResourceChange,
|
|
7871
8064
|
onAddResource,
|
|
7872
8065
|
enableAddResource = true,
|
|
7873
8066
|
resourceMenuCommands = []
|
|
@@ -7875,7 +8068,10 @@ function ResourceTimelineChart({
|
|
|
7875
8068
|
const scrollContainerRef = useRef8(null);
|
|
7876
8069
|
const gridRef = useRef8(null);
|
|
7877
8070
|
const panStateRef = useRef8(null);
|
|
8071
|
+
const conflictNavigationIndexRef = useRef8(/* @__PURE__ */ new Map());
|
|
8072
|
+
const conflictHighlightTimeoutRef = useRef8(null);
|
|
7878
8073
|
const [isCreatingResource, setIsCreatingResource] = useState8(false);
|
|
8074
|
+
const [activeConflictItemId, setActiveConflictItemId] = useState8(null);
|
|
7879
8075
|
const validItems = useMemo9(() => collectValidItems(resources), [resources]);
|
|
7880
8076
|
const dateRange = useMemo9(() => getMultiMonthDays(validItems), [validItems]);
|
|
7881
8077
|
const monthStart = useMemo9(() => {
|
|
@@ -7887,6 +8083,26 @@ function ResourceTimelineChart({
|
|
|
7887
8083
|
[customDays, isWeekend3]
|
|
7888
8084
|
);
|
|
7889
8085
|
const gridWidth = useMemo9(() => Math.round(dateRange.length * dayWidth), [dateRange.length, dayWidth]);
|
|
8086
|
+
const effectiveRowHeaderWidth = Math.max(rowHeaderWidth, DEFAULT_ROW_HEADER_WIDTH);
|
|
8087
|
+
const workedDaysByResourceId = useMemo9(() => {
|
|
8088
|
+
const map = /* @__PURE__ */ new Map();
|
|
8089
|
+
for (const resource of resources) {
|
|
8090
|
+
const workedDays = resource.items.reduce((sum, item) => {
|
|
8091
|
+
try {
|
|
8092
|
+
const startDate = parseUTCDate(item.startDate);
|
|
8093
|
+
const endDate = parseUTCDate(item.endDate);
|
|
8094
|
+
if (!isValidDate(startDate) || !isValidDate(endDate)) {
|
|
8095
|
+
return sum;
|
|
8096
|
+
}
|
|
8097
|
+
return sum + getDurationValue(startDate, endDate, businessDays, weekendPredicate);
|
|
8098
|
+
} catch {
|
|
8099
|
+
return sum;
|
|
8100
|
+
}
|
|
8101
|
+
}, 0);
|
|
8102
|
+
map.set(resource.id, workedDays);
|
|
8103
|
+
}
|
|
8104
|
+
return map;
|
|
8105
|
+
}, [businessDays, resources, weekendPredicate]);
|
|
7890
8106
|
const layout = useMemo9(
|
|
7891
8107
|
() => layoutResourceTimelineItems(resources, {
|
|
7892
8108
|
monthStart,
|
|
@@ -7910,6 +8126,23 @@ function ResourceTimelineChart({
|
|
|
7910
8126
|
}
|
|
7911
8127
|
return map;
|
|
7912
8128
|
}, [layout.items]);
|
|
8129
|
+
const conflictItemsByResourceId = useMemo9(() => {
|
|
8130
|
+
const map = /* @__PURE__ */ new Map();
|
|
8131
|
+
for (const item of layout.items) {
|
|
8132
|
+
if (item.conflictRanges.length === 0) {
|
|
8133
|
+
continue;
|
|
8134
|
+
}
|
|
8135
|
+
const next = map.get(item.resourceId) ?? [];
|
|
8136
|
+
next.push(item);
|
|
8137
|
+
map.set(item.resourceId, next);
|
|
8138
|
+
}
|
|
8139
|
+
for (const items of map.values()) {
|
|
8140
|
+
items.sort(
|
|
8141
|
+
(left, right) => left.top - right.top || left.left - right.left || left.itemId.localeCompare(right.itemId)
|
|
8142
|
+
);
|
|
8143
|
+
}
|
|
8144
|
+
return map;
|
|
8145
|
+
}, [layout.items]);
|
|
7913
8146
|
const canAddResource = enableAddResource && Boolean(onAddResource);
|
|
7914
8147
|
const resourceAddRowHeight = laneHeight + DEFAULT_RESOURCE_ROW_GAP;
|
|
7915
8148
|
const displayTotalHeight = layout.totalHeight + (canAddResource ? resourceAddRowHeight : 0);
|
|
@@ -7917,11 +8150,38 @@ function ResourceTimelineChart({
|
|
|
7917
8150
|
onAddResource?.({
|
|
7918
8151
|
id: crypto.randomUUID(),
|
|
7919
8152
|
name,
|
|
8153
|
+
type: "\u0414\u0440\u0443\u0433\u043E\u0435",
|
|
8154
|
+
scope: "Project",
|
|
7920
8155
|
items: []
|
|
7921
8156
|
});
|
|
7922
8157
|
setIsCreatingResource(false);
|
|
7923
8158
|
}, [onAddResource]);
|
|
7924
8159
|
const handleCancelNewResource = useCallback7(() => setIsCreatingResource(false), []);
|
|
8160
|
+
const handleConflictBadgeClick = useCallback7((resourceId) => {
|
|
8161
|
+
const conflictItems = conflictItemsByResourceId.get(resourceId) ?? [];
|
|
8162
|
+
if (conflictItems.length === 0) {
|
|
8163
|
+
return;
|
|
8164
|
+
}
|
|
8165
|
+
const currentIndex = conflictNavigationIndexRef.current.get(resourceId) ?? 0;
|
|
8166
|
+
const target = conflictItems[currentIndex % conflictItems.length];
|
|
8167
|
+
conflictNavigationIndexRef.current.set(resourceId, (currentIndex + 1) % conflictItems.length);
|
|
8168
|
+
const container = scrollContainerRef.current;
|
|
8169
|
+
if (container) {
|
|
8170
|
+
container.scrollTo({
|
|
8171
|
+
left: Math.max(0, Math.round(target.left - dayWidth * 2)),
|
|
8172
|
+
top: Math.max(0, Math.round(target.top - laneHeight)),
|
|
8173
|
+
behavior: "smooth"
|
|
8174
|
+
});
|
|
8175
|
+
}
|
|
8176
|
+
setActiveConflictItemId(target.itemId);
|
|
8177
|
+
if (conflictHighlightTimeoutRef.current) {
|
|
8178
|
+
window.clearTimeout(conflictHighlightTimeoutRef.current);
|
|
8179
|
+
}
|
|
8180
|
+
conflictHighlightTimeoutRef.current = window.setTimeout(() => {
|
|
8181
|
+
setActiveConflictItemId((current) => current === target.itemId ? null : current);
|
|
8182
|
+
conflictHighlightTimeoutRef.current = null;
|
|
8183
|
+
}, 1600);
|
|
8184
|
+
}, [conflictItemsByResourceId, dayWidth, laneHeight]);
|
|
7925
8185
|
const { preview, startDrag } = useResourceItemDrag({
|
|
7926
8186
|
dayWidth,
|
|
7927
8187
|
monthStart,
|
|
@@ -7990,6 +8250,13 @@ function ResourceTimelineChart({
|
|
|
7990
8250
|
window.removeEventListener("mouseup", handlePanEnd);
|
|
7991
8251
|
};
|
|
7992
8252
|
}, [allowVerticalPan]);
|
|
8253
|
+
useEffect8(() => {
|
|
8254
|
+
return () => {
|
|
8255
|
+
if (conflictHighlightTimeoutRef.current) {
|
|
8256
|
+
window.clearTimeout(conflictHighlightTimeoutRef.current);
|
|
8257
|
+
}
|
|
8258
|
+
};
|
|
8259
|
+
}, []);
|
|
7993
8260
|
return /* @__PURE__ */ jsx15("div", { className: "gantt-container gantt-resourceTimeline", children: /* @__PURE__ */ jsx15(
|
|
7994
8261
|
"div",
|
|
7995
8262
|
{
|
|
@@ -8007,24 +8274,36 @@ function ResourceTimelineChart({
|
|
|
8007
8274
|
"div",
|
|
8008
8275
|
{
|
|
8009
8276
|
className: "gantt-resourceTimeline-resourceColumn",
|
|
8010
|
-
style: { width: `${
|
|
8277
|
+
style: { width: `${effectiveRowHeaderWidth}px`, minWidth: `${effectiveRowHeaderWidth}px` },
|
|
8011
8278
|
children: [
|
|
8012
|
-
/* @__PURE__ */
|
|
8279
|
+
/* @__PURE__ */ jsxs12(
|
|
8013
8280
|
"div",
|
|
8014
8281
|
{
|
|
8015
8282
|
className: "gantt-resourceTimeline-corner",
|
|
8016
|
-
style: { height: `${headerHeight}px` }
|
|
8283
|
+
style: { height: `${headerHeight + 0.5}px` },
|
|
8284
|
+
children: [
|
|
8285
|
+
/* @__PURE__ */ jsx15("span", { className: "gantt-resourceTimeline-resourceHeaderCell gantt-resourceTimeline-resourceHeaderNumber", children: "#" }),
|
|
8286
|
+
/* @__PURE__ */ jsx15("span", { className: "gantt-resourceTimeline-resourceHeaderCell gantt-resourceTimeline-resourceHeaderName", children: "\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435" }),
|
|
8287
|
+
/* @__PURE__ */ jsx15("span", { className: "gantt-resourceTimeline-resourceHeaderCell", "aria-label": "\u0414\u043E\u0441\u0442\u0443\u043F\u043D\u043E\u0441\u0442\u044C" }),
|
|
8288
|
+
/* @__PURE__ */ jsx15("span", { className: "gantt-resourceTimeline-resourceHeaderCell", children: "\u041D\u0430\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F" }),
|
|
8289
|
+
/* @__PURE__ */ jsx15("span", { className: "gantt-resourceTimeline-resourceHeaderCell gantt-resourceTimeline-resourceHeaderActions", "aria-label": "\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u044F" })
|
|
8290
|
+
]
|
|
8017
8291
|
}
|
|
8018
8292
|
),
|
|
8019
|
-
layout.rows.map((row) => /* @__PURE__ */ jsx15(
|
|
8293
|
+
layout.rows.map((row, rowIndex) => /* @__PURE__ */ jsx15(
|
|
8020
8294
|
ResourceHeader,
|
|
8021
8295
|
{
|
|
8022
8296
|
resource: row.resource,
|
|
8023
8297
|
resourceId: row.resourceId,
|
|
8298
|
+
rowIndex,
|
|
8024
8299
|
conflictCount: row.conflictCount,
|
|
8300
|
+
workedDays: workedDaysByResourceId.get(row.resourceId) ?? 0,
|
|
8301
|
+
assignmentCount: row.resource.items.length,
|
|
8025
8302
|
height: row.resourceRowHeight + DEFAULT_RESOURCE_ROW_GAP,
|
|
8026
8303
|
paddingBottom: DEFAULT_RESOURCE_ROW_GAP,
|
|
8027
|
-
menuCommands: resourceMenuCommands
|
|
8304
|
+
menuCommands: resourceMenuCommands,
|
|
8305
|
+
onResourceChange,
|
|
8306
|
+
onConflictBadgeClick: handleConflictBadgeClick
|
|
8028
8307
|
},
|
|
8029
8308
|
row.resourceId
|
|
8030
8309
|
)),
|
|
@@ -8109,9 +8388,14 @@ function ResourceTimelineChart({
|
|
|
8109
8388
|
(resourceItems) => resourceItems.map((layoutItem) => {
|
|
8110
8389
|
const customClassName = getItemClassName?.(layoutItem.item);
|
|
8111
8390
|
const isDraggingItem = preview?.itemId === layoutItem.itemId;
|
|
8391
|
+
const hasItemMenu = Boolean(onResourceItemMenuClick);
|
|
8392
|
+
const isActiveItem = activeResourceItemId === layoutItem.itemId;
|
|
8112
8393
|
const className = [
|
|
8113
8394
|
"gantt-resourceTimeline-item",
|
|
8395
|
+
hasItemMenu && "gantt-resourceTimeline-itemHasMenu",
|
|
8396
|
+
isActiveItem && "gantt-resourceTimeline-itemActive",
|
|
8114
8397
|
isDraggingItem && "gantt-resourceTimeline-itemDragging",
|
|
8398
|
+
activeConflictItemId === layoutItem.itemId && "gantt-resourceTimeline-itemConflictActive",
|
|
8115
8399
|
(readonly || layoutItem.item.locked) && "gantt-resourceTimeline-itemDisabled",
|
|
8116
8400
|
customClassName
|
|
8117
8401
|
].filter(Boolean).join(" ");
|
|
@@ -8210,6 +8494,22 @@ function ResourceTimelineChart({
|
|
|
8210
8494
|
},
|
|
8211
8495
|
`conflict-overlay-${index}`
|
|
8212
8496
|
)),
|
|
8497
|
+
hasItemMenu && /* @__PURE__ */ jsx15(
|
|
8498
|
+
"button",
|
|
8499
|
+
{
|
|
8500
|
+
type: "button",
|
|
8501
|
+
className: "gantt-resourceTimeline-itemMenuButton",
|
|
8502
|
+
"aria-label": "\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u044F \u043D\u0430\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F",
|
|
8503
|
+
onMouseDown: (event) => {
|
|
8504
|
+
event.stopPropagation();
|
|
8505
|
+
},
|
|
8506
|
+
onClick: (event) => {
|
|
8507
|
+
event.stopPropagation();
|
|
8508
|
+
onResourceItemMenuClick?.(layoutItem.item);
|
|
8509
|
+
},
|
|
8510
|
+
children: /* @__PURE__ */ jsx15("span", { "aria-hidden": "true", children: "\u22EE" })
|
|
8511
|
+
}
|
|
8512
|
+
),
|
|
8213
8513
|
/* @__PURE__ */ jsx15("div", { className: "gantt-resourceTimeline-itemInner", children: renderItem ? renderItem(layoutItem.item, renderContext) : /* @__PURE__ */ jsxs12("div", { className: "gantt-resourceTimeline-defaultItemContent", children: [
|
|
8214
8514
|
/* @__PURE__ */ jsxs12("div", { className: "gantt-resourceTimeline-defaultItemMain", children: [
|
|
8215
8515
|
/* @__PURE__ */ jsx15(
|