gantt-lib 0.81.0 → 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/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-p-aPnDwQ.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-p-aPnDwQ.mjs';
2
+ import { T as Task$1, R as ResourceTimelineItem, V as ValidationResult, a as ResourcePlannerChartProps, b as ResourceTimelineResource } from './index-BPStPBtF.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-BPStPBtF.mjs';
4
4
  import * as react_jsx_runtime from 'react/jsx-runtime';
5
5
  import * as RadixPopover from '@radix-ui/react-popover';
6
6
 
@@ -549,7 +549,7 @@ declare const GanttChart: <TTask extends Task = Task, TItem extends ResourceTime
549
549
  ref?: React$1.Ref<GanttChartHandle>;
550
550
  }) => React$1.ReactElement;
551
551
 
552
- declare function ResourceTimelineChart<TItem extends ResourceTimelineItem = ResourceTimelineItem>({ resources, dayWidth, viewMode, rowHeaderWidth, laneHeight, headerHeight, containerHeight, allowVerticalPan, customDays, isWeekend, businessDays, readonly, disableResourceReassignment, renderItem, getItemClassName, onResourceItemClick, onResourceItemMenuClick, activeResourceItemId, onResourceItemMove, onAddResource, enableAddResource, resourceMenuCommands, }: 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, onResourceItemMenuClick, activeResourceItemId, onResourceItemMove, onResourceChange, onAddResource, enableAddResource, resourceMenuCommands, }: ResourcePlannerChartProps<TItem>): react_jsx_runtime.JSX.Element;
553
553
 
554
554
  interface TaskRowProps {
555
555
  /** Task data to render */
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-p-aPnDwQ.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-p-aPnDwQ.js';
2
+ import { T as Task$1, R as ResourceTimelineItem, V as ValidationResult, a as ResourcePlannerChartProps, b as ResourceTimelineResource } from './index-BPStPBtF.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-BPStPBtF.js';
4
4
  import * as react_jsx_runtime from 'react/jsx-runtime';
5
5
  import * as RadixPopover from '@radix-ui/react-popover';
6
6
 
@@ -549,7 +549,7 @@ declare const GanttChart: <TTask extends Task = Task, TItem extends ResourceTime
549
549
  ref?: React$1.Ref<GanttChartHandle>;
550
550
  }) => React$1.ReactElement;
551
551
 
552
- declare function ResourceTimelineChart<TItem extends ResourceTimelineItem = ResourceTimelineItem>({ resources, dayWidth, viewMode, rowHeaderWidth, laneHeight, headerHeight, containerHeight, allowVerticalPan, customDays, isWeekend, businessDays, readonly, disableResourceReassignment, renderItem, getItemClassName, onResourceItemClick, onResourceItemMenuClick, activeResourceItemId, onResourceItemMove, onAddResource, enableAddResource, resourceMenuCommands, }: 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, onResourceItemMenuClick, activeResourceItemId, onResourceItemMove, onResourceChange, onAddResource, enableAddResource, resourceMenuCommands, }: ResourcePlannerChartProps<TItem>): react_jsx_runtime.JSX.Element;
553
553
 
554
554
  interface TaskRowProps {
555
555
  /** Task data to render */
package/dist/index.js CHANGED
@@ -7746,7 +7746,7 @@ var import_jsx_runtime15 = require("react/jsx-runtime");
7746
7746
  var DEFAULT_DAY_WIDTH = 40;
7747
7747
  var DEFAULT_HEADER_HEIGHT = 40;
7748
7748
  var DEFAULT_LANE_HEIGHT = 40;
7749
- var DEFAULT_ROW_HEADER_WIDTH = 240;
7749
+ var DEFAULT_ROW_HEADER_WIDTH = 420;
7750
7750
  var DEFAULT_RESOURCE_ROW_GAP = 8;
7751
7751
  var ITEM_OUTER_VERTICAL_INSET = 2;
7752
7752
  var ITEM_INNER_VERTICAL_INSET = 1;
@@ -7834,21 +7834,97 @@ var clampOverlaySegments = (segments2, maxWidth) => segments2.flatMap((segment)
7834
7834
  return width > 0 ? [{ left, width }] : [];
7835
7835
  });
7836
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 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"];
7838
+ var RESOURCE_SCOPE_OPTIONS = ["Shared", "Project"];
7839
+ var RESOURCE_SCOPE_LABELS = {
7840
+ Shared: "\u041E\u0431\u0449\u0438\u0439",
7841
+ Project: "\u041F\u0440\u043E\u0435\u043A\u0442"
7842
+ };
7843
+ var RESOURCE_TYPE_CLASS_NAMES = {
7844
+ \u041B\u044E\u0434\u0438: "People",
7845
+ \u041E\u0431\u043E\u0440\u0443\u0434\u043E\u0432\u0430\u043D\u0438\u0435: "Equipment",
7846
+ \u041C\u0430\u0442\u0435\u0440\u0438\u0430\u043B\u044B: "Materials",
7847
+ \u0414\u0440\u0443\u0433\u043E\u0435: "Other"
7848
+ };
7849
+ var ResourceTypeIcon = ({ type }) => {
7850
+ if (type === "\u041B\u044E\u0434\u0438") {
7851
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("svg", { className: "gantt-resourceTimeline-resourceTypeIcon gantt-resourceTimeline-resourceTypeIconPeople", width: "16", height: "16", viewBox: "0 0 24 24", "aria-hidden": "true", children: [
7852
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" }),
7853
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("circle", { cx: "9", cy: "7", r: "4" }),
7854
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "M22 21v-2a4 4 0 0 0-3-3.87" }),
7855
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "M16 3.13a4 4 0 0 1 0 7.75" })
7856
+ ] });
7857
+ }
7858
+ if (type === "\u041E\u0431\u043E\u0440\u0443\u0434\u043E\u0432\u0430\u043D\u0438\u0435") {
7859
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("svg", { className: "gantt-resourceTimeline-resourceTypeIcon gantt-resourceTimeline-resourceTypeIconEquipment", width: "16", height: "16", viewBox: "0 0 24 24", "aria-hidden": "true", children: [
7860
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "m15 12-9.373 9.373a1 1 0 0 1-3.001-3L12 9" }),
7861
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "m18 15 4-4" }),
7862
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("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" })
7863
+ ] });
7864
+ }
7865
+ if (type === "\u041C\u0430\u0442\u0435\u0440\u0438\u0430\u043B\u044B") {
7866
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("svg", { className: "gantt-resourceTimeline-resourceTypeIcon gantt-resourceTimeline-resourceTypeIconMaterials", width: "16", height: "16", viewBox: "0 0 24 24", "aria-hidden": "true", children: [
7867
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "M10 22v-8" }),
7868
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "M2.336 8.89 10 14l11.715-7.029" }),
7869
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("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" })
7870
+ ] });
7871
+ }
7872
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("svg", { className: "gantt-resourceTimeline-resourceTypeIcon gantt-resourceTimeline-resourceTypeIconOther", width: "16", height: "16", viewBox: "0 0 24 24", "aria-hidden": "true", children: [
7873
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("circle", { cx: "12", cy: "12", r: "9" }),
7874
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "M12 8v4" }),
7875
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "M12 16h.01" })
7876
+ ] });
7877
+ };
7837
7878
  var ResourceHeader = ({
7838
7879
  resource,
7839
7880
  resourceId,
7881
+ rowIndex,
7840
7882
  conflictCount,
7883
+ workedDays,
7884
+ assignmentCount,
7841
7885
  height,
7842
7886
  paddingBottom,
7843
7887
  menuCommands,
7888
+ onResourceChange,
7844
7889
  onConflictBadgeClick
7845
7890
  }) => {
7846
7891
  const [menuOpen, setMenuOpen] = (0, import_react14.useState)(false);
7892
+ const [typeMenuOpen, setTypeMenuOpen] = (0, import_react14.useState)(false);
7893
+ const [scopeMenuOpen, setScopeMenuOpen] = (0, import_react14.useState)(false);
7894
+ const [draftName, setDraftName] = (0, import_react14.useState)(resource.name);
7847
7895
  const visibleCommands = (0, import_react14.useMemo)(
7848
7896
  () => menuCommands.filter((command) => command.isVisible?.(resource) ?? true),
7849
7897
  [menuCommands, resource]
7850
7898
  );
7851
7899
  const hasMenu = visibleCommands.length > 0;
7900
+ const type = resource.type ?? "\u0414\u0440\u0443\u0433\u043E\u0435";
7901
+ const scope = resource.scope ?? "Project";
7902
+ const scopeLabel = RESOURCE_SCOPE_LABELS[scope] ?? scope;
7903
+ (0, import_react14.useEffect)(() => {
7904
+ setDraftName(resource.name);
7905
+ }, [resource.name]);
7906
+ const applyResourcePatch = (0, import_react14.useCallback)((patch) => {
7907
+ onResourceChange?.({ ...resource, ...patch });
7908
+ }, [onResourceChange, resource]);
7909
+ const handleNameCommit = (0, import_react14.useCallback)(() => {
7910
+ const nextName = draftName.trim();
7911
+ if (!nextName) {
7912
+ setDraftName(resource.name);
7913
+ return;
7914
+ }
7915
+ if (nextName !== resource.name) {
7916
+ applyResourcePatch({ name: nextName });
7917
+ }
7918
+ }, [applyResourcePatch, draftName, resource.name]);
7919
+ const handleNameKeyDown = (0, import_react14.useCallback)((event) => {
7920
+ if (event.key === "Enter") {
7921
+ event.preventDefault();
7922
+ event.currentTarget.blur();
7923
+ } else if (event.key === "Escape") {
7924
+ setDraftName(resource.name);
7925
+ event.currentTarget.blur();
7926
+ }
7927
+ }, [resource.name]);
7852
7928
  const handleCommandClick = (command, event) => {
7853
7929
  event.stopPropagation();
7854
7930
  if (command.closeOnSelect !== false) {
@@ -7866,49 +7942,154 @@ var ResourceHeader = ({
7866
7942
  paddingBottom: `${paddingBottom}px`
7867
7943
  },
7868
7944
  children: [
7869
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "gantt-resourceTimeline-resourceName", children: resource.name }),
7870
- conflictCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
7871
- "button",
7872
- {
7873
- type: "button",
7874
- className: "gantt-resourceTimeline-conflictBadge",
7875
- "aria-label": formatOverlapCount(conflictCount),
7876
- title: formatOverlapCount(conflictCount),
7877
- onClick: (event) => {
7878
- event.stopPropagation();
7879
- onConflictBadgeClick?.(resourceId);
7880
- },
7881
- children: conflictCount
7882
- }
7883
- ),
7884
- hasMenu && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Popover, { open: menuOpen, onOpenChange: setMenuOpen, children: [
7945
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "gantt-resourceTimeline-resourceNumber", children: rowIndex + 1 }),
7946
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "gantt-resourceTimeline-resourceName", children: [
7947
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Popover, { open: typeMenuOpen, onOpenChange: setTypeMenuOpen, children: [
7948
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
7949
+ "button",
7950
+ {
7951
+ type: "button",
7952
+ className: `gantt-resourceTimeline-resourceTypeIconButton gantt-resourceTimeline-resourceTypeIconButton${RESOURCE_TYPE_CLASS_NAMES[type] ?? "Other"}`,
7953
+ disabled: !onResourceChange,
7954
+ "aria-label": `\u0422\u0438\u043F \u0440\u0435\u0441\u0443\u0440\u0441\u0430 ${resource.name}: ${type}`,
7955
+ title: type,
7956
+ onClick: (event) => {
7957
+ event.stopPropagation();
7958
+ setTypeMenuOpen((open) => !open);
7959
+ },
7960
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ResourceTypeIcon, { type })
7961
+ }
7962
+ ) }),
7963
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(PopoverContent, { className: "gantt-resourceTimeline-resourceOptionMenu", portal: true, align: "start", children: RESOURCE_TYPE_OPTIONS.map((option) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
7964
+ "button",
7965
+ {
7966
+ type: "button",
7967
+ className: `gantt-resourceTimeline-resourceOption${type === option ? " gantt-resourceTimeline-resourceOptionActive" : ""}`,
7968
+ onClick: (event) => {
7969
+ event.stopPropagation();
7970
+ setTypeMenuOpen(false);
7971
+ applyResourcePatch({ type: option });
7972
+ },
7973
+ children: [
7974
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "gantt-resourceTimeline-resourceOptionIcon", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ResourceTypeIcon, { type: option }) }),
7975
+ option
7976
+ ]
7977
+ },
7978
+ option
7979
+ )) })
7980
+ ] }),
7981
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
7982
+ "textarea",
7983
+ {
7984
+ className: "gantt-resourceTimeline-resourceNameInput",
7985
+ value: draftName,
7986
+ disabled: !onResourceChange,
7987
+ "aria-label": `\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u0430 ${resource.name}`,
7988
+ rows: 2,
7989
+ onChange: (event) => setDraftName(event.target.value),
7990
+ onBlur: handleNameCommit,
7991
+ onKeyDown: handleNameKeyDown,
7992
+ onClick: (event) => event.stopPropagation()
7993
+ }
7994
+ )
7995
+ ] }),
7996
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Popover, { open: scopeMenuOpen, onOpenChange: setScopeMenuOpen, children: [
7885
7997
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
7886
7998
  "button",
7887
7999
  {
7888
- className: "gantt-resourceTimeline-resourceMenuButton",
7889
8000
  type: "button",
7890
- "aria-label": "\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u044F \u0440\u0435\u0441\u0443\u0440\u0441\u0430",
8001
+ className: `gantt-resourceTimeline-resourceScopeChip gantt-resourceTimeline-resourceScope${scope === "Shared" ? "Shared" : "Project"}`,
8002
+ disabled: !onResourceChange,
8003
+ "aria-label": `\u0414\u043E\u0441\u0442\u0443\u043F\u043D\u043E\u0441\u0442\u044C \u0440\u0435\u0441\u0443\u0440\u0441\u0430 ${resource.name}`,
7891
8004
  onClick: (event) => {
7892
8005
  event.stopPropagation();
7893
- setMenuOpen((open) => !open);
8006
+ setScopeMenuOpen((open) => !open);
7894
8007
  },
7895
- children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { "aria-hidden": "true", children: "\u22EE" })
8008
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: scopeLabel })
7896
8009
  }
7897
8010
  ) }),
7898
- /* @__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)(
8011
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(PopoverContent, { className: "gantt-resourceTimeline-resourceOptionMenu", portal: true, align: "start", children: RESOURCE_SCOPE_OPTIONS.map((option) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
7899
8012
  "button",
7900
8013
  {
7901
8014
  type: "button",
7902
- className: `gantt-resourceTimeline-resourceMenuItem${command.danger ? " gantt-resourceTimeline-resourceMenuItemDanger" : ""}`,
7903
- disabled: command.isDisabled?.(resource) ?? false,
7904
- onClick: (event) => handleCommandClick(command, event),
8015
+ className: `gantt-resourceTimeline-resourceOption${scope === option ? " gantt-resourceTimeline-resourceOptionActive" : ""}`,
8016
+ onClick: (event) => {
8017
+ event.stopPropagation();
8018
+ setScopeMenuOpen(false);
8019
+ applyResourcePatch({ scope: option });
8020
+ },
7905
8021
  children: [
7906
- command.icon,
7907
- command.label
8022
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: `gantt-resourceTimeline-resourceOptionScopeDot gantt-resourceTimeline-resourceScope${option}` }),
8023
+ RESOURCE_SCOPE_LABELS[option] ?? option
7908
8024
  ]
7909
8025
  },
7910
- command.id
8026
+ option
7911
8027
  )) })
8028
+ ] }),
8029
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
8030
+ "span",
8031
+ {
8032
+ className: "gantt-resourceTimeline-resourceAssignments",
8033
+ "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.`,
8034
+ children: [
8035
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "gantt-resourceTimeline-resourceWorkedDays", children: [
8036
+ workedDays,
8037
+ " \u0434\u043D."
8038
+ ] }),
8039
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "gantt-resourceTimeline-resourceAssignmentCount", children: [
8040
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("svg", { className: "gantt-resourceTimeline-resourceAssignmentIcon", width: "14", height: "14", viewBox: "0 0 24 24", "aria-hidden": "true", children: [
8041
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("rect", { width: "15", height: "5", x: "4", y: "5", rx: "2" }),
8042
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("rect", { width: "10", height: "5", x: "4", y: "14", rx: "2" })
8043
+ ] }),
8044
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: assignmentCount })
8045
+ ] })
8046
+ ]
8047
+ }
8048
+ ),
8049
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "gantt-resourceTimeline-resourceActions", children: [
8050
+ conflictCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
8051
+ "button",
8052
+ {
8053
+ type: "button",
8054
+ className: "gantt-resourceTimeline-conflictBadge",
8055
+ "aria-label": formatOverlapCount(conflictCount),
8056
+ title: formatOverlapCount(conflictCount),
8057
+ onClick: (event) => {
8058
+ event.stopPropagation();
8059
+ onConflictBadgeClick?.(resourceId);
8060
+ },
8061
+ children: conflictCount
8062
+ }
8063
+ ),
8064
+ hasMenu && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Popover, { open: menuOpen, onOpenChange: setMenuOpen, children: [
8065
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
8066
+ "button",
8067
+ {
8068
+ className: "gantt-resourceTimeline-resourceMenuButton",
8069
+ type: "button",
8070
+ "aria-label": "\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u044F \u0440\u0435\u0441\u0443\u0440\u0441\u0430",
8071
+ onClick: (event) => {
8072
+ event.stopPropagation();
8073
+ setMenuOpen((open) => !open);
8074
+ },
8075
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { "aria-hidden": "true", children: "\u22EE" })
8076
+ }
8077
+ ) }),
8078
+ /* @__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)(
8079
+ "button",
8080
+ {
8081
+ type: "button",
8082
+ className: `gantt-resourceTimeline-resourceMenuItem${command.danger ? " gantt-resourceTimeline-resourceMenuItemDanger" : ""}`,
8083
+ disabled: command.isDisabled?.(resource) ?? false,
8084
+ onClick: (event) => handleCommandClick(command, event),
8085
+ children: [
8086
+ command.icon,
8087
+ command.label
8088
+ ]
8089
+ },
8090
+ command.id
8091
+ )) })
8092
+ ] })
7912
8093
  ] })
7913
8094
  ]
7914
8095
  }
@@ -7947,7 +8128,7 @@ var NewResourceRow = ({ height, onConfirm, onCancel }) => {
7947
8128
  handleConfirm();
7948
8129
  }
7949
8130
  };
7950
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
8131
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
7951
8132
  "div",
7952
8133
  {
7953
8134
  className: "gantt-resourceTimeline-resourceHeader gantt-resourceTimeline-resourceHeaderNew",
@@ -7955,18 +8136,21 @@ var NewResourceRow = ({ height, onConfirm, onCancel }) => {
7955
8136
  height: `${height}px`,
7956
8137
  paddingBottom: `${DEFAULT_RESOURCE_ROW_GAP}px`
7957
8138
  },
7958
- children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
7959
- Input,
7960
- {
7961
- ref: inputRef,
7962
- value: nameValue,
7963
- onChange: (event) => setNameValue(event.target.value),
7964
- onKeyDown: handleKeyDown,
7965
- onBlur: handleBlur,
7966
- placeholder: "\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u0430",
7967
- className: "gantt-resourceTimeline-resourceInput"
7968
- }
7969
- )
8139
+ children: [
8140
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "gantt-resourceTimeline-resourceNumber", children: "+" }),
8141
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
8142
+ Input,
8143
+ {
8144
+ ref: inputRef,
8145
+ value: nameValue,
8146
+ onChange: (event) => setNameValue(event.target.value),
8147
+ onKeyDown: handleKeyDown,
8148
+ onBlur: handleBlur,
8149
+ placeholder: "\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u0430",
8150
+ className: "gantt-resourceTimeline-resourceInput"
8151
+ }
8152
+ )
8153
+ ]
7970
8154
  }
7971
8155
  );
7972
8156
  };
@@ -7990,6 +8174,7 @@ function ResourceTimelineChart({
7990
8174
  onResourceItemMenuClick,
7991
8175
  activeResourceItemId,
7992
8176
  onResourceItemMove,
8177
+ onResourceChange,
7993
8178
  onAddResource,
7994
8179
  enableAddResource = true,
7995
8180
  resourceMenuCommands = []
@@ -8012,6 +8197,26 @@ function ResourceTimelineChart({
8012
8197
  [customDays, isWeekend3]
8013
8198
  );
8014
8199
  const gridWidth = (0, import_react14.useMemo)(() => Math.round(dateRange.length * dayWidth), [dateRange.length, dayWidth]);
8200
+ const effectiveRowHeaderWidth = Math.max(rowHeaderWidth, DEFAULT_ROW_HEADER_WIDTH);
8201
+ const workedDaysByResourceId = (0, import_react14.useMemo)(() => {
8202
+ const map = /* @__PURE__ */ new Map();
8203
+ for (const resource of resources) {
8204
+ const workedDays = resource.items.reduce((sum, item) => {
8205
+ try {
8206
+ const startDate = parseUTCDate(item.startDate);
8207
+ const endDate = parseUTCDate(item.endDate);
8208
+ if (!isValidDate(startDate) || !isValidDate(endDate)) {
8209
+ return sum;
8210
+ }
8211
+ return sum + getDurationValue(startDate, endDate, businessDays, weekendPredicate);
8212
+ } catch {
8213
+ return sum;
8214
+ }
8215
+ }, 0);
8216
+ map.set(resource.id, workedDays);
8217
+ }
8218
+ return map;
8219
+ }, [businessDays, resources, weekendPredicate]);
8015
8220
  const layout = (0, import_react14.useMemo)(
8016
8221
  () => layoutResourceTimelineItems(resources, {
8017
8222
  monthStart,
@@ -8059,6 +8264,8 @@ function ResourceTimelineChart({
8059
8264
  onAddResource?.({
8060
8265
  id: crypto.randomUUID(),
8061
8266
  name,
8267
+ type: "\u0414\u0440\u0443\u0433\u043E\u0435",
8268
+ scope: "Project",
8062
8269
  items: []
8063
8270
  });
8064
8271
  setIsCreatingResource(false);
@@ -8181,24 +8388,35 @@ function ResourceTimelineChart({
8181
8388
  "div",
8182
8389
  {
8183
8390
  className: "gantt-resourceTimeline-resourceColumn",
8184
- style: { width: `${rowHeaderWidth}px`, minWidth: `${rowHeaderWidth}px` },
8391
+ style: { width: `${effectiveRowHeaderWidth}px`, minWidth: `${effectiveRowHeaderWidth}px` },
8185
8392
  children: [
8186
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
8393
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
8187
8394
  "div",
8188
8395
  {
8189
8396
  className: "gantt-resourceTimeline-corner",
8190
- style: { height: `${headerHeight}px` }
8397
+ style: { height: `${headerHeight + 0.5}px` },
8398
+ children: [
8399
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "gantt-resourceTimeline-resourceHeaderCell gantt-resourceTimeline-resourceHeaderNumber", children: "#" }),
8400
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "gantt-resourceTimeline-resourceHeaderCell gantt-resourceTimeline-resourceHeaderName", children: "\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435" }),
8401
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "gantt-resourceTimeline-resourceHeaderCell", "aria-label": "\u0414\u043E\u0441\u0442\u0443\u043F\u043D\u043E\u0441\u0442\u044C" }),
8402
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "gantt-resourceTimeline-resourceHeaderCell", children: "\u041D\u0430\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F" }),
8403
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "gantt-resourceTimeline-resourceHeaderCell gantt-resourceTimeline-resourceHeaderActions", "aria-label": "\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u044F" })
8404
+ ]
8191
8405
  }
8192
8406
  ),
8193
- layout.rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
8407
+ layout.rows.map((row, rowIndex) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
8194
8408
  ResourceHeader,
8195
8409
  {
8196
8410
  resource: row.resource,
8197
8411
  resourceId: row.resourceId,
8412
+ rowIndex,
8198
8413
  conflictCount: row.conflictCount,
8414
+ workedDays: workedDaysByResourceId.get(row.resourceId) ?? 0,
8415
+ assignmentCount: row.resource.items.length,
8199
8416
  height: row.resourceRowHeight + DEFAULT_RESOURCE_ROW_GAP,
8200
8417
  paddingBottom: DEFAULT_RESOURCE_ROW_GAP,
8201
8418
  menuCommands: resourceMenuCommands,
8419
+ onResourceChange,
8202
8420
  onConflictBadgeClick: handleConflictBadgeClick
8203
8421
  },
8204
8422
  row.resourceId