@outbuild-company/schedule-core 1.35.2 → 1.36.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.cjs CHANGED
@@ -2306,24 +2306,37 @@ function toLevelWindow(input) {
2306
2306
  return { startLevel, depth: input.depth };
2307
2307
  }
2308
2308
  var INVALID_CRITERION = /* @__PURE__ */ Symbol("invalid-group-criterion");
2309
- function toSecondaryCriterion(input) {
2310
- const secondary = input.secondary;
2311
- if (secondary === void 0 || secondary === null) return null;
2312
- if (typeof secondary !== "object") return INVALID_CRITERION;
2313
- if (typeof secondary.attributeKey !== "string" || secondary.attributeKey.length === 0) {
2309
+ var MAX_NESTED_GROUP_CRITERIA = 3;
2310
+ function toNestedCriterion(input, usedKeys) {
2311
+ if (typeof input !== "object" || input === null) return INVALID_CRITERION;
2312
+ if (typeof input.attributeKey !== "string" || input.attributeKey.length === 0) {
2314
2313
  return INVALID_CRITERION;
2315
2314
  }
2316
- if (secondary.attributeKey === input.attributeKey) return INVALID_CRITERION;
2317
- const window2 = toLevelWindow(secondary);
2315
+ if (usedKeys.has(input.attributeKey)) return INVALID_CRITERION;
2316
+ const window2 = toLevelWindow(input);
2318
2317
  if (window2 === null) return INVALID_CRITERION;
2319
- if (!isValidDirection(secondary.direction)) return INVALID_CRITERION;
2318
+ if (!isValidDirection(input.direction)) return INVALID_CRITERION;
2320
2319
  return {
2321
- attributeKey: secondary.attributeKey,
2320
+ attributeKey: input.attributeKey,
2322
2321
  startLevel: window2.startLevel,
2323
2322
  depth: window2.depth,
2324
- direction: secondary.direction
2323
+ direction: input.direction
2325
2324
  };
2326
2325
  }
2326
+ function toNestedCriteria(input, primaryKey) {
2327
+ const rawNested = input.nested ?? (input.secondary == null ? [] : [input.secondary]);
2328
+ if (!Array.isArray(rawNested)) return INVALID_CRITERION;
2329
+ if (rawNested.length > MAX_NESTED_GROUP_CRITERIA) return INVALID_CRITERION;
2330
+ const usedKeys = /* @__PURE__ */ new Set([primaryKey]);
2331
+ const nested = [];
2332
+ for (const rawCriterion of rawNested) {
2333
+ const criterion = toNestedCriterion(rawCriterion, usedKeys);
2334
+ if (criterion === INVALID_CRITERION) return INVALID_CRITERION;
2335
+ usedKeys.add(criterion.attributeKey);
2336
+ nested.push(criterion);
2337
+ }
2338
+ return nested;
2339
+ }
2327
2340
  function toGroupState(input) {
2328
2341
  if (typeof input.attributeKey !== "string" || input.attributeKey.length === 0) {
2329
2342
  return null;
@@ -2337,8 +2350,8 @@ function toGroupState(input) {
2337
2350
  if (!Array.isArray(input.collapsedIds) || input.collapsedIds.some((id) => typeof id !== "string")) {
2338
2351
  return null;
2339
2352
  }
2340
- const secondary = toSecondaryCriterion(input);
2341
- if (secondary === INVALID_CRITERION) return null;
2353
+ const nested = toNestedCriteria(input, input.attributeKey);
2354
+ if (nested === INVALID_CRITERION) return null;
2342
2355
  return {
2343
2356
  attributeKey: input.attributeKey,
2344
2357
  startLevel: window2.startLevel,
@@ -2346,7 +2359,7 @@ function toGroupState(input) {
2346
2359
  direction: input.direction,
2347
2360
  includeWbs: input.includeWbs,
2348
2361
  collapsedIds: new Set(input.collapsedIds),
2349
- secondary
2362
+ nested
2350
2363
  };
2351
2364
  }
2352
2365
  function emptyViewChanges(action) {
@@ -13027,7 +13040,7 @@ function resolveDataDateProgressButton(activity, progress, progressChanges, deps
13027
13040
  );
13028
13041
  }
13029
13042
  function resolveDataDateFieldChanges(activity, changes, deps, column, confirmations, progressRouting, editedStart = null) {
13030
- const generic = routeGenericColumnEdit(
13043
+ const routed = routeGenericColumnEdit(
13031
13044
  activity,
13032
13045
  routeConstraintTypeEdit(activity, changes, column),
13033
13046
  deps,
@@ -13036,9 +13049,8 @@ function resolveDataDateFieldChanges(activity, changes, deps, column, confirmati
13036
13049
  progressRouting,
13037
13050
  editedStart
13038
13051
  );
13039
- if (generic === null) return rejected(REJECTION_REASON.INVALID_VALUE);
13040
- if ("accepted" in generic) return generic;
13041
- const routed = limitTransitionActuals(activity, generic, deps, column);
13052
+ if (routed === null) return rejected(REJECTION_REASON.INVALID_VALUE);
13053
+ if ("accepted" in routed) return routed;
13042
13054
  if (routed.dataDatePatch === void 0) return accepted(routed);
13043
13055
  if (activity.p6 === void 0 || deps.dataDateCapability === null) {
13044
13056
  return rejected(REJECTION_REASON.INVALID_VALUE);
@@ -13098,32 +13110,6 @@ function withMirroredProgress(activity, changes, next, deps, column) {
13098
13110
  }
13099
13111
  return { ...changes, patch: { ...changes.patch, progress: percent } };
13100
13112
  }
13101
- var EXECUTION_TRANSITION_COLUMNS = /* @__PURE__ */ new Set([
13102
- COLUMN.PROGRESS,
13103
- COLUMN.EXECUTION_STATUS,
13104
- COLUMN.PHYSICAL_PERCENT_COMPLETE
13105
- ]);
13106
- function limitTransitionActuals(activity, changes, deps, column) {
13107
- const dataDate = deps.dataDateSettings?.dataDate ?? null;
13108
- if (!EXECUTION_TRANSITION_COLUMNS.has(column) || dataDate === null || changes.dataDatePatch === void 0 || !hasActiveDataDate(deps.dataDateSettings, deps.dataDateEnabled)) {
13109
- return changes;
13110
- }
13111
- const calendar = deps.ctx.calendars.getCalendar(activity.calendarId);
13112
- const limit = calendar === null ? { start: dataDate, finish: dataDate } : completionActualsLimit(dataDate, calendar);
13113
- const recordedStart = activity.p6?.actualStart ?? null;
13114
- const floor = recordedStart !== null && recordedStart <= dataDate ? recordedStart : null;
13115
- const alternative = changes.confirmationAlternative;
13116
- return {
13117
- ...changes,
13118
- dataDatePatch: capActualDates(changes.dataDatePatch, floor, limit),
13119
- ...alternative === void 0 ? {} : {
13120
- confirmationAlternative: {
13121
- ...alternative,
13122
- effects: capActualDates(alternative.effects, floor, limit)
13123
- }
13124
- }
13125
- };
13126
- }
13127
13113
  function accepted(changes) {
13128
13114
  return { accepted: true, changes };
13129
13115
  }
@@ -25915,7 +25901,7 @@ function emitActivities(node, context) {
25915
25901
  });
25916
25902
  }
25917
25903
  }
25918
- function emitNode(node, childDirection, allowSecondary, context) {
25904
+ function emitNode(node, childDirection, nextNestedIndex, context) {
25919
25905
  const { group, rows } = context;
25920
25906
  rows.push({
25921
25907
  kind: VISUAL_ROW_KIND.GROUP,
@@ -25927,20 +25913,24 @@ function emitNode(node, childDirection, allowSecondary, context) {
25927
25913
  });
25928
25914
  if (group.collapsedIds.has(node.id)) return;
25929
25915
  for (const child of sortedChildNodes(node, childDirection)) {
25930
- emitNode(child, childDirection, allowSecondary, context);
25916
+ emitNode(child, childDirection, nextNestedIndex, context);
25931
25917
  }
25932
25918
  if (node.activities.length === 0) return;
25933
- const secondary = group.secondary;
25934
- if (allowSecondary && secondary != null && context.secondaryCatalog != null) {
25935
- const secondaryRoot = buildGroupTree(
25919
+ const nestedCriterion = group.nested[nextNestedIndex];
25920
+ const nestedCatalog = context.nestedCatalogs[nextNestedIndex] ?? null;
25921
+ if (nestedCriterion != null && nestedCatalog != null) {
25922
+ const nestedRoot = buildGroupTree(
25936
25923
  node.activities,
25937
- secondary,
25938
- context.secondaryCatalog,
25924
+ nestedCriterion,
25925
+ nestedCatalog,
25939
25926
  createNode(node.id, "", "", null, node.level, 0),
25940
25927
  true
25941
25928
  );
25942
- for (const child of sortedChildNodes(secondaryRoot, secondary.direction)) {
25943
- emitNode(child, secondary.direction, false, context);
25929
+ for (const child of sortedChildNodes(
25930
+ nestedRoot,
25931
+ nestedCriterion.direction
25932
+ )) {
25933
+ emitNode(child, nestedCriterion.direction, nextNestedIndex + 1, context);
25944
25934
  }
25945
25935
  return;
25946
25936
  }
@@ -25983,11 +25973,11 @@ function projectVisualRows(input) {
25983
25973
  comparator: input.comparator,
25984
25974
  orderMode: input.orderMode,
25985
25975
  wbsDepth: input.wbsDepth,
25986
- secondaryCatalog: input.secondaryCatalog,
25976
+ nestedCatalogs: input.nestedCatalogs,
25987
25977
  rows
25988
25978
  };
25989
25979
  for (const child of sortedChildNodes(root, group.direction)) {
25990
- emitNode(child, group.direction, true, context);
25980
+ emitNode(child, group.direction, 0, context);
25991
25981
  }
25992
25982
  return rows;
25993
25983
  }
@@ -26393,7 +26383,9 @@ var ScheduleState = class _ScheduleState {
26393
26383
  if (this._cache.visualRows) return this._cache.visualRows;
26394
26384
  const group = this._viewAttributes.getGroup();
26395
26385
  const catalog = group === null ? null : this._viewAttributes.getCatalog(group.attributeKey);
26396
- const secondaryCatalog = group?.secondary == null ? null : this._viewAttributes.getCatalog(group.secondary.attributeKey);
26386
+ const nestedCatalogs = group === null ? [] : group.nested.map(
26387
+ (criterion) => this._viewAttributes.getCatalog(criterion.attributeKey)
26388
+ );
26397
26389
  const activitiesInVisualOrder = [];
26398
26390
  for (const activityId of this.getVisualOrderIds()) {
26399
26391
  const activity = this.getActivity(activityId);
@@ -26406,7 +26398,7 @@ var ScheduleState = class _ScheduleState {
26406
26398
  hasChildren: (activityId) => this.hasChildren(activityId),
26407
26399
  group,
26408
26400
  catalog,
26409
- secondaryCatalog,
26401
+ nestedCatalogs,
26410
26402
  comparator: this.getOrderComparator(),
26411
26403
  orderMode: this.getOrderMode(),
26412
26404
  wbsDepth: this._viewAttributes.getWbsDepth()
@@ -31162,13 +31154,11 @@ function prepareDataDateSettingsUpdate(current, patch) {
31162
31154
  };
31163
31155
  }
31164
31156
  function prepareDataDateActivityUpdate(current, patch, primaryConstraint) {
31165
- const percentRouted = routeActivityPercentComplete(current, patch);
31157
+ const synchronized = synchronizeNotStartedDurations(current, patch);
31158
+ const percentRouted = routeActivityPercentComplete(current, synchronized);
31166
31159
  validateActivityInputPatch(percentRouted);
31167
31160
  validateSecondaryConstraint(percentRouted, primaryConstraint);
31168
- const routed = synchronizeNotStartedDurations(
31169
- current,
31170
- gatePhysicalPercentInput(current, percentRouted)
31171
- );
31161
+ const routed = gatePhysicalPercentInput(current, percentRouted);
31172
31162
  const next = cloneDomainValue({
31173
31163
  ...current,
31174
31164
  ...routed,
@@ -31181,7 +31171,7 @@ function prepareDataDateActivityUpdate(current, patch, primaryConstraint) {
31181
31171
  };
31182
31172
  }
31183
31173
  function synchronizeNotStartedDurations(current, patch) {
31184
- if (current.executionStatus !== P6_EXECUTION_STATUS.NOT_STARTED || patch.remainingDurationHours === void 0 || patch.originalDurationHours !== void 0) {
31174
+ if (current.executionStatus !== P6_EXECUTION_STATUS.NOT_STARTED || patch.actualStart != null || patch.activityPercentComplete !== void 0 || patch.remainingDurationHours === void 0 || patch.originalDurationHours !== void 0) {
31185
31175
  return patch;
31186
31176
  }
31187
31177
  return {
@@ -31226,7 +31216,7 @@ function routeActivityPercentComplete(current, patch) {
31226
31216
  case P6_PERCENT_COMPLETE_TYPE.DURATION:
31227
31217
  return {
31228
31218
  ...rest,
31229
- remainingDurationHours: current.originalDurationHours * (1 - activityPercentComplete / FULL_PERCENT)
31219
+ remainingDurationHours: (rest.originalDurationHours ?? current.originalDurationHours) * (1 - activityPercentComplete / FULL_PERCENT)
31230
31220
  };
31231
31221
  case P6_PERCENT_COMPLETE_TYPE.UNITS:
31232
31222
  throw new Error(