@outbuild-company/schedule-core 1.12.0 → 1.13.2

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.js CHANGED
@@ -1,4 +1,17 @@
1
+ // src/activity-types/constants.ts
2
+ var ACTIVITY_TYPE = {
3
+ TASK: "task",
4
+ PROJECT: "project",
5
+ MILESTONE: "milestone"
6
+ };
7
+ var ACTIVITY_TYPES = Object.values(ACTIVITY_TYPE);
8
+ function isActivityType(value) {
9
+ return ACTIVITY_TYPES.includes(value);
10
+ }
11
+
1
12
  // src/types.ts
13
+ var NOTIFICATION_TYPE = {
14
+ CONSTRAINT: "constraint"};
2
15
  var WORK_TIME_DIRECTION = {
3
16
  FUTURE: "future",
4
17
  PAST: "past"
@@ -23,6 +36,11 @@ var STATUS = {
23
36
  WAITING: "Waiting",
24
37
  DOING: "Doing"
25
38
  };
39
+ var ENTITY_CHANGE_KIND = {
40
+ CREATED: "created",
41
+ UPDATED: "updated",
42
+ DELETED: "deleted"
43
+ };
26
44
 
27
45
  // src/constraints/index.ts
28
46
  var CONSTRAINT_TYPE = {
@@ -36,12 +54,12 @@ var CONSTRAINT_TYPE = {
36
54
  MFO: "mfo"
37
55
  };
38
56
  var VIOLATION_RULES = {
39
- mso: () => true,
40
- mfo: () => true,
41
- snlt: (constraint, projected) => constraint < projected,
42
- snet: (constraint, projected) => constraint > projected,
43
- fnlt: (constraint, projected) => constraint < projected,
44
- fnet: (constraint, projected) => constraint > projected
57
+ [CONSTRAINT_TYPE.MSO]: () => true,
58
+ [CONSTRAINT_TYPE.MFO]: () => true,
59
+ [CONSTRAINT_TYPE.SNLT]: (constraint, projected) => constraint < projected,
60
+ [CONSTRAINT_TYPE.SNET]: (constraint, projected) => constraint > projected,
61
+ [CONSTRAINT_TYPE.FNLT]: (constraint, projected) => constraint < projected,
62
+ [CONSTRAINT_TYPE.FNET]: (constraint, projected) => constraint > projected
45
63
  };
46
64
  function checkConstraintViolation(constraintType, constraintDate, projectedDate) {
47
65
  if (!constraintDate) return { violated: false };
@@ -53,16 +71,16 @@ function checkConstraintViolation(constraintType, constraintDate, projectedDate)
53
71
  return { violated: false };
54
72
  }
55
73
  var START_BASED_CONSTRAINTS = /* @__PURE__ */ new Set([
56
- "mso",
57
- "snet",
58
- "snlt"
74
+ CONSTRAINT_TYPE.MSO,
75
+ CONSTRAINT_TYPE.SNET,
76
+ CONSTRAINT_TYPE.SNLT
59
77
  ]);
60
78
  function pickProjectedDateForConstraint(constraintType, projectedStart, projectedEnd) {
61
79
  return START_BASED_CONSTRAINTS.has(constraintType) ? projectedStart : projectedEnd;
62
80
  }
63
81
  function buildConstraintNotification(constraintType, constraintDate, projectedDate) {
64
82
  return {
65
- type: "constraint",
83
+ type: NOTIFICATION_TYPE.CONSTRAINT,
66
84
  messageKey: "constraint_violation",
67
85
  data: {
68
86
  constraintType,
@@ -72,12 +90,30 @@ function buildConstraintNotification(constraintType, constraintDate, projectedDa
72
90
  };
73
91
  }
74
92
  var CONSTRAINT_CASES = {
75
- snet: { startOfDay: true, direction: WORK_TIME_DIRECTION.FUTURE },
76
- snlt: { startOfDay: true, direction: WORK_TIME_DIRECTION.PAST },
77
- fnet: { startOfDay: false, direction: WORK_TIME_DIRECTION.FUTURE },
78
- fnlt: { startOfDay: false, direction: WORK_TIME_DIRECTION.PAST },
79
- mso: { startOfDay: true, direction: WORK_TIME_DIRECTION.FUTURE },
80
- mfo: { startOfDay: false, direction: WORK_TIME_DIRECTION.PAST }
93
+ [CONSTRAINT_TYPE.SNET]: {
94
+ startOfDay: true,
95
+ direction: WORK_TIME_DIRECTION.FUTURE
96
+ },
97
+ [CONSTRAINT_TYPE.SNLT]: {
98
+ startOfDay: true,
99
+ direction: WORK_TIME_DIRECTION.PAST
100
+ },
101
+ [CONSTRAINT_TYPE.FNET]: {
102
+ startOfDay: false,
103
+ direction: WORK_TIME_DIRECTION.FUTURE
104
+ },
105
+ [CONSTRAINT_TYPE.FNLT]: {
106
+ startOfDay: false,
107
+ direction: WORK_TIME_DIRECTION.PAST
108
+ },
109
+ [CONSTRAINT_TYPE.MSO]: {
110
+ startOfDay: true,
111
+ direction: WORK_TIME_DIRECTION.FUTURE
112
+ },
113
+ [CONSTRAINT_TYPE.MFO]: {
114
+ startOfDay: false,
115
+ direction: WORK_TIME_DIRECTION.PAST
116
+ }
81
117
  };
82
118
  var startOfUtcDay = (d) => new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()));
83
119
  var addUtcDays = (d, n) => new Date(d.getTime() + n * 864e5);
@@ -129,7 +165,9 @@ function computeConstraintBounds(activity, adapter) {
129
165
  latestEnd: null
130
166
  };
131
167
  const type = activity.constraintType;
132
- if (!type || type === "asap" || type === "alap") return empty;
168
+ if (!type || type === CONSTRAINT_TYPE.ASAP || type === CONSTRAINT_TYPE.ALAP) {
169
+ return empty;
170
+ }
133
171
  const constraintDate = getEffectiveConstraintDate(activity, adapter);
134
172
  if (!constraintDate) return empty;
135
173
  const endFromStart = (start) => adapter.calculateEndDate({
@@ -143,35 +181,35 @@ function computeConstraintBounds(activity, adapter) {
143
181
  task: activity
144
182
  });
145
183
  switch (type) {
146
- case "snet":
184
+ case CONSTRAINT_TYPE.SNET:
147
185
  return {
148
186
  earliestStart: constraintDate,
149
187
  latestStart: null,
150
188
  earliestEnd: endFromStart(constraintDate),
151
189
  latestEnd: null
152
190
  };
153
- case "snlt":
191
+ case CONSTRAINT_TYPE.SNLT:
154
192
  return {
155
193
  earliestStart: null,
156
194
  latestStart: constraintDate,
157
195
  earliestEnd: null,
158
196
  latestEnd: endFromStart(constraintDate)
159
197
  };
160
- case "fnet":
198
+ case CONSTRAINT_TYPE.FNET:
161
199
  return {
162
200
  earliestStart: startFromEnd(constraintDate),
163
201
  latestStart: null,
164
202
  earliestEnd: constraintDate,
165
203
  latestEnd: null
166
204
  };
167
- case "fnlt":
205
+ case CONSTRAINT_TYPE.FNLT:
168
206
  return {
169
207
  earliestStart: null,
170
208
  latestStart: startFromEnd(constraintDate),
171
209
  earliestEnd: null,
172
210
  latestEnd: constraintDate
173
211
  };
174
- case "mso": {
212
+ case CONSTRAINT_TYPE.MSO: {
175
213
  const end = endFromStart(constraintDate);
176
214
  return {
177
215
  earliestStart: constraintDate,
@@ -180,7 +218,7 @@ function computeConstraintBounds(activity, adapter) {
180
218
  latestEnd: end
181
219
  };
182
220
  }
183
- case "mfo": {
221
+ case CONSTRAINT_TYPE.MFO: {
184
222
  const start = startFromEnd(constraintDate);
185
223
  return {
186
224
  earliestStart: start,
@@ -208,13 +246,17 @@ function clampStartToBounds(candidate, bounds) {
208
246
  return candidate;
209
247
  }
210
248
 
211
- // src/autoscheduler/types.ts
249
+ // src/autoscheduler/links/constants.ts
212
250
  var LINK_TYPE = {
213
251
  FINISH_TO_START: "0",
214
252
  START_TO_START: "1",
215
253
  FINISH_TO_FINISH: "2",
216
254
  START_TO_FINISH: "3"
217
255
  };
256
+ var LINK_TYPES = Object.values(LINK_TYPE);
257
+ function isLinkType(value) {
258
+ return LINK_TYPES.includes(value);
259
+ }
218
260
 
219
261
  // src/constants/columns.ts
220
262
  var EDITABLE = {
@@ -300,6 +342,7 @@ var DISPATCH_ACTION_KIND = {
300
342
  ACTIVITY_INDENT: "activity-indent",
301
343
  ACTIVITY_OUTDENT: "activity-outdent",
302
344
  ACTIVITY_SET_PROGRESS: "activity-set-progress",
345
+ ACTIVITY_LOOKAHEAD_CONVERT: "activity-lookahead-convert",
303
346
  SELECTION_TOGGLE: "selection-toggle",
304
347
  SELECTION_REPLACE: "selection-replace",
305
348
  VISIBILITY_SET: "visibility-set",
@@ -382,14 +425,14 @@ function activityEditToColumnEdit(activityId, edit) {
382
425
  }
383
426
 
384
427
  // src/api/schedule-api.ts
385
- var LINK_TYPES = {
428
+ var LINK_TYPES2 = {
386
429
  [LINK_RELATIONSHIP.FINISH_TO_START]: LINK_TYPE.FINISH_TO_START,
387
430
  [LINK_RELATIONSHIP.START_TO_START]: LINK_TYPE.START_TO_START,
388
431
  [LINK_RELATIONSHIP.FINISH_TO_FINISH]: LINK_TYPE.FINISH_TO_FINISH,
389
432
  [LINK_RELATIONSHIP.START_TO_FINISH]: LINK_TYPE.START_TO_FINISH
390
433
  };
391
434
  function linkType(relationship) {
392
- return LINK_TYPES[relationship];
435
+ return LINK_TYPES2[relationship];
393
436
  }
394
437
  function batchLink(operation) {
395
438
  if (operation.kind === LINK_BATCH_OPERATION_KIND.CREATE) {
@@ -491,6 +534,8 @@ function createActivitiesApi(engine) {
491
534
  { ...input, kind: DISPATCH_ACTION_KIND.ACTIVITY_MOVE },
492
535
  options
493
536
  ),
537
+ planLookaheadConversion: (input) => engine.planLookaheadConversion(input),
538
+ applyLookaheadConversion: (input) => engine.applyLookaheadConversion(input),
494
539
  indent: (activityIds, context = {}) => engine.dispatch({
495
540
  ...context,
496
541
  kind: DISPATCH_ACTION_KIND.ACTIVITY_INDENT,
@@ -669,6 +714,7 @@ function createScheduleNamespaces(engine) {
669
714
  diagnostics: {
670
715
  auditEffectiveGraph: () => engine.auditEffectiveGraph(),
671
716
  revision: () => engine.getScheduleRevision(),
717
+ stateRevision: () => engine.getStateRevision(),
672
718
  canonicalDigest: () => engine.getCanonicalDigest()
673
719
  }
674
720
  };
@@ -820,6 +866,7 @@ var REJECTION_REASON = {
820
866
  OUTDENT_ROOT_LEVEL_NOT_EDITABLE: "outdent_root_level_not_editable",
821
867
  HIERARCHY_CYCLE: "hierarchy_cycle",
822
868
  SANDBOX_PERSISTENCE_FORBIDDEN: "sandbox_persistence_forbidden",
869
+ STALE_STATE_REVISION: "stale-state-revision",
823
870
  INVALID_PROGRESS_VALUE: "invalid_progress_value_must_be_0_or_100"
824
871
  };
825
872
 
@@ -924,11 +971,6 @@ function dispatchVisibilitySet(action, deps) {
924
971
  }
925
972
 
926
973
  // src/autoscheduler/constants.ts
927
- var ACTIVITY_TYPE = {
928
- TASK: "task",
929
- PROJECT: "project",
930
- MILESTONE: "milestone"
931
- };
932
974
  var TIMING = {
933
975
  YIELD_SLICE_MS: 8
934
976
  };
@@ -1971,53 +2013,55 @@ function filterTopoOrder(order, scopedIds) {
1971
2013
  }
1972
2014
 
1973
2015
  // src/activity-types/behavior.ts
2016
+ var PONDERATOR_WEIGHT = {
2017
+ OWN_BASELINE: "own-baseline",
2018
+ RECURSIVE_LEAF_SUM: "recursive-leaf-sum",
2019
+ ZERO: "zero"
2020
+ };
1974
2021
  var ACTIVITY_TYPE_BEHAVIOR = {
1975
- project: {
2022
+ [ACTIVITY_TYPE.PROJECT]: {
1976
2023
  alwaysSummary: true,
1977
2024
  holdsConstraint: false,
1978
2025
  carriesCustomId: false,
1979
2026
  forcedDuration: null,
1980
- ponderatorWeight: "recursive-leaf-sum",
2027
+ ponderatorWeight: PONDERATOR_WEIGHT.RECURSIVE_LEAF_SUM,
1981
2028
  promotesToProjectOnFirstChild: false
1982
2029
  },
1983
- task: {
2030
+ [ACTIVITY_TYPE.TASK]: {
1984
2031
  alwaysSummary: false,
1985
2032
  holdsConstraint: true,
1986
2033
  carriesCustomId: true,
1987
2034
  forcedDuration: null,
1988
- ponderatorWeight: "own-baseline",
2035
+ ponderatorWeight: PONDERATOR_WEIGHT.OWN_BASELINE,
1989
2036
  promotesToProjectOnFirstChild: true
1990
2037
  },
1991
- milestone: {
2038
+ [ACTIVITY_TYPE.MILESTONE]: {
1992
2039
  alwaysSummary: false,
1993
2040
  holdsConstraint: true,
1994
2041
  carriesCustomId: true,
1995
2042
  forcedDuration: 0,
1996
- ponderatorWeight: "zero",
2043
+ ponderatorWeight: PONDERATOR_WEIGHT.ZERO,
1997
2044
  promotesToProjectOnFirstChild: true
1998
2045
  }
1999
2046
  };
2000
2047
 
2001
2048
  // src/activity-types/predicates.ts
2002
- function isActivityType(value) {
2003
- return value === "project" || value === "task" || value === "milestone";
2004
- }
2005
2049
  function isSummary(type, hasChildren) {
2006
2050
  return hasChildren || isActivityType(type) && ACTIVITY_TYPE_BEHAVIOR[type].alwaysSummary;
2007
2051
  }
2008
2052
  function isMilestoneType(type) {
2009
- return type === "milestone";
2053
+ return type === ACTIVITY_TYPE.MILESTONE;
2010
2054
  }
2011
2055
  function isPromotableLeafType(type) {
2012
2056
  return isActivityType(type) && ACTIVITY_TYPE_BEHAVIOR[type].promotesToProjectOnFirstChild;
2013
2057
  }
2014
2058
 
2015
2059
  // src/activity-types/transitions.ts
2016
- var PROMOTION_TARGET_TYPE = "project";
2017
- var DEMOTION_TARGET_TYPE = "task";
2060
+ var PROMOTION_TARGET_TYPE = ACTIVITY_TYPE.PROJECT;
2061
+ var DEMOTION_TARGET_TYPE = ACTIVITY_TYPE.TASK;
2018
2062
  function typeForNewDuration(currentDuration, newDuration) {
2019
- if (newDuration === 0) return "milestone";
2020
- if (currentDuration === 0 && newDuration > 0) return "task";
2063
+ if (newDuration === 0) return ACTIVITY_TYPE.MILESTONE;
2064
+ if (currentDuration === 0 && newDuration > 0) return ACTIVITY_TYPE.TASK;
2021
2065
  return null;
2022
2066
  }
2023
2067
 
@@ -2603,7 +2647,7 @@ function processConstraints(activityIds, adapter, plans) {
2603
2647
  startDate: activity.startDate,
2604
2648
  endDate: activity.endDate,
2605
2649
  drivingLinkId: null,
2606
- kind: "asap",
2650
+ kind: CONSTRAINT_TYPE.ASAP,
2607
2651
  conflict: false,
2608
2652
  earliestStart: bounds.earliestStart,
2609
2653
  latestStart: bounds.latestStart,
@@ -2755,7 +2799,7 @@ async function asapPass(orderedIds, links, adapter, options, isCurrent, plans) {
2755
2799
  startDate: activity.startDate,
2756
2800
  endDate: activity.endDate,
2757
2801
  drivingLinkId: null,
2758
- kind: "asap",
2802
+ kind: CONSTRAINT_TYPE.ASAP,
2759
2803
  conflict: false
2760
2804
  };
2761
2805
  const hasConstraintBounds = plan.earliestStart || plan.latestStart || plan.earliestEnd || plan.latestEnd;
@@ -2959,13 +3003,13 @@ async function alapPass(reversedIds, links, asapPlans, adapter, _options, isCurr
2959
3003
  startDate: snappedStart,
2960
3004
  endDate: snappedEnd,
2961
3005
  drivingLinkId: null,
2962
- kind: "alap",
3006
+ kind: CONSTRAINT_TYPE.ALAP,
2963
3007
  conflict: false
2964
3008
  };
2965
3009
  plan.startDate = snappedStart;
2966
3010
  plan.endDate = snappedEnd;
2967
3011
  plan.drivingLinkId = null;
2968
- plan.kind = "alap";
3012
+ plan.kind = CONSTRAINT_TYPE.ALAP;
2969
3013
  const predecessorFloor = plan.earliestSchedulingStart ?? null;
2970
3014
  plan.earliestSchedulingStart = null;
2971
3015
  plan.earliestSchedulingEnd = null;
@@ -2993,7 +3037,7 @@ var noopReporter = {
2993
3037
  // src/internal/state/calendar-duration.ts
2994
3038
  var CALENDAR_DAY_MS = 864e5;
2995
3039
  function computeCalendarDuration(activity) {
2996
- if (activity.type === "milestone") return 0;
3040
+ if (activity.type === ACTIVITY_TYPE.MILESTONE) return 0;
2997
3041
  const start = activity.startDate?.getTime();
2998
3042
  const end = activity.endDate?.getTime();
2999
3043
  if (start == null || end == null || Number.isNaN(start) || Number.isNaN(end)) {
@@ -3300,8 +3344,12 @@ var ReparentedPort = class {
3300
3344
 
3301
3345
  // src/internal/dependency-graph/effective-graph-validation.ts
3302
3346
  function validateTopologyCommit(input) {
3303
- const { port, currentLinks, proposedLinks, proposal } = input;
3304
- const proposedEdges = projectEffectiveEdges(port, proposedLinks, proposal);
3347
+ const { port, proposedPort, currentLinks, proposedLinks, proposal } = input;
3348
+ const proposedEdges = projectEffectiveEdges(
3349
+ proposedPort ?? port,
3350
+ proposedLinks,
3351
+ proposal
3352
+ );
3305
3353
  if (!hasDirectedCycle(proposedEdges)) return { ok: true };
3306
3354
  const currentEdges = projectEffectiveEdges(port, currentLinks);
3307
3355
  const corruptBefore = corruptActivityIds(currentEdges);
@@ -3511,19 +3559,25 @@ function defaultNewLinkId() {
3511
3559
  }
3512
3560
 
3513
3561
  // src/autoscheduler/links/link-display.ts
3562
+ var LINK_CODE = {
3563
+ FINISH_TO_START: "fs",
3564
+ START_TO_START: "ss",
3565
+ FINISH_TO_FINISH: "ff",
3566
+ START_TO_FINISH: "sf"
3567
+ };
3514
3568
  var LINK_TYPE_CODE = {
3515
- [LINK_TYPE.FINISH_TO_START]: "fs",
3516
- [LINK_TYPE.START_TO_START]: "ss",
3517
- [LINK_TYPE.FINISH_TO_FINISH]: "ff",
3518
- [LINK_TYPE.START_TO_FINISH]: "sf"
3569
+ [LINK_TYPE.FINISH_TO_START]: LINK_CODE.FINISH_TO_START,
3570
+ [LINK_TYPE.START_TO_START]: LINK_CODE.START_TO_START,
3571
+ [LINK_TYPE.FINISH_TO_FINISH]: LINK_CODE.FINISH_TO_FINISH,
3572
+ [LINK_TYPE.START_TO_FINISH]: LINK_CODE.START_TO_FINISH
3519
3573
  };
3520
3574
  var LINK_CODE_TO_TYPE = {
3521
- fs: LINK_TYPE.FINISH_TO_START,
3522
- ss: LINK_TYPE.START_TO_START,
3523
- ff: LINK_TYPE.FINISH_TO_FINISH,
3524
- sf: LINK_TYPE.START_TO_FINISH
3575
+ [LINK_CODE.FINISH_TO_START]: LINK_TYPE.FINISH_TO_START,
3576
+ [LINK_CODE.START_TO_START]: LINK_TYPE.START_TO_START,
3577
+ [LINK_CODE.FINISH_TO_FINISH]: LINK_TYPE.FINISH_TO_FINISH,
3578
+ [LINK_CODE.START_TO_FINISH]: LINK_TYPE.START_TO_FINISH
3525
3579
  };
3526
- var DEFAULT_LINK_CODE = "fs";
3580
+ var DEFAULT_LINK_CODE = LINK_CODE.FINISH_TO_START;
3527
3581
  function parseLinkTypeCode(raw) {
3528
3582
  if (raw in LINK_CODE_TO_TYPE) {
3529
3583
  return LINK_CODE_TO_TYPE[raw];
@@ -3531,33 +3585,53 @@ function parseLinkTypeCode(raw) {
3531
3585
  return void 0;
3532
3586
  }
3533
3587
  var LINK_ENTRY_SEPARATOR = ";";
3534
- var ENTRY_RE = /^(\d+)(fs|ss|ff|sf)?(?:([+-]?)(\d+(?:\.\d+)?)d?)?$/i;
3588
+ var LAG_UNIT = {
3589
+ DAY: "d",
3590
+ WEEK: "w",
3591
+ WEEK_DHTMLX: "wk",
3592
+ MONTH: "m",
3593
+ MONTH_DHTMLX: "mon",
3594
+ YEAR: "y"
3595
+ };
3596
+ var ENTRY_RE = /^(\d+)(fs|ss|ff|sf)?(?:([+-]?)(\d+(?:\.\d+)?)(wk|w|mon|m|d|y)?)?$/i;
3535
3597
 
3536
3598
  // src/autoscheduler/links/parse-predecessor-string.ts
3537
- function parsePredecessorString(input) {
3599
+ var DEFAULT_WORKING_DAYS_PER_WEEK = 5;
3600
+ var DAYS_PER_MONTH = 30;
3601
+ var DAYS_PER_YEAR = 365;
3602
+ var FIXED_UNIT_DAYS = {
3603
+ [LAG_UNIT.DAY]: 1,
3604
+ [LAG_UNIT.MONTH]: DAYS_PER_MONTH,
3605
+ [LAG_UNIT.MONTH_DHTMLX]: DAYS_PER_MONTH,
3606
+ [LAG_UNIT.YEAR]: DAYS_PER_YEAR
3607
+ };
3608
+ function parsePredecessorString(input, options = {}) {
3538
3609
  const specs = [];
3539
3610
  const errors = [];
3611
+ const daysPerWeek = options.daysPerWeek !== void 0 && Number.isFinite(options.daysPerWeek) && options.daysPerWeek > 0 ? options.daysPerWeek : DEFAULT_WORKING_DAYS_PER_WEEK;
3540
3612
  const trimmed = input.replace(/\s+/g, "");
3541
3613
  if (trimmed.length === 0) return { specs, errors };
3542
3614
  for (const raw of trimmed.split(LINK_ENTRY_SEPARATOR)) {
3543
3615
  if (raw.length === 0) continue;
3544
- const spec = parseEntry(raw);
3616
+ const spec = parseEntry(raw, daysPerWeek);
3545
3617
  if (spec) specs.push(spec);
3546
3618
  else errors.push(raw);
3547
3619
  }
3548
3620
  return { specs, errors };
3549
3621
  }
3550
- function parseEntry(entry) {
3622
+ function parseEntry(entry, daysPerWeek) {
3551
3623
  const lower = entry.toLowerCase();
3552
3624
  const match = ENTRY_RE.exec(lower);
3553
3625
  if (!match) return null;
3554
- const [, correlativeId, typeStr, sign, magnitude] = match;
3626
+ const [, correlativeId, typeStr, sign, magnitude, unit] = match;
3555
3627
  const type = typeStr ? LINK_CODE_TO_TYPE[typeStr] : LINK_CODE_TO_TYPE[DEFAULT_LINK_CODE];
3556
3628
  let lag = 0;
3557
3629
  if (magnitude !== void 0) {
3558
3630
  const value = Number(magnitude);
3559
3631
  if (Number.isNaN(value)) return null;
3560
- lag = sign === "-" ? -value : value;
3632
+ const unitDays = unit === LAG_UNIT.WEEK || unit === LAG_UNIT.WEEK_DHTMLX ? daysPerWeek : FIXED_UNIT_DAYS[unit ?? LAG_UNIT.DAY];
3633
+ const days = value * unitDays;
3634
+ lag = sign === "-" ? -days : days;
3561
3635
  }
3562
3636
  return {
3563
3637
  correlativeId,
@@ -3589,20 +3663,24 @@ function diffLinks(input) {
3589
3663
  const operations = [];
3590
3664
  for (const [key, link] of currentByKey) {
3591
3665
  if (!desired.has(key)) {
3592
- operations.push({ kind: "delete", linkId: link.id });
3666
+ operations.push({ kind: LINK_OPERATION_KIND.DELETE, linkId: link.id });
3593
3667
  }
3594
3668
  }
3595
3669
  for (const [key, spec] of desired) {
3596
3670
  const existing = currentByKey.get(key);
3597
3671
  if (!existing) continue;
3598
3672
  if (existing.lag !== spec.lag) {
3599
- operations.push({ kind: "update", linkId: existing.id, lag: spec.lag });
3673
+ operations.push({
3674
+ kind: LINK_OPERATION_KIND.UPDATE,
3675
+ linkId: existing.id,
3676
+ lag: spec.lag
3677
+ });
3600
3678
  }
3601
3679
  }
3602
3680
  for (const [key, spec] of desired) {
3603
3681
  if (currentByKey.has(key)) continue;
3604
3682
  operations.push({
3605
- kind: "create",
3683
+ kind: LINK_OPERATION_KIND.CREATE,
3606
3684
  source: spec.source,
3607
3685
  target: targetActivityId,
3608
3686
  type: spec.type,
@@ -3636,20 +3714,24 @@ function diffOutgoingLinks(input) {
3636
3714
  const operations = [];
3637
3715
  for (const [key, link] of currentByKey) {
3638
3716
  if (!desired.has(key)) {
3639
- operations.push({ kind: "delete", linkId: link.id });
3717
+ operations.push({ kind: LINK_OPERATION_KIND.DELETE, linkId: link.id });
3640
3718
  }
3641
3719
  }
3642
3720
  for (const [key, spec] of desired) {
3643
3721
  const existing = currentByKey.get(key);
3644
3722
  if (!existing) continue;
3645
3723
  if (existing.lag !== spec.lag) {
3646
- operations.push({ kind: "update", linkId: existing.id, lag: spec.lag });
3724
+ operations.push({
3725
+ kind: LINK_OPERATION_KIND.UPDATE,
3726
+ linkId: existing.id,
3727
+ lag: spec.lag
3728
+ });
3647
3729
  }
3648
3730
  }
3649
3731
  for (const [key, spec] of desired) {
3650
3732
  if (currentByKey.has(key)) continue;
3651
3733
  operations.push({
3652
- kind: "create",
3734
+ kind: LINK_OPERATION_KIND.CREATE,
3653
3735
  source: sourceActivityId,
3654
3736
  target: spec.target,
3655
3737
  type: spec.type,
@@ -3693,13 +3775,13 @@ var currentImpl = {
3693
3775
  // src/autoscheduler/date-math/types.ts
3694
3776
  function pickDatesForLinkType(source, target, linkType2) {
3695
3777
  switch (linkType2) {
3696
- case "0":
3778
+ case LINK_TYPE.FINISH_TO_START:
3697
3779
  return { sourceDate: source.endDate, targetDate: target.startDate };
3698
- case "1":
3780
+ case LINK_TYPE.START_TO_START:
3699
3781
  return { sourceDate: source.startDate, targetDate: target.startDate };
3700
- case "2":
3782
+ case LINK_TYPE.FINISH_TO_FINISH:
3701
3783
  return { sourceDate: source.endDate, targetDate: target.endDate };
3702
- case "3":
3784
+ case LINK_TYPE.START_TO_FINISH:
3703
3785
  return { sourceDate: source.startDate, targetDate: target.endDate };
3704
3786
  }
3705
3787
  }
@@ -3832,7 +3914,7 @@ var AutoScheduler = class {
3832
3914
  };
3833
3915
  } catch (error) {
3834
3916
  this.reporter.error("[AutoScheduler] Error during scheduling", error);
3835
- return emptyResult;
3917
+ throw error;
3836
3918
  }
3837
3919
  }
3838
3920
  };
@@ -3912,7 +3994,7 @@ function adjustLinkLagOnTaskMove(targetId, adapter, preEditTarget) {
3912
3994
  if (!link) continue;
3913
3995
  const source = adapter.getActivity(link.source);
3914
3996
  if (!source) continue;
3915
- if (source.constraintType === "alap") continue;
3997
+ if (source.constraintType === CONSTRAINT_TYPE.ALAP) continue;
3916
3998
  const isEndAnchoredIntoMilestone = isMilestoneType(target.type) && (link.type === LINK_TYPE.START_TO_FINISH || link.type === LINK_TYPE.FINISH_TO_FINISH);
3917
3999
  if (isEndAnchoredIntoMilestone) continue;
3918
4000
  const { sourceDate, targetDate } = pickDatesForLinkType(
@@ -3926,7 +4008,10 @@ function adjustLinkLagOnTaskMove(targetId, adapter, preEditTarget) {
3926
4008
  calendarApi
3927
4009
  );
3928
4010
  if (newLag === link.lag) continue;
3929
- applyLinkUpdate({ linkId: link.id, lag: newLag }, adapter);
4011
+ applyLinkUpdate(
4012
+ { kind: LINK_OPERATION_KIND.UPDATE, linkId: link.id, lag: newLag },
4013
+ adapter
4014
+ );
3930
4015
  }
3931
4016
  }
3932
4017
 
@@ -4038,15 +4123,19 @@ function computeLeafRealWork(workHours, progress) {
4038
4123
  }
4039
4124
 
4040
4125
  // src/propagations/upward/parent-bounds.ts
4126
+ var PARENT_PROGRESS_MODE = {
4127
+ SKIP: "skip",
4128
+ FREEZE_WITHOUT_CONTRIBUTION: "freeze-when-no-contribution"
4129
+ };
4041
4130
  async function updateParentBoundsFromChildren(adapter, dirtyIds, recomputeProgress = true, options = {}) {
4042
4131
  const parents = dirtyIds ? findAncestorsOfDirty(adapter, dirtyIds) : findAllParents(adapter);
4043
- const progressMode = recomputeProgress ? options.progressMode ?? "freeze-when-no-contribution" : "skip";
4132
+ const progressMode = recomputeProgress ? options.progressMode ?? PARENT_PROGRESS_MODE.FREEZE_WITHOUT_CONTRIBUTION : PARENT_PROGRESS_MODE.SKIP;
4044
4133
  await recomputeParentsCooperatively(parents, adapter, progressMode, {
4045
4134
  recomputeRealWork: options.recomputeRealWork ?? false
4046
4135
  });
4047
4136
  }
4048
4137
  function recomputeSingleParentDisplayBounds(parentId, adapter) {
4049
- recomputeParentFromChildren(parentId, adapter, "skip");
4138
+ recomputeParentFromChildren(parentId, adapter, PARENT_PROGRESS_MODE.SKIP);
4050
4139
  }
4051
4140
  async function recomputeParentsCooperatively(parents, adapter, progressMode, options = {
4052
4141
  recomputeRealWork: false
@@ -4132,7 +4221,7 @@ function aggregateChildren(childrenIds, adapter, includeRealWork) {
4132
4221
  }
4133
4222
  return { minStart, maxEnd, realWorkSum, weightedChildren };
4134
4223
  }
4135
- function recomputeParentFromChildren(parentId, adapter, progressMode = "freeze-when-no-contribution", recomputeRealWork = false) {
4224
+ function recomputeParentFromChildren(parentId, adapter, progressMode = PARENT_PROGRESS_MODE.FREEZE_WITHOUT_CONTRIBUTION, recomputeRealWork = false) {
4136
4225
  const parent = adapter.getActivity(parentId);
4137
4226
  if (!parent) return;
4138
4227
  const childrenIds = adapter.getChildren(parentId);
@@ -4147,7 +4236,7 @@ function recomputeParentFromChildren(parentId, adapter, progressMode = "freeze-w
4147
4236
  adapter.setActivityField(parentId, "startDate", newStart);
4148
4237
  adapter.setActivityField(parentId, "endDate", newEnd);
4149
4238
  adapter.setActivityField(parentId, "durationHours", durationHours);
4150
- if (progressMode !== "skip") {
4239
+ if (progressMode !== PARENT_PROGRESS_MODE.SKIP) {
4151
4240
  applyWeightedProgressRollup(parentId, aggregate.weightedChildren, adapter);
4152
4241
  }
4153
4242
  if (recomputeRealWork) {
@@ -4254,6 +4343,21 @@ function fieldChanges(patch, options = {}) {
4254
4343
  };
4255
4344
  }
4256
4345
 
4346
+ // src/columns/shared/tracking-events.ts
4347
+ var COLUMN_TRACK_EVENT = {
4348
+ PROGRESS_ENTRY: "activity_progress_entry",
4349
+ PROGRESS_UPDATE_RADIO_BUTTON: "activity_progress_update_radio_button",
4350
+ DURATION_ENTRY: "activity_duration_entry",
4351
+ START_DATE_ENTRY: "activity_start_date_entry",
4352
+ END_DATE_ENTRY: "activity_end_date_entry",
4353
+ NAME_ENTRY: "activity_name_entry",
4354
+ DESCRIPTION_ENTRY: "activity_description_entry",
4355
+ CALENDAR_ASSIGNMENT: "activity_calendar_assignment",
4356
+ COST_BUDGETED_ENTRY: "activity_cost_budgeted_entry",
4357
+ COST_SPENT_ENTRY: "activity_cost_spent_entry",
4358
+ LABOR_HOURS_BUDGETED_ENTRY: "activity_labor_hours_budgeted_entry"
4359
+ };
4360
+
4257
4361
  // src/columns/text/text-pipeline.ts
4258
4362
  var textPipeline = {
4259
4363
  targetField: "name",
@@ -4273,7 +4377,7 @@ var textPipeline = {
4273
4377
  postProcessors: []
4274
4378
  });
4275
4379
  },
4276
- trackEvent: "activity_name_entry"
4380
+ trackEvent: COLUMN_TRACK_EVENT.NAME_ENTRY
4277
4381
  };
4278
4382
 
4279
4383
  // src/columns/description/description-pipeline.ts
@@ -4295,7 +4399,7 @@ var descriptionPipeline = {
4295
4399
  { autoSchedule: false, postProcessors: [] }
4296
4400
  );
4297
4401
  },
4298
- trackEvent: "activity_description_entry"
4402
+ trackEvent: COLUMN_TRACK_EVENT.DESCRIPTION_ENTRY
4299
4403
  };
4300
4404
 
4301
4405
  // src/columns/shared/activity-predicates.ts
@@ -4327,6 +4431,7 @@ var setEndDate = (value) => ({
4327
4431
  });
4328
4432
 
4329
4433
  // src/columns/shared/date-normalize.ts
4434
+ var UTC_TIME_ZONE = "UTC";
4330
4435
  function truncateToUtcDay(date2, tz) {
4331
4436
  {
4332
4437
  const parts = new Intl.DateTimeFormat("en-CA", {
@@ -4347,11 +4452,11 @@ function endOfLocalDay(date2, tz) {
4347
4452
  }
4348
4453
  }
4349
4454
  function nextWorkingDay(calendar, domainDay) {
4350
- let cursor = truncateToUtcDay(domainDay, "UTC");
4455
+ let cursor = truncateToUtcDay(domainDay, UTC_TIME_ZONE);
4351
4456
  while (!calendar.isWorkTime(cursor, CALENDAR_UNIT.DAY)) {
4352
4457
  cursor = new Date(cursor);
4353
4458
  cursor.setUTCDate(cursor.getUTCDate() + 1);
4354
- cursor = truncateToUtcDay(cursor, "UTC");
4459
+ cursor = truncateToUtcDay(cursor, UTC_TIME_ZONE);
4355
4460
  }
4356
4461
  return cursor;
4357
4462
  }
@@ -4374,22 +4479,22 @@ function shiftEnd(calendar, domainDay) {
4374
4479
  });
4375
4480
  }
4376
4481
  var START_BASED_CONSTRAINTS2 = /* @__PURE__ */ new Set([
4377
- "snet",
4378
- "snlt",
4379
- "mso"
4482
+ CONSTRAINT_TYPE.SNET,
4483
+ CONSTRAINT_TYPE.SNLT,
4484
+ CONSTRAINT_TYPE.MSO
4380
4485
  ]);
4381
4486
  var END_BASED_CONSTRAINTS = /* @__PURE__ */ new Set([
4382
- "fnet",
4383
- "fnlt",
4384
- "mfo"
4487
+ CONSTRAINT_TYPE.FNET,
4488
+ CONSTRAINT_TYPE.FNLT,
4489
+ CONSTRAINT_TYPE.MFO
4385
4490
  ]);
4386
4491
  var DATELESS_CONSTRAINTS = /* @__PURE__ */ new Set([
4387
- "asap",
4388
- "alap"
4492
+ CONSTRAINT_TYPE.ASAP,
4493
+ CONSTRAINT_TYPE.ALAP
4389
4494
  ]);
4390
- var IMPLIED_CONSTRAINT_ON_DATE_EDIT = "snet";
4495
+ var IMPLIED_CONSTRAINT_ON_DATE_EDIT = CONSTRAINT_TYPE.SNET;
4391
4496
  function normalizeConstraintDate(typedDay, calendar, constraintType) {
4392
- const constraintDay = truncateToUtcDay(typedDay, "UTC");
4497
+ const constraintDay = truncateToUtcDay(typedDay, UTC_TIME_ZONE);
4393
4498
  if (!START_BASED_CONSTRAINTS2.has(constraintType) && !END_BASED_CONSTRAINTS.has(constraintType)) {
4394
4499
  return constraintDay;
4395
4500
  }
@@ -4425,6 +4530,20 @@ var POST_PROCESSOR = {
4425
4530
  // src/columns/shared/error-codes.ts
4426
4531
  var VALIDATION_REASON = {
4427
4532
  NEGATIVE_DURATION: "negative_duration"};
4533
+ var EDIT_DENIAL_REASON = {
4534
+ COMPLETED: "completed",
4535
+ SUMMARY: "summary",
4536
+ HAS_PROGRESS: "has_progress",
4537
+ HAS_LOOKAHEAD_TASKS: "has_lookahead_tasks",
4538
+ SIR_START_AFTER_PROGRESS: "sir_start_after_progress"
4539
+ };
4540
+ var EDIT_ALERT_KEY = {
4541
+ CANT_EDIT_COMPLETED: "cant_edit_completed_activity",
4542
+ SUMMARY_COLUMN_VALUE: "summary_column_value",
4543
+ CANT_EDIT_WITH_PROGRESS: "cant_edit_activity_with_progress",
4544
+ SIR_CANT_MOVE_START_AFTER_PROGRESS: "sir_cant_move_start_after_progress",
4545
+ CANT_EDIT_WITH_TASK: "cant_edit_actvity_with_task"
4546
+ };
4428
4547
 
4429
4548
  // src/columns/shared/constraint-validation.ts
4430
4549
  function checkConstraintViolation2(constraintType, constraintDate, projectedDate) {
@@ -4489,7 +4608,7 @@ var durationPipeline = {
4489
4608
  } : {}
4490
4609
  };
4491
4610
  },
4492
- trackEvent: "activity_duration_entry"
4611
+ trackEvent: COLUMN_TRACK_EVENT.DURATION_ENTRY
4493
4612
  };
4494
4613
  function isNegativeDuration(value) {
4495
4614
  return Math.sign(value) === -1;
@@ -4501,7 +4620,7 @@ function checkDurationAgainstConstraints(activity, newDuration, ctx) {
4501
4620
  const calendar = ctx.calendars.getCalendar(activity.calendarId);
4502
4621
  if (!calendar) return { violated: false };
4503
4622
  const type = activity.constraintType;
4504
- if (type !== "fnet" && type !== "fnlt" && type !== "mfo") {
4623
+ if (type !== CONSTRAINT_TYPE.FNET && type !== CONSTRAINT_TYPE.FNLT && type !== CONSTRAINT_TYPE.MFO) {
4505
4624
  return { violated: false };
4506
4625
  }
4507
4626
  const projectedEnd = calendar.calculateEndDate(
@@ -4547,10 +4666,10 @@ var MAX_PROGRESS = PROGRESS_COMPLETE;
4547
4666
  var progressPipeline = {
4548
4667
  targetField: "progress",
4549
4668
  canEdit(activity, hierarchy) {
4550
- if (hasLookaheadTasks(activity))
4551
- return cannotEdit("has_lookahead_tasks", "cant_edit_actvity_with_task");
4552
4669
  if (isSummaryActivity2(activity, hierarchy))
4553
4670
  return cannotEdit("summary", "summary_column_value");
4671
+ if (hasLookaheadTasks(activity))
4672
+ return cannotEdit("has_lookahead_tasks", "cant_edit_actvity_with_task");
4554
4673
  return canEdit();
4555
4674
  },
4556
4675
  parseInput(rawValue) {
@@ -4594,7 +4713,7 @@ var progressPipeline = {
4594
4713
  trackingEvents
4595
4714
  });
4596
4715
  },
4597
- trackEvent: "activity_progress_entry"
4716
+ trackEvent: COLUMN_TRACK_EVENT.PROGRESS_ENTRY
4598
4717
  };
4599
4718
  function isOutOfRange(value) {
4600
4719
  return value < MIN_PROGRESS || value > MAX_PROGRESS;
@@ -4674,7 +4793,7 @@ function computeWeightedProgress(parentId, overlay, hierarchy) {
4674
4793
  function buildRecursiveTrackingEvents(activity, newValue) {
4675
4794
  return [
4676
4795
  {
4677
- name: "activity_progress_update_radio_button",
4796
+ name: COLUMN_TRACK_EVENT.PROGRESS_UPDATE_RADIO_BUTTON,
4678
4797
  properties: {
4679
4798
  activity_id: activity.id,
4680
4799
  activity_name: activity.name,
@@ -4714,7 +4833,7 @@ var costPipeline = {
4714
4833
  cascadeMutations
4715
4834
  });
4716
4835
  },
4717
- trackEvent: "activity_cost_budgeted_entry"
4836
+ trackEvent: COLUMN_TRACK_EVENT.COST_BUDGETED_ENTRY
4718
4837
  };
4719
4838
  function buildCostAncestorCascade(activity, newCost, hierarchy) {
4720
4839
  const overlay = /* @__PURE__ */ new Map();
@@ -4767,7 +4886,7 @@ var usedCostPipeline = {
4767
4886
  }
4768
4887
  );
4769
4888
  },
4770
- trackEvent: "activity_cost_spent_entry"
4889
+ trackEvent: COLUMN_TRACK_EVENT.COST_SPENT_ENTRY
4771
4890
  };
4772
4891
  function buildUsedCostAncestorCascade(activity, newUsedCost, hierarchy) {
4773
4892
  const overlay = /* @__PURE__ */ new Map();
@@ -4822,7 +4941,7 @@ var hhWorkTimePipeline = {
4822
4941
  }
4823
4942
  );
4824
4943
  },
4825
- trackEvent: "activity_labor_hours_budgeted_entry"
4944
+ trackEvent: COLUMN_TRACK_EVENT.LABOR_HOURS_BUDGETED_ENTRY
4826
4945
  };
4827
4946
  function computeRealWork(hhWorkTime, progress) {
4828
4947
  return computeLeafRealWork(hhWorkTime, progress);
@@ -4915,7 +5034,7 @@ var startDatePipeline = {
4915
5034
  throw new Error("startDatePipeline: no calendar resolved (integrity)");
4916
5035
  }
4917
5036
  const finalStart = shiftStart(calendar, newValue);
4918
- const milestoneActivity = activity.type === "milestone";
5037
+ const milestoneActivity = activity.type === ACTIVITY_TYPE.MILESTONE;
4919
5038
  const finalEnd = milestoneActivity ? finalStart : calendar.calculateEndDate(finalStart, activity.durationHours);
4920
5039
  const constraintDate = finalStart;
4921
5040
  return {
@@ -4935,7 +5054,7 @@ var startDatePipeline = {
4935
5054
  constraintWarning: detectConstraintWarning(activity, finalStart, calendar)
4936
5055
  };
4937
5056
  },
4938
- trackEvent: "activity_start_date_entry"
5057
+ trackEvent: COLUMN_TRACK_EVENT.START_DATE_ENTRY
4939
5058
  };
4940
5059
  function checkParentStartConstraint(activity, newDate, ctx) {
4941
5060
  const parentStartDate = ctx.hierarchy.getParentStartDateIfHasPredecessors(
@@ -5029,7 +5148,7 @@ var endDatePipeline = {
5029
5148
  ...constraintWarning ? { constraintWarning } : {}
5030
5149
  };
5031
5150
  },
5032
- trackEvent: "activity_end_date_entry"
5151
+ trackEvent: COLUMN_TRACK_EVENT.END_DATE_ENTRY
5033
5152
  };
5034
5153
  function isNearlyCompleted(activity) {
5035
5154
  return activity.progress >= NEAR_COMPLETE_THRESHOLD;
@@ -5140,7 +5259,9 @@ function buildConstraintTypeExtraFields(activity, newType, ctx) {
5140
5259
  };
5141
5260
  }
5142
5261
  function normalizeMilestoneConstraintDate(activity, newType, derivedDate, ctx) {
5143
- if (activity.type !== "milestone" || !derivedDate) return derivedDate;
5262
+ if (activity.type !== ACTIVITY_TYPE.MILESTONE || !derivedDate) {
5263
+ return derivedDate;
5264
+ }
5144
5265
  const calendar = ctx.calendars.getCalendar(String(activity.calendarId));
5145
5266
  if (!calendar) return derivedDate;
5146
5267
  return normalizeConstraintDate(derivedDate, calendar, newType);
@@ -5218,7 +5339,7 @@ var calendarIdPipeline = {
5218
5339
  postProcessors: []
5219
5340
  });
5220
5341
  },
5221
- trackEvent: "activity_calendar_assignment"
5342
+ trackEvent: COLUMN_TRACK_EVENT.CALENDAR_ASSIGNMENT
5222
5343
  };
5223
5344
  function isEmpty(value) {
5224
5345
  return value === "";
@@ -5300,8 +5421,7 @@ var customIdPipeline = {
5300
5421
  { customId: newValue },
5301
5422
  { autoSchedule: false, postProcessors: [] }
5302
5423
  );
5303
- },
5304
- trackEvent: "schedule_custom_id_edition"
5424
+ }
5305
5425
  };
5306
5426
 
5307
5427
  // src/columns/subcontract-id/subcontract-id-pipeline.ts
@@ -5440,6 +5560,9 @@ var ACTIVITY_BATCH_MODE = {
5440
5560
  APPEND: "append",
5441
5561
  REPLACE: "replace"
5442
5562
  };
5563
+ var ACTIVITY_PROGRESS_ORIGIN = {
5564
+ ACTION_BUTTON: "action-button"
5565
+ };
5443
5566
  var SCHEDULE_EFFECT_KIND = {
5444
5567
  SIR_AUTO_REJECT: "sir-auto-reject"
5445
5568
  };
@@ -5458,7 +5581,9 @@ var CHANGE_SET_SOURCE_KIND = {
5458
5581
 
5459
5582
  // src/dispatch/shared/constraint-warnings.ts
5460
5583
  function toConstraintWarning(activityId, notification) {
5461
- if (!notification || notification.type !== "constraint") return null;
5584
+ if (!notification || notification.type !== NOTIFICATION_TYPE.CONSTRAINT) {
5585
+ return null;
5586
+ }
5462
5587
  const data = notification.data;
5463
5588
  if (!data?.constraintType || !data.constraintDate) return null;
5464
5589
  return {
@@ -5504,6 +5629,7 @@ var ACTIVITY_PROPERTY = {
5504
5629
  TYPE: "type",
5505
5630
  START_DATE: "startDate",
5506
5631
  END_DATE: "endDate",
5632
+ DURATION_HOURS: "durationHours",
5507
5633
  CONSTRAINT_TYPE: "constraintType",
5508
5634
  CONSTRAINT_DATE: "constraintDate",
5509
5635
  PROGRESS: "progress",
@@ -5636,7 +5762,7 @@ async function buildActivityChanges(adapter, before, touched, correlativeBefore)
5636
5762
  function buildEntryForTouchedId(adapter, before, activityId, correlativeBefore) {
5637
5763
  const afterSnap = adapter.getActivity(activityId);
5638
5764
  if (!afterSnap) {
5639
- return { id: activityId, kind: "deleted", after: null };
5765
+ return { id: activityId, kind: ENTITY_CHANGE_KIND.DELETED, after: null };
5640
5766
  }
5641
5767
  const beforeSnap = before.get(activityId);
5642
5768
  if (!beforeSnap && correlativeBefore?.has(activityId)) {
@@ -5651,7 +5777,7 @@ function buildEntryForTouchedId(adapter, before, activityId, correlativeBefore)
5651
5777
  if (beforeSnap && Object.keys(diff).length === 0) return null;
5652
5778
  return {
5653
5779
  id: activityId,
5654
- kind: beforeSnap ? "updated" : "created",
5780
+ kind: beforeSnap ? ENTITY_CHANGE_KIND.UPDATED : ENTITY_CHANGE_KIND.CREATED,
5655
5781
  fields: diff,
5656
5782
  after: structuredCloneActivity(afterSnap)
5657
5783
  };
@@ -5660,7 +5786,7 @@ function buildCorrelativeOnlyEntry(activityId, correlativeIdBefore, liveActivity
5660
5786
  if (correlativeIdBefore === liveActivity.correlativeId) return null;
5661
5787
  return {
5662
5788
  id: activityId,
5663
- kind: "updated",
5789
+ kind: ENTITY_CHANGE_KIND.UPDATED,
5664
5790
  fields: {
5665
5791
  correlativeId: {
5666
5792
  before: correlativeIdBefore,
@@ -5785,7 +5911,7 @@ function expectedProgressFromBaseline(start, end, now, calendar) {
5785
5911
  }
5786
5912
 
5787
5913
  // src/columns/expected-progress/compute.ts
5788
- var isProject = (activity) => activity.type === "project";
5914
+ var isProject = (activity) => activity.type === ACTIVITY_TYPE.PROJECT;
5789
5915
  var leafExpectedLive = (activity, now, state) => {
5790
5916
  const calendarId = activity.calendarId;
5791
5917
  const calendar = calendarId != null ? state.calendarReader.getCalendar(String(calendarId)) : null;
@@ -5839,7 +5965,7 @@ function applyExpectedProgressLive(state, now) {
5839
5965
  }
5840
5966
 
5841
5967
  // src/columns/expected-progress-base/compute.ts
5842
- var isProject2 = (a) => a.type === "project";
5968
+ var isProject2 = (a) => a.type === ACTIVITY_TYPE.PROJECT;
5843
5969
  var activeBaselineOf = (a) => getActiveBaseline(a);
5844
5970
  var leafExpected = (a, now, adapter, defaultBaseCalendarId) => {
5845
5971
  const base = activeBaselineOf(a);
@@ -6001,15 +6127,44 @@ function getNextWorkingHour(activityParams) {
6001
6127
  return newDate;
6002
6128
  }
6003
6129
 
6130
+ // src/critical-path/legacy/constants/constraints.js
6131
+ var CONSTRAINT_TYPES = CONSTRAINT_TYPE;
6132
+
6133
+ // src/critical-path/legacy/constants/linkTypes.js
6134
+ var LINK_TYPES3 = Object.freeze({
6135
+ FS: LINK_CODE.FINISH_TO_START,
6136
+ SS: LINK_CODE.START_TO_START,
6137
+ FF: LINK_CODE.FINISH_TO_FINISH,
6138
+ SF: LINK_CODE.START_TO_FINISH
6139
+ });
6140
+
6141
+ // src/critical-path/legacy/constants/linkByCode.js
6142
+ function getLinkNameByCode(code) {
6143
+ return LINK_TYPE_CODE[String(Number(code))] ?? LINK_CODE.START_TO_FINISH;
6144
+ }
6145
+
6146
+ // src/critical-path/legacy/constants/calculation.js
6147
+ var CALCULATION_DIRECTION = Object.freeze({
6148
+ FORWARD: "forward",
6149
+ BACKWARD: "backward"
6150
+ });
6151
+ var COMPARISON_DIRECTION = Object.freeze({
6152
+ GREATER: "greater",
6153
+ LESS: "less"
6154
+ });
6155
+ var GANTT_FIELD = Object.freeze({
6156
+ SOURCE: "$source"
6157
+ });
6158
+
6004
6159
  // src/critical-path/legacy/helpers/filters.js
6005
6160
  var byFirstLevel = (activity) => {
6006
6161
  if (!activity) return false;
6007
6162
  return activity["$level"] === 1;
6008
6163
  };
6009
- var filterByParentType = (activity) => activity.type === "project";
6164
+ var filterByParentType = (activity) => activity.type === ACTIVITY_TYPE.PROJECT;
6010
6165
  var avoidSubproject = (activity) => activity["$level"] !== 0;
6011
- var byTaskType = (activity) => activity.type === "task";
6012
- var byTaskTypeAndMilestone = (activity) => activity.type === "task" || activity.type === "milestone";
6166
+ var byTaskType = (activity) => activity.type === ACTIVITY_TYPE.TASK;
6167
+ var byTaskTypeAndMilestone = (activity) => activity.type === ACTIVITY_TYPE.TASK || activity.type === ACTIVITY_TYPE.MILESTONE;
6013
6168
  var filters_default = {
6014
6169
  byFirstLevel,
6015
6170
  filterByParentType,
@@ -6018,37 +6173,6 @@ var filters_default = {
6018
6173
  byTaskTypeAndMilestone
6019
6174
  };
6020
6175
 
6021
- // src/critical-path/legacy/constants/constraints.js
6022
- var CONSTRAINT_TYPES = Object.freeze({
6023
- MFO: "mfo",
6024
- MSO: "mso",
6025
- FNLT: "fnlt",
6026
- FNET: "fnet",
6027
- SNET: "snet",
6028
- SNLT: "snlt",
6029
- ALAP: "alap",
6030
- ASAP: "asap"
6031
- });
6032
-
6033
- // src/critical-path/legacy/constants/linkTypes.js
6034
- var LINK_TYPES2 = Object.freeze({
6035
- FS: "fs",
6036
- SS: "ss",
6037
- FF: "ff",
6038
- SF: "sf"
6039
- });
6040
-
6041
- // src/critical-path/legacy/constants/linkByCode.js
6042
- function getLinkNameByCode(code) {
6043
- const linkMap = {
6044
- 0: "fs",
6045
- 1: "ss",
6046
- 2: "ff",
6047
- 3: "sf"
6048
- };
6049
- return linkMap[Number(code)] || "sf";
6050
- }
6051
-
6052
6176
  // src/critical-path/legacy/base/identifiers/secondLevelActivities.js
6053
6177
  function identifySecondLevelActivities(params) {
6054
6178
  const { gantt, pendingParentsWithNoLinks, calculations, linkProperty } = params;
@@ -6110,7 +6234,7 @@ function filterChildrenThatCanBeCalculated(params) {
6110
6234
  const linkedActivities = getArrayOfLinkedActivities3({
6111
6235
  gantt,
6112
6236
  links,
6113
- linkDirection: linkProperty === "$source" ? "target" : "source"
6237
+ linkDirection: linkProperty === GANTT_FIELD.SOURCE ? "target" : "source"
6114
6238
  });
6115
6239
  const isLinkedWithCalculatedOrSibling = linkedActivities.every(
6116
6240
  (linkedActivityId) => calculations.has(linkedActivityId)
@@ -6139,13 +6263,13 @@ function getArrayOfLinkedActivities(params) {
6139
6263
  function identifyInitialActivities({ gantt, linkProperty, direction }) {
6140
6264
  try {
6141
6265
  const chainStartActivities = getChainStartActivities(gantt, linkProperty);
6142
- if (direction === "forward") {
6266
+ if (direction === CALCULATION_DIRECTION.FORWARD) {
6143
6267
  return {
6144
6268
  chainStartActivities,
6145
6269
  activitiesStartChainButChildrenOfLinkedParents: null
6146
6270
  };
6147
6271
  }
6148
- if (direction === "backward") {
6272
+ if (direction === CALCULATION_DIRECTION.BACKWARD) {
6149
6273
  return processBackwardActivities(
6150
6274
  chainStartActivities,
6151
6275
  gantt,
@@ -6169,7 +6293,7 @@ function processBackwardActivities(chainStartActivities, gantt, linkProperty) {
6169
6293
  if (!parentActivity) return;
6170
6294
  if (parentActivity[linkProperty].length > 0) {
6171
6295
  activitiesStartChainButChildrenOfLinkedParents.add(activity.id);
6172
- } else if (parentActivity.constraint_type !== "fnlt") {
6296
+ } else if (parentActivity.constraint_type !== CONSTRAINT_TYPES.FNLT) {
6173
6297
  withoutLinkedParents.push(activity);
6174
6298
  }
6175
6299
  });
@@ -6190,7 +6314,7 @@ function identifyParentsWithAndWithoutLinks({
6190
6314
  const parentsWithFullProgress = /* @__PURE__ */ new Set();
6191
6315
  const pendingParentsWithNoLinks = /* @__PURE__ */ new Set();
6192
6316
  const pendingParentsWithLinks = /* @__PURE__ */ new Set();
6193
- if (direction === "backward") {
6317
+ if (direction === CALCULATION_DIRECTION.BACKWARD) {
6194
6318
  const parentsWithFullProgressArray = getParentsWithFullProgress(allParentActivities);
6195
6319
  parentsWithFullProgressArray.forEach((activity) => {
6196
6320
  parentsWithFullProgress.add(activity.id);
@@ -6228,9 +6352,9 @@ function getParentsWithNoLinks(activities, direction, linkProperty) {
6228
6352
  }
6229
6353
  const hasLinks = links.length > 0;
6230
6354
  const constraintType = activity.constraint_type || "";
6231
- const isNotFnlt = constraintType !== "fnlt";
6232
- if (direction === "forward") {
6233
- const isNotSnet = constraintType !== "snet";
6355
+ const isNotFnlt = constraintType !== CONSTRAINT_TYPES.FNLT;
6356
+ if (direction === CALCULATION_DIRECTION.FORWARD) {
6357
+ const isNotSnet = constraintType !== CONSTRAINT_TYPES.SNET;
6234
6358
  return !hasLinks && isNotFnlt && isNotSnet;
6235
6359
  } else {
6236
6360
  return !hasLinks && isNotFnlt;
@@ -6286,10 +6410,10 @@ function identifyForbiddenActivities({
6286
6410
  }
6287
6411
  }
6288
6412
  function getLinkProperty(direction) {
6289
- return direction === "forward" ? "$source" : "$target";
6413
+ return direction === CALCULATION_DIRECTION.FORWARD ? GANTT_FIELD.SOURCE : "$target";
6290
6414
  }
6291
6415
  function getLinkDirection(direction) {
6292
- return direction === "forward" ? "target" : "source";
6416
+ return direction === CALCULATION_DIRECTION.FORWARD ? "target" : "source";
6293
6417
  }
6294
6418
  function getArrayOfLinkedActivities2(gantt, links, direction) {
6295
6419
  return links.map((link) => {
@@ -6325,7 +6449,7 @@ function mutateDate({
6325
6449
  activityCalendar,
6326
6450
  activity
6327
6451
  }) {
6328
- if (linkType2 === LINK_TYPES2.FS && lag === 0) {
6452
+ if (linkType2 === LINK_TYPES3.FS && lag === 0) {
6329
6453
  return getNextWorkingHour({
6330
6454
  activityCalendar,
6331
6455
  direction: "future",
@@ -6361,10 +6485,10 @@ function calculateRestrictionSnet({
6361
6485
  return { es, ef };
6362
6486
  }
6363
6487
  function mutateTheDateToFutureOrPastInBaseRestriction(dateBaseToCalculate, restrictionOfLink, activityCalendar, activity) {
6364
- if (![LINK_TYPES2.FS, LINK_TYPES2.SS, LINK_TYPES2.FF].includes(restrictionOfLink)) {
6488
+ if (![LINK_TYPES3.FS, LINK_TYPES3.SS, LINK_TYPES3.FF].includes(restrictionOfLink)) {
6365
6489
  return dateBaseToCalculate;
6366
6490
  }
6367
- let constraintThatGoToNextWorkingHour = [LINK_TYPES2.FS, LINK_TYPES2.SS];
6491
+ let constraintThatGoToNextWorkingHour = [LINK_TYPES3.FS, LINK_TYPES3.SS];
6368
6492
  let direction = constraintThatGoToNextWorkingHour.includes(restrictionOfLink) ? "future" : "past";
6369
6493
  return getNextWorkingHour({
6370
6494
  dateBaseToCalculate,
@@ -6392,10 +6516,10 @@ var CalculateForwardParentsWithLinks = class {
6392
6516
  const calculationsFromLinks = this.calculateLinks();
6393
6517
  const maxEfFromLinks = getMaxEarlyStartSet(calculationsFromLinks);
6394
6518
  const constraintType = this.activity.constraint_type;
6395
- if (constraintType === "snet") {
6519
+ if (constraintType === CONSTRAINT_TYPES.SNET) {
6396
6520
  return this.handleSNETConstraint(maxEfFromLinks);
6397
6521
  }
6398
- if (constraintType === "fnlt") {
6522
+ if (constraintType === CONSTRAINT_TYPES.FNLT) {
6399
6523
  return this.handleFNLTConstraint(maxEfFromLinks);
6400
6524
  }
6401
6525
  return maxEfFromLinks;
@@ -6409,13 +6533,13 @@ var CalculateForwardParentsWithLinks = class {
6409
6533
  const predecessorEs = linkedActivity.es;
6410
6534
  const predecessorEf = linkedActivity.ef;
6411
6535
  let calculation = null;
6412
- if (linkType2 === "ss") {
6536
+ if (linkType2 === LINK_TYPES3.SS) {
6413
6537
  calculation = this.calculateSSLink({ lag, predecessorEs });
6414
- } else if (linkType2 === "ff") {
6538
+ } else if (linkType2 === LINK_TYPES3.FF) {
6415
6539
  calculation = this.calculateFFLink({ lag, predecessorEf });
6416
- } else if (linkType2 === "fs") {
6540
+ } else if (linkType2 === LINK_TYPES3.FS) {
6417
6541
  calculation = this.calculateFSLink({ lag, predecessorEf });
6418
- } else if (linkType2 === "sf") {
6542
+ } else if (linkType2 === LINK_TYPES3.SF) {
6419
6543
  calculation = this.calculateSFLink({
6420
6544
  lag,
6421
6545
  predecessorEs,
@@ -6460,7 +6584,7 @@ var CalculateForwardParentsWithLinks = class {
6460
6584
  }
6461
6585
  calculateSSLink({ lag, predecessorEs }) {
6462
6586
  const esLinked = mutateDate({
6463
- linkType: "ss",
6587
+ linkType: LINK_TYPES3.SS,
6464
6588
  lag,
6465
6589
  predecessorTime: predecessorEs,
6466
6590
  activityCalendar: this.activityCalendar,
@@ -6475,7 +6599,7 @@ var CalculateForwardParentsWithLinks = class {
6475
6599
  if (lag > 0) {
6476
6600
  es = mutateTheDateToFutureOrPastInBaseRestriction(
6477
6601
  es,
6478
- "ss",
6602
+ LINK_TYPES3.SS,
6479
6603
  this.activityCalendar,
6480
6604
  this.activity
6481
6605
  );
@@ -6490,7 +6614,7 @@ var CalculateForwardParentsWithLinks = class {
6490
6614
  }
6491
6615
  calculateFFLink({ lag, predecessorEf }) {
6492
6616
  const efLinked = mutateDate({
6493
- linkType: "ff",
6617
+ linkType: LINK_TYPES3.FF,
6494
6618
  lag,
6495
6619
  predecessorTime: predecessorEf,
6496
6620
  activityCalendar: this.activityCalendar,
@@ -6511,7 +6635,7 @@ var CalculateForwardParentsWithLinks = class {
6511
6635
  if (lag > 0) {
6512
6636
  es = mutateTheDateToFutureOrPastInBaseRestriction(
6513
6637
  es,
6514
- "ff",
6638
+ LINK_TYPES3.FF,
6515
6639
  this.activityCalendar,
6516
6640
  this.activity
6517
6641
  );
@@ -6558,7 +6682,7 @@ var CalculateForwardParentsWithLinks = class {
6558
6682
  if (lag > 0) {
6559
6683
  es = mutateTheDateToFutureOrPastInBaseRestriction(
6560
6684
  es,
6561
- "sf",
6685
+ LINK_TYPES3.SF,
6562
6686
  this.activityCalendar,
6563
6687
  this.activity
6564
6688
  );
@@ -6585,16 +6709,16 @@ var CalculateBackwardParentsLinks = class {
6585
6709
  const calculationsFromLinks = [];
6586
6710
  for (let linkedActivity of this.linkedActivitiesData) {
6587
6711
  const linkType2 = getLinkNameByCode(linkedActivity.linkType);
6588
- if (linkedActivity.type === "task" && Number(linkedActivity.progress) > 0) {
6712
+ if (linkedActivity.type === ACTIVITY_TYPE.TASK && Number(linkedActivity.progress) > 0) {
6589
6713
  continue;
6590
6714
  }
6591
- if (linkedActivity.type === "project" && Number(linkedActivity.progress) === 100) {
6715
+ if (linkedActivity.type === ACTIVITY_TYPE.PROJECT && Number(linkedActivity.progress) === 100) {
6592
6716
  continue;
6593
6717
  }
6594
6718
  const lag = linkedActivity.linkLag;
6595
6719
  let sucessorLs = linkedActivity.ls;
6596
6720
  let sucessorLf = linkedActivity.lf;
6597
- if (linkType2 === "ss") {
6721
+ if (linkType2 === LINK_TYPES3.SS) {
6598
6722
  const valuesToDoCalculation = {
6599
6723
  lag,
6600
6724
  workTime: sucessorLs,
@@ -6604,7 +6728,7 @@ var CalculateBackwardParentsLinks = class {
6604
6728
  let { ls, lf } = this.calculateSSLink(valuesToDoCalculation);
6605
6729
  calculationsFromLinks.push({ ls, lf });
6606
6730
  }
6607
- if (linkType2 === "ff") {
6731
+ if (linkType2 === LINK_TYPES3.FF) {
6608
6732
  const valuesToDoCalculation = {
6609
6733
  lag,
6610
6734
  workTime: sucessorLf,
@@ -6614,7 +6738,7 @@ var CalculateBackwardParentsLinks = class {
6614
6738
  let { ls, lf } = this.calculateFFLink(valuesToDoCalculation);
6615
6739
  calculationsFromLinks.push({ ls, lf });
6616
6740
  }
6617
- if (linkType2 === "fs") {
6741
+ if (linkType2 === LINK_TYPES3.FS) {
6618
6742
  const valuesToDoCalculation = {
6619
6743
  lag,
6620
6744
  workTime: sucessorLs,
@@ -6624,7 +6748,7 @@ var CalculateBackwardParentsLinks = class {
6624
6748
  let { ls, lf } = this.calculateFsLink(valuesToDoCalculation);
6625
6749
  calculationsFromLinks.push({ ls, lf });
6626
6750
  }
6627
- if (linkType2 === "sf") {
6751
+ if (linkType2 === LINK_TYPES3.SF) {
6628
6752
  const valuesToDoCalculation = {
6629
6753
  lag,
6630
6754
  workTime: sucessorLf,
@@ -6635,7 +6759,7 @@ var CalculateBackwardParentsLinks = class {
6635
6759
  calculationsFromLinks.push({ ls, lf });
6636
6760
  }
6637
6761
  }
6638
- if (this.activity.constraint_type === "fnlt") {
6762
+ if (this.activity.constraint_type === CONSTRAINT_TYPES.FNLT) {
6639
6763
  const maxLfFromLinks = this.getMinLfFromLinks(calculationsFromLinks);
6640
6764
  let restriction = this.calculateSfRestrictionDates();
6641
6765
  if (!maxLfFromLinks) {
@@ -6682,7 +6806,7 @@ var CalculateBackwardParentsLinks = class {
6682
6806
  lfSucessor = this.getLastWorkingHour(
6683
6807
  lfSucessor,
6684
6808
  this.activityCalendar,
6685
- "past"
6809
+ WORK_TIME_DIRECTION.PAST
6686
6810
  );
6687
6811
  }
6688
6812
  lfPred = addDurationToDate(
@@ -6712,7 +6836,7 @@ var CalculateBackwardParentsLinks = class {
6712
6836
  const lsSucessor2 = this.getLastWorkingHour(
6713
6837
  workTime,
6714
6838
  this.activityCalendar,
6715
- "past"
6839
+ WORK_TIME_DIRECTION.PAST
6716
6840
  );
6717
6841
  lfPred = addDurationToDate(
6718
6842
  this.activityCalendar,
@@ -6720,7 +6844,7 @@ var CalculateBackwardParentsLinks = class {
6720
6844
  lfDataCalculation,
6721
6845
  this.activity
6722
6846
  );
6723
- lfPred = this.getLastWorkingHour(lfPred, this.activityCalendar, "past");
6847
+ lfPred = this.getLastWorkingHour(lfPred, this.activityCalendar, WORK_TIME_DIRECTION.PAST);
6724
6848
  lsPred = addDurationToDate(
6725
6849
  this.activityCalendar,
6726
6850
  lfPred,
@@ -6746,7 +6870,7 @@ var CalculateBackwardParentsLinks = class {
6746
6870
  this.activity
6747
6871
  );
6748
6872
  if (!isMilestone) {
6749
- lfPred = this.getLastWorkingHour(lfPred, this.activityCalendar, "past");
6873
+ lfPred = this.getLastWorkingHour(lfPred, this.activityCalendar, WORK_TIME_DIRECTION.PAST);
6750
6874
  }
6751
6875
  return { ls: lsPred, lf: lfPred };
6752
6876
  }
@@ -6833,10 +6957,10 @@ var CalculateBackwardParentsLinks = class {
6833
6957
  );
6834
6958
  return { ls: lsRestriction, lf: lfRestriction };
6835
6959
  }
6836
- getLastWorkingHour(date2, activityCalendar, dir = "past") {
6960
+ getLastWorkingHour(date2, activityCalendar, dir = WORK_TIME_DIRECTION.PAST) {
6837
6961
  const normalizedDate = date2 instanceof Date ? date2 : new Date(date2);
6838
6962
  let resetedDate = moment_default(normalizedDate).clone();
6839
- if (this.isActivityInInitHour(activityCalendar, normalizedDate) && dir === "past") {
6963
+ if (this.isActivityInInitHour(activityCalendar, normalizedDate) && dir === WORK_TIME_DIRECTION.PAST) {
6840
6964
  resetedDate = resetedDate.hours(0).minutes(0).seconds(0).milliseconds(0);
6841
6965
  }
6842
6966
  let newDate = getNextWorkingHour({
@@ -6882,7 +7006,7 @@ function parentWithLinks(params) {
6882
7006
  const linksArray = parent[linkProperty];
6883
7007
  const parentData = extractParentData(parent);
6884
7008
  let calculation = null;
6885
- if (direction === "forward") {
7009
+ if (direction === CALCULATION_DIRECTION.FORWARD) {
6886
7010
  const linksWithActivityData = getLinksWithActivityDataForward(
6887
7011
  linksArray,
6888
7012
  linkDirection,
@@ -7000,7 +7124,7 @@ function getCalculatedChildren(childrenIds, calculations) {
7000
7124
  return childrenIds.filter((childId) => calculations.has(childId)).map((childId) => calculations.get(childId));
7001
7125
  }
7002
7126
  function computeParentCalculation(childrenCalculations, direction) {
7003
- if (direction === "forward") {
7127
+ if (direction === CALCULATION_DIRECTION.FORWARD) {
7004
7128
  const earliestStart = calculateEarliestDate(childrenCalculations, "es");
7005
7129
  const latestFinish = calculateLatestDate(childrenCalculations, "ef");
7006
7130
  return { es: earliestStart, ef: latestFinish };
@@ -7032,8 +7156,8 @@ var CalculationOfParent = class {
7032
7156
  constructor(params) {
7033
7157
  this.activity = params.activity;
7034
7158
  this.direction = params.direction;
7035
- this.linkProperty = params.direction === "forward" ? "$target" : "$source";
7036
- this.linkDirection = params.direction === "forward" ? "source" : "target";
7159
+ this.linkProperty = params.direction === CALCULATION_DIRECTION.FORWARD ? "$target" : GANTT_FIELD.SOURCE;
7160
+ this.linkDirection = params.direction === CALCULATION_DIRECTION.FORWARD ? "source" : "target";
7037
7161
  this.calculationsOfParentThatImpactChildrens = params.calculationsOfParentThatImpactChildrens;
7038
7162
  this.calculations = params.calculations;
7039
7163
  this.calculationOfParentsFromLinks = params.calculationOfParentsFromLinks;
@@ -7047,7 +7171,7 @@ var CalculationOfParent = class {
7047
7171
  const allLinkedTasks = this.getArrayOfIdOfLinkedActivities(
7048
7172
  this.activity[this.linkProperty]
7049
7173
  );
7050
- if (this.direction === "backward") {
7174
+ if (this.direction === CALCULATION_DIRECTION.BACKWARD) {
7051
7175
  const restrictions = [CONSTRAINT_TYPES.FNLT];
7052
7176
  if (this.shouldCalculateParentWithLinksBackward(restrictions)) {
7053
7177
  this.calculateAndStoreParentWithLinks(this.activity);
@@ -7060,10 +7184,10 @@ var CalculationOfParent = class {
7060
7184
  }
7061
7185
  const areAllLinksCalculated = this.areAllLinksCalculated(allLinkedTasks);
7062
7186
  if (areAllLinksCalculated && this.calculationsOfParentThatImpactChildrens.has(this.activity.id)) {
7063
- if (this.direction === "forward") {
7187
+ if (this.direction === CALCULATION_DIRECTION.FORWARD) {
7064
7188
  this.setDatesToParentsWithLinks();
7065
7189
  }
7066
- if (this.direction === "backward") {
7190
+ if (this.direction === CALCULATION_DIRECTION.BACKWARD) {
7067
7191
  this.setDatesToParentsWithLinksBackward();
7068
7192
  }
7069
7193
  return;
@@ -7264,7 +7388,7 @@ var ThirdLevelActivityIdentifier = class {
7264
7388
  this.addActivityToLevel(activity, activitiesByLevel);
7265
7389
  }
7266
7390
  isProjectActivity(activity) {
7267
- return activity.type === "project";
7391
+ return activity.type === ACTIVITY_TYPE.PROJECT;
7268
7392
  }
7269
7393
  hasLink(activity) {
7270
7394
  return Boolean(activity[this.linkProperty]?.length);
@@ -7333,8 +7457,8 @@ var CriticalPathHelpers = class {
7333
7457
  constructor(ganttInstace, direction) {
7334
7458
  this.direction = direction;
7335
7459
  this.gantt = ganttInstace;
7336
- this.linkProperty = this.direction === "forward" ? "$target" : "$source";
7337
- this.linkDirection = this.direction === "forward" ? "source" : "target";
7460
+ this.linkProperty = this.direction === CALCULATION_DIRECTION.FORWARD ? "$target" : GANTT_FIELD.SOURCE;
7461
+ this.linkDirection = this.direction === CALCULATION_DIRECTION.FORWARD ? "source" : "target";
7338
7462
  this.projectDates = ganttInstace.getSubtaskDates();
7339
7463
  }
7340
7464
  tryToCalculateLastLevelChildrens() {
@@ -7426,7 +7550,7 @@ var CriticalPathHelpers = class {
7426
7550
  function(activity) {
7427
7551
  const parentId = Number(activity.parent);
7428
7552
  allTasks.add(activity.id);
7429
- if (activity.type === "project") {
7553
+ if (activity.type === ACTIVITY_TYPE.PROJECT) {
7430
7554
  const parentInfo = {
7431
7555
  level: activity["$level"],
7432
7556
  hasLink: Boolean(activity[this.linkProperty].length),
@@ -7447,7 +7571,7 @@ var CriticalPathHelpers = class {
7447
7571
  }
7448
7572
  level.get(Number(activity.parent)).push({
7449
7573
  id: activity.id,
7450
- isParent: activity.type === "project",
7574
+ isParent: activity.type === ACTIVITY_TYPE.PROJECT,
7451
7575
  calculated: false
7452
7576
  });
7453
7577
  }.bind(this),
@@ -7497,7 +7621,7 @@ var CriticalPathHelpers = class {
7497
7621
  }
7498
7622
  calculateSecondLevelActivities() {
7499
7623
  try {
7500
- if (this.direction === "forward") {
7624
+ if (this.direction === CALCULATION_DIRECTION.FORWARD) {
7501
7625
  this.recursiveCalculateEfAndEs(
7502
7626
  Array.from(this.secondLevelActivities),
7503
7627
  0,
@@ -7515,12 +7639,12 @@ var CriticalPathHelpers = class {
7515
7639
  this.chainStartActivities.forEach((activity) => {
7516
7640
  if (!activity) return;
7517
7641
  if (activity.progress > 100) return;
7518
- if (activity.type === "project") return;
7642
+ if (activity.type === ACTIVITY_TYPE.PROJECT) return;
7519
7643
  const dates = this.calculateStartAndFinishOfChainOrigin(
7520
7644
  activity,
7521
7645
  this.direction
7522
7646
  );
7523
- if (this.direction === "forward") {
7647
+ if (this.direction === CALCULATION_DIRECTION.FORWARD) {
7524
7648
  let { es, ef } = dates;
7525
7649
  this.calculations.set(activity.id, { es, ef, text: activity.text });
7526
7650
  this.activitiesWaitingForCalculation.delete(activity.id);
@@ -7601,7 +7725,7 @@ var CriticalPathHelpers = class {
7601
7725
  );
7602
7726
  }
7603
7727
  let direction = customDirection || this.direction;
7604
- if (direction === "forward") {
7728
+ if (direction === CALCULATION_DIRECTION.FORWARD) {
7605
7729
  let es = activity.start_date;
7606
7730
  let ef = activity.end_date;
7607
7731
  return {
@@ -7712,14 +7836,14 @@ var CriticalPathHelpers = class {
7712
7836
  }
7713
7837
  );
7714
7838
  arrayOfActivitiesObject.forEach((activity) => {
7715
- const isAParent = activity.type === "project";
7839
+ const isAParent = activity.type === ACTIVITY_TYPE.PROJECT;
7716
7840
  this.setDatesForActivityWithFullProgress(activity);
7717
7841
  this.activitiesWaitingForCalculation.delete(activity.id);
7718
7842
  if (isAParent && this.pendingParentsWithLinks.has(activity.id)) {
7719
7843
  this.parentCalculationFromChildren.add(activity.id);
7720
7844
  this.calculationsOfParentThatImpactChildrens.set(activity.id, {
7721
- [this.direction === "forward" ? "es" : "ls"]: activity.start_date,
7722
- [this.direction === "forward" ? "ef" : "lf"]: activity.end_date
7845
+ [this.direction === CALCULATION_DIRECTION.FORWARD ? "es" : "ls"]: activity.start_date,
7846
+ [this.direction === CALCULATION_DIRECTION.FORWARD ? "ef" : "lf"]: activity.end_date
7723
7847
  });
7724
7848
  this.calculationOfParentsFromLinks.add(activity.id);
7725
7849
  }
@@ -7814,7 +7938,7 @@ var LinksRulesCalculationsMethods = class {
7814
7938
  }
7815
7939
  return this.calculatedActivities.get(Number(activity));
7816
7940
  }
7817
- calculateSucessorTimes(predecessorTime, esDataCalculation, efDataCalculation = 0, lag, restrictionOfLink = LINK_TYPES2.FS) {
7941
+ calculateSucessorTimes(predecessorTime, esDataCalculation, efDataCalculation = 0, lag, restrictionOfLink = LINK_TYPES3.FS) {
7818
7942
  const activityCalendar = this.gantt.getCalendar(
7819
7943
  this.referenceActivity.calendar_id
7820
7944
  );
@@ -7826,9 +7950,9 @@ var LinksRulesCalculationsMethods = class {
7826
7950
  let dateBaseToCalculate = predecessorTime;
7827
7951
  let es = null;
7828
7952
  let ef = null;
7829
- const isAMilestone = this.referenceActivity.type === "milestone";
7953
+ const isAMilestone = this.referenceActivity.type === ACTIVITY_TYPE.MILESTONE;
7830
7954
  if (!isAMilestone) {
7831
- if (restrictionOfLink === LINK_TYPES2.FS && lag === 0) {
7955
+ if (restrictionOfLink === LINK_TYPES3.FS && lag === 0) {
7832
7956
  dateBaseToCalculate = getNextWorkingHour({
7833
7957
  dateBaseToCalculate,
7834
7958
  activityCalendar,
@@ -7843,7 +7967,7 @@ var LinksRulesCalculationsMethods = class {
7843
7967
  );
7844
7968
  }
7845
7969
  }
7846
- if ([LINK_TYPES2.FF, LINK_TYPES2.SF].includes(restrictionOfLink)) {
7970
+ if ([LINK_TYPES3.FF, LINK_TYPES3.SF].includes(restrictionOfLink)) {
7847
7971
  ef = addDurationToDate(
7848
7972
  activityCalendar,
7849
7973
  dateBaseToCalculate,
@@ -7897,7 +8021,7 @@ var LinksRulesCalculationsMethods = class {
7897
8021
  esDataCalculation,
7898
8022
  efDataCalculation,
7899
8023
  lag,
7900
- LINK_TYPES2.SS
8024
+ LINK_TYPES3.SS
7901
8025
  );
7902
8026
  }
7903
8027
  calculateFF(link) {
@@ -7911,7 +8035,7 @@ var LinksRulesCalculationsMethods = class {
7911
8035
  esDataCalculation,
7912
8036
  efDataCalculation,
7913
8037
  lag,
7914
- LINK_TYPES2.FF
8038
+ LINK_TYPES3.FF
7915
8039
  );
7916
8040
  }
7917
8041
  calculateFS(link) {
@@ -7925,7 +8049,7 @@ var LinksRulesCalculationsMethods = class {
7925
8049
  esDataCalculation,
7926
8050
  efDataCalculation,
7927
8051
  lag,
7928
- LINK_TYPES2.FS
8052
+ LINK_TYPES3.FS
7929
8053
  );
7930
8054
  }
7931
8055
  calculateSF(link) {
@@ -7939,17 +8063,17 @@ var LinksRulesCalculationsMethods = class {
7939
8063
  esDataCalculation,
7940
8064
  efDataCalculation,
7941
8065
  lag,
7942
- LINK_TYPES2.SF
8066
+ LINK_TYPES3.SF
7943
8067
  );
7944
8068
  }
7945
8069
  mutateTheDateToFutureOrPastInBaseRestriction(dateBaseToCalculate, restrictionOfLink, activityCalendar) {
7946
- if (![LINK_TYPES2.FS, LINK_TYPES2.SS, LINK_TYPES2.FF].includes(restrictionOfLink)) {
8070
+ if (![LINK_TYPES3.FS, LINK_TYPES3.SS, LINK_TYPES3.FF].includes(restrictionOfLink)) {
7947
8071
  return dateBaseToCalculate;
7948
8072
  }
7949
- const constraintThatGoToNextWorkingHour = [LINK_TYPES2.FS, LINK_TYPES2.SS];
8073
+ const constraintThatGoToNextWorkingHour = [LINK_TYPES3.FS, LINK_TYPES3.SS];
7950
8074
  const direction = constraintThatGoToNextWorkingHour.includes(
7951
8075
  restrictionOfLink
7952
- ) ? "future" : "past";
8076
+ ) ? "future" : WORK_TIME_DIRECTION.PAST;
7953
8077
  return getNextWorkingHour({
7954
8078
  dateBaseToCalculate,
7955
8079
  activityCalendar,
@@ -8030,7 +8154,7 @@ var ActivityCalculator = class {
8030
8154
  const pendingActivities = new Set(pendingToCalculate);
8031
8155
  for (const activityId of pendingToCalculate) {
8032
8156
  const activityData = this.gantt.getTask(activityId);
8033
- if (activityData.type === "project") {
8157
+ if (activityData.type === ACTIVITY_TYPE.PROJECT) {
8034
8158
  this.handleProjectActivity(
8035
8159
  activityId,
8036
8160
  activityData,
@@ -8094,7 +8218,7 @@ var ActivityCalculator = class {
8094
8218
  canCalculateParentActivity(activityData) {
8095
8219
  const hasNoLinks = (activityData[this.linkProperty] || []).length === 0;
8096
8220
  const constraintType = activityData.constraint_type;
8097
- const isSpecialConstraintType = this.direction === "forward" ? constraintType === "fnlt" || constraintType === "snlt" : constraintType === "fnlt";
8221
+ const isSpecialConstraintType = this.direction === CALCULATION_DIRECTION.FORWARD ? constraintType === CONSTRAINT_TYPES.FNLT || constraintType === CONSTRAINT_TYPES.SNLT : constraintType === CONSTRAINT_TYPES.FNLT;
8098
8222
  if (isSpecialConstraintType && hasNoLinks) {
8099
8223
  return true;
8100
8224
  }
@@ -8112,13 +8236,13 @@ var ActivityCalculator = class {
8112
8236
  if (isParentPendingWithLinks && !hasParentCalculationFromLinks) {
8113
8237
  return;
8114
8238
  }
8115
- if (this.direction === "backward") {
8239
+ if (this.direction === CALCULATION_DIRECTION.BACKWARD) {
8116
8240
  const isStartChainChildOfLinkedParent = this.activitiesStartChainButChildrenOfLinkedParents.has(activityId);
8117
8241
  if (isStartChainChildOfLinkedParent && !hasParentCalculationFromLinks) {
8118
8242
  return;
8119
8243
  }
8120
8244
  }
8121
- if (activityData["$target"].length === 0 && activityData["$source"].length === 0) {
8245
+ if (activityData["$target"].length === 0 && activityData[GANTT_FIELD.SOURCE].length === 0) {
8122
8246
  activitiesThatCanBeCalculated.add(activityId);
8123
8247
  pendingActivities.delete(activityId);
8124
8248
  return;
@@ -8129,7 +8253,7 @@ var ActivityCalculator = class {
8129
8253
  const arePredecessorsCalculated = linkedActivities.every(
8130
8254
  (act) => this.calculations.has(act.id)
8131
8255
  );
8132
- if (this.direction === "backward") {
8256
+ if (this.direction === CALCULATION_DIRECTION.BACKWARD) {
8133
8257
  const hasNoLinkedActivities = linkedActivities.length === 0;
8134
8258
  if ((hasNoLinkedActivities || arePredecessorsCalculated) && hasParentCalculationFromLinks) {
8135
8259
  activitiesThatCanBeCalculated.add(activityId);
@@ -8181,7 +8305,7 @@ var get_activities_to_calculate_default = ActivityCalculator;
8181
8305
  var createIsCurrent2 = (calculationId, getCurrentId) => () => getCurrentId() === calculationId;
8182
8306
 
8183
8307
  // src/critical-path/legacy/utils/validation.js
8184
- var shouldAbortCalculation = (gantt) => !gantt?.fullyParsed || typeof window !== "undefined" && window.to_use_react_gantt?.conversionMode?.isActive;
8308
+ var shouldAbortCalculation = (gantt) => !gantt?.fullyParsed;
8185
8309
 
8186
8310
  // src/critical-path/legacy/utils/timing.js
8187
8311
  var TIME_BUDGET_MS = 16;
@@ -8232,7 +8356,7 @@ var iterativeCalculate = async ({
8232
8356
  // src/critical-path/legacy/forward-path/index.js
8233
8357
  var ForwardPath = class extends generic_calculations_default {
8234
8358
  constructor(gantt) {
8235
- super(gantt, "forward");
8359
+ super(gantt, CALCULATION_DIRECTION.FORWARD);
8236
8360
  this.gantt = gantt;
8237
8361
  this.chainStartActivities = /* @__PURE__ */ new Set();
8238
8362
  this.secondLevelActivities = /* @__PURE__ */ new Set();
@@ -8297,7 +8421,7 @@ var ForwardPath = class extends generic_calculations_default {
8297
8421
  calculateStartAndFinishTimes(activitiesToCalculate) {
8298
8422
  activitiesToCalculate.forEach((activity) => {
8299
8423
  const activityReference = this.gantt.getTask(activity);
8300
- if (activityReference.type === "project") {
8424
+ if (activityReference.type === ACTIVITY_TYPE.PROJECT) {
8301
8425
  return this.doCalculationForParentType(activityReference);
8302
8426
  }
8303
8427
  if (!activityReference) {
@@ -8416,11 +8540,11 @@ var ForwardPath = class extends generic_calculations_default {
8416
8540
  this.activitiesWaitingForCalculation.delete(activity);
8417
8541
  });
8418
8542
  }
8419
- getTheGreatesDateBetweenRestrictionAndEsEf(restriction, linkCalculation, comparisonType = "greater") {
8420
- if (comparisonType === "greater") {
8543
+ getTheGreatesDateBetweenRestrictionAndEsEf(restriction, linkCalculation, comparisonType = COMPARISON_DIRECTION.GREATER) {
8544
+ if (comparisonType === COMPARISON_DIRECTION.GREATER) {
8421
8545
  return linkCalculation.ef > restriction.ef ? linkCalculation : restriction;
8422
8546
  }
8423
- if (comparisonType === "less") {
8547
+ if (comparisonType === COMPARISON_DIRECTION.LESS) {
8424
8548
  return linkCalculation.ef < restriction.ef ? linkCalculation : restriction;
8425
8549
  }
8426
8550
  }
@@ -8440,7 +8564,7 @@ var ForwardPath = class extends generic_calculations_default {
8440
8564
  const comparisontype = [
8441
8565
  CONSTRAINT_TYPES.SNET,
8442
8566
  CONSTRAINT_TYPES.FNET
8443
- ].includes(constraintType) ? "greater" : "less";
8567
+ ].includes(constraintType) ? COMPARISON_DIRECTION.GREATER : COMPARISON_DIRECTION.LESS;
8444
8568
  const { es, ef } = this.getTheGreatesDateBetweenRestrictionAndEsEf(
8445
8569
  calculatedRestriction,
8446
8570
  calculatedEsEf,
@@ -8456,9 +8580,9 @@ var ForwardPath = class extends generic_calculations_default {
8456
8580
  }
8457
8581
  const sourceId = ganttActivityLink.source;
8458
8582
  const targetId = ganttActivityLink.target;
8459
- if (!this.gantt.getTask(sourceId) || this.gantt.getTask(sourceId)?.type === "project")
8583
+ if (!this.gantt.getTask(sourceId) || this.gantt.getTask(sourceId)?.type === ACTIVITY_TYPE.PROJECT)
8460
8584
  return;
8461
- if (!this.gantt.getTask(targetId) || this.gantt.getTask(targetId)?.type === "project")
8585
+ if (!this.gantt.getTask(targetId) || this.gantt.getTask(targetId)?.type === ACTIVITY_TYPE.PROJECT)
8462
8586
  return;
8463
8587
  return link;
8464
8588
  }).filter(Boolean);
@@ -8481,7 +8605,7 @@ var CalculationsGenericMethods = class {
8481
8605
  }
8482
8606
  return this.calculatedActivities.get(activity);
8483
8607
  }
8484
- calculateSuccessorTimes(sucessorTime, lsDataCalculation, lfDataCalculation = 0, lag, type = LINK_TYPES2.FS) {
8608
+ calculateSuccessorTimes(sucessorTime, lsDataCalculation, lfDataCalculation = 0, lag, type = LINK_TYPES3.FS) {
8485
8609
  let activityCalendar = this.gantt.getCalendar(this.activity.calendar_id);
8486
8610
  if (!activityCalendar) {
8487
8611
  throw new Error(
@@ -8489,7 +8613,7 @@ var CalculationsGenericMethods = class {
8489
8613
  );
8490
8614
  }
8491
8615
  const workTime = sucessorTime;
8492
- let isMilestone = this.activity.type === "milestone";
8616
+ let isMilestone = this.activity.type === ACTIVITY_TYPE.MILESTONE;
8493
8617
  if (isMilestone && lag === 0) {
8494
8618
  let lsPred = addDurationToDate(
8495
8619
  activityCalendar,
@@ -8513,19 +8637,19 @@ var CalculationsGenericMethods = class {
8513
8637
  lfDataCalculation,
8514
8638
  isMilestone
8515
8639
  };
8516
- if (type === LINK_TYPES2.FS) {
8640
+ if (type === LINK_TYPES3.FS) {
8517
8641
  let { ls, lf } = this.calculateFsLink(valuesToDoCalculation);
8518
8642
  return { ls, lf };
8519
8643
  }
8520
- if (type === LINK_TYPES2.FF) {
8644
+ if (type === LINK_TYPES3.FF) {
8521
8645
  let { ls, lf } = this.calculateFFLink(valuesToDoCalculation);
8522
8646
  return { ls, lf };
8523
8647
  }
8524
- if (type === LINK_TYPES2.SS) {
8648
+ if (type === LINK_TYPES3.SS) {
8525
8649
  let { ls, lf } = this.calculateSSlink(valuesToDoCalculation);
8526
8650
  return { ls, lf };
8527
8651
  }
8528
- if (type === LINK_TYPES2.SF) {
8652
+ if (type === LINK_TYPES3.SF) {
8529
8653
  let { ls, lf } = this.calculateSFLink(valuesToDoCalculation);
8530
8654
  return { ls, lf };
8531
8655
  }
@@ -8540,7 +8664,7 @@ var CalculationsGenericMethods = class {
8540
8664
  lsDataForCalculation,
8541
8665
  lfDataForCalculation,
8542
8666
  lag,
8543
- LINK_TYPES2.SS
8667
+ LINK_TYPES3.SS
8544
8668
  );
8545
8669
  }
8546
8670
  calculateFF(link, constraint) {
@@ -8557,7 +8681,7 @@ var CalculationsGenericMethods = class {
8557
8681
  lsDataForCalculation,
8558
8682
  lfDataForCalculation,
8559
8683
  lag,
8560
- LINK_TYPES2.FF
8684
+ LINK_TYPES3.FF
8561
8685
  );
8562
8686
  }
8563
8687
  calculateFS(link, constraint) {
@@ -8575,7 +8699,7 @@ var CalculationsGenericMethods = class {
8575
8699
  lsDataForCalculation,
8576
8700
  lfDataForCalculation,
8577
8701
  lag,
8578
- LINK_TYPES2.FS
8702
+ LINK_TYPES3.FS
8579
8703
  );
8580
8704
  }
8581
8705
  calculateSF(link, getFromForward = false) {
@@ -8588,7 +8712,7 @@ var CalculationsGenericMethods = class {
8588
8712
  lsDataForCalculation,
8589
8713
  lfDataForCalculation,
8590
8714
  lag,
8591
- LINK_TYPES2.SF
8715
+ LINK_TYPES3.SF
8592
8716
  );
8593
8717
  }
8594
8718
  getEarlyStartFromForwardPath(link) {
@@ -8611,10 +8735,10 @@ var CalculationsGenericMethods = class {
8611
8735
  this.activity
8612
8736
  );
8613
8737
  }
8614
- getLastWorkingHour(date2, activityCalendar, dir = "past") {
8738
+ getLastWorkingHour(date2, activityCalendar, dir = WORK_TIME_DIRECTION.PAST) {
8615
8739
  const normalizedDate = date2 instanceof Date ? date2 : new Date(date2);
8616
8740
  let resetedDate = moment_default(normalizedDate).clone();
8617
- if (this.isActivityInInitHour(activityCalendar, normalizedDate) && dir === "past") {
8741
+ if (this.isActivityInInitHour(activityCalendar, normalizedDate) && dir === WORK_TIME_DIRECTION.PAST) {
8618
8742
  resetedDate = resetedDate.hours(0).minutes(0).seconds(0).milliseconds(0);
8619
8743
  }
8620
8744
  let newDate = getNextWorkingHour({
@@ -8657,7 +8781,7 @@ var CalculationsGenericMethods = class {
8657
8781
  const lsSucessor2 = this.getLastWorkingHour(
8658
8782
  workTime,
8659
8783
  activityCalendar,
8660
- "past"
8784
+ WORK_TIME_DIRECTION.PAST
8661
8785
  );
8662
8786
  lfPred = addDurationToDate(
8663
8787
  activityCalendar,
@@ -8665,7 +8789,7 @@ var CalculationsGenericMethods = class {
8665
8789
  lfDataCalculation,
8666
8790
  this.activity
8667
8791
  );
8668
- lfPred = this.getLastWorkingHour(lfPred, activityCalendar, "past");
8792
+ lfPred = this.getLastWorkingHour(lfPred, activityCalendar, WORK_TIME_DIRECTION.PAST);
8669
8793
  lsPred = addDurationToDate(
8670
8794
  activityCalendar,
8671
8795
  lfPred,
@@ -8691,7 +8815,7 @@ var CalculationsGenericMethods = class {
8691
8815
  this.activity
8692
8816
  );
8693
8817
  if (!isMilestone) {
8694
- lfPred = this.getLastWorkingHour(lfPred, activityCalendar, "past", true);
8818
+ lfPred = this.getLastWorkingHour(lfPred, activityCalendar, WORK_TIME_DIRECTION.PAST, true);
8695
8819
  }
8696
8820
  return { ls: lsPred, lf: lfPred };
8697
8821
  }
@@ -8724,7 +8848,7 @@ var CalculationsGenericMethods = class {
8724
8848
  lfSucessor = this.getLastWorkingHour(
8725
8849
  lfSucessor,
8726
8850
  activityCalendar,
8727
- "past"
8851
+ WORK_TIME_DIRECTION.PAST
8728
8852
  );
8729
8853
  }
8730
8854
  lfPred = addDurationToDate(
@@ -8838,7 +8962,7 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
8838
8962
  if (this.links.length === 0) {
8839
8963
  return new generic_calculations_default(
8840
8964
  this.gantt,
8841
- "backward"
8965
+ CALCULATION_DIRECTION.BACKWARD
8842
8966
  ).calculateStartAndFinishOfChainOrigin(this.activity);
8843
8967
  }
8844
8968
  let activityProgressMajorThanZeroButLessThanOneHundred = this.activity.progress > 0 && this.activity.progress < 100;
@@ -8950,7 +9074,7 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
8950
9074
  if (!activityFromLink) {
8951
9075
  return;
8952
9076
  }
8953
- if (activityFromLink.progress > 0 && activityFromLink.type !== "project") {
9077
+ if (activityFromLink.progress > 0 && activityFromLink.type !== ACTIVITY_TYPE.PROJECT) {
8954
9078
  return;
8955
9079
  }
8956
9080
  const specialParamForFS = this.getSpecialCalculationParamForConstraintLink();
@@ -9083,7 +9207,7 @@ var restrictionCalculation_default2 = calculateRestriction3;
9083
9207
  // src/critical-path/legacy/backward-path/index.js
9084
9208
  var BackwardPath = class extends generic_calculations_default {
9085
9209
  constructor(ganttInstance, forwardPathCalculations, forwardConstraintsMap) {
9086
- super(ganttInstance, "backward");
9210
+ super(ganttInstance, CALCULATION_DIRECTION.BACKWARD);
9087
9211
  this.gantt = ganttInstance;
9088
9212
  this.chainStartActivities = /* @__PURE__ */ new Set();
9089
9213
  this.secondLevelActivities = /* @__PURE__ */ new Set();
@@ -9202,7 +9326,7 @@ var BackwardPath = class extends generic_calculations_default {
9202
9326
  activityReference
9203
9327
  );
9204
9328
  }
9205
- if (activityReference.type === "project") {
9329
+ if (activityReference.type === ACTIVITY_TYPE.PROJECT) {
9206
9330
  return this.doCalculationForParentType(activityReference);
9207
9331
  }
9208
9332
  if (progress === 100) {
@@ -9283,7 +9407,7 @@ var BackwardPath = class extends generic_calculations_default {
9283
9407
  if (!activityData) {
9284
9408
  continue;
9285
9409
  }
9286
- if (activityData.type === "project") {
9410
+ if (activityData.type === ACTIVITY_TYPE.PROJECT) {
9287
9411
  allLinkedHasProgress = false;
9288
9412
  }
9289
9413
  if (activityData.progress === 0) {
@@ -9302,7 +9426,7 @@ var BackwardPath = class extends generic_calculations_default {
9302
9426
  const parent = Number(activity.parent);
9303
9427
  let { ls, lf } = this.calculateStartAndFinishOfChainOrigin(
9304
9428
  activity,
9305
- "backward"
9429
+ CALCULATION_DIRECTION.BACKWARD
9306
9430
  );
9307
9431
  if (this.calculationsOfParentThatImpactChildrens.has(parent)) {
9308
9432
  ls = activity.start_date;
@@ -9371,9 +9495,9 @@ var BackwardPath = class extends generic_calculations_default {
9371
9495
  return links.map((link) => {
9372
9496
  let sourceId = this.gantt.getLink(link).source;
9373
9497
  let targetId = this.gantt.getLink(link).target;
9374
- if (!this.gantt.getTask(sourceId) || this.gantt.getTask(sourceId)?.type === "project")
9498
+ if (!this.gantt.getTask(sourceId) || this.gantt.getTask(sourceId)?.type === ACTIVITY_TYPE.PROJECT)
9375
9499
  return;
9376
- if (!this.gantt.getTask(targetId) || this.gantt.getTask(targetId)?.type === "project")
9500
+ if (!this.gantt.getTask(targetId) || this.gantt.getTask(targetId)?.type === ACTIVITY_TYPE.PROJECT)
9377
9501
  return;
9378
9502
  return link;
9379
9503
  }).filter(Boolean);
@@ -10075,7 +10199,7 @@ var CriticalPath = class {
10075
10199
  var legacy_default = CriticalPath;
10076
10200
 
10077
10201
  // src/critical-path/gantt-adapter.ts
10078
- var isFinishConstraint = (type) => type === "fnet" || type === "fnlt" || type === "mfo";
10202
+ var isFinishConstraint = (type) => type === CONSTRAINT_TYPE.FNET || type === CONSTRAINT_TYPE.FNLT || type === CONSTRAINT_TYPE.MFO;
10079
10203
  var startOfUtcDay3 = (date2) => new Date(
10080
10204
  Date.UTC(date2.getUTCFullYear(), date2.getUTCMonth(), date2.getUTCDate())
10081
10205
  );
@@ -10557,38 +10681,38 @@ var NON_SCHEDULING_INLINE_COLUMNS = /* @__PURE__ */ new Set([
10557
10681
  COLUMN.TAGS
10558
10682
  ]);
10559
10683
  var NON_SCHEDULING_KINDS = /* @__PURE__ */ new Set([
10560
- "activity-clipboard-clear",
10561
- "activity-copy",
10562
- "selection-toggle",
10563
- "selection-replace",
10564
- "visibility-set",
10565
- "filter-set",
10566
- "sort-set",
10567
- "sir-sync",
10568
- "activity-lookahead-sync",
10569
- "persistence-acknowledge",
10570
- "baseline-apply",
10571
- "ponderator-criterion-set",
10572
- "status-criteria-set"
10684
+ DISPATCH_ACTION_KIND.ACTIVITY_CLIPBOARD_CLEAR,
10685
+ DISPATCH_ACTION_KIND.ACTIVITY_COPY,
10686
+ DISPATCH_ACTION_KIND.SELECTION_TOGGLE,
10687
+ DISPATCH_ACTION_KIND.SELECTION_REPLACE,
10688
+ DISPATCH_ACTION_KIND.VISIBILITY_SET,
10689
+ DISPATCH_ACTION_KIND.FILTER_SET,
10690
+ DISPATCH_ACTION_KIND.SORT_SET,
10691
+ DISPATCH_ACTION_KIND.SIR_SYNC,
10692
+ DISPATCH_ACTION_KIND.ACTIVITY_LOOKAHEAD_SYNC,
10693
+ DISPATCH_ACTION_KIND.PERSISTENCE_ACKNOWLEDGE,
10694
+ DISPATCH_ACTION_KIND.BASELINE_APPLY,
10695
+ DISPATCH_ACTION_KIND.PONDERATOR_CRITERION_SET,
10696
+ DISPATCH_ACTION_KIND.STATUS_CRITERIA_SET
10573
10697
  ]);
10574
10698
  var PURE_VIEW_STATE_KINDS = /* @__PURE__ */ new Set([
10575
- "activity-clipboard-clear",
10576
- "activity-copy",
10577
- "selection-toggle",
10578
- "selection-replace",
10579
- "visibility-set",
10580
- "filter-set",
10581
- "sort-set"
10699
+ DISPATCH_ACTION_KIND.ACTIVITY_CLIPBOARD_CLEAR,
10700
+ DISPATCH_ACTION_KIND.ACTIVITY_COPY,
10701
+ DISPATCH_ACTION_KIND.SELECTION_TOGGLE,
10702
+ DISPATCH_ACTION_KIND.SELECTION_REPLACE,
10703
+ DISPATCH_ACTION_KIND.VISIBILITY_SET,
10704
+ DISPATCH_ACTION_KIND.FILTER_SET,
10705
+ DISPATCH_ACTION_KIND.SORT_SET
10582
10706
  ]);
10583
10707
  function reappliesViewState(action) {
10584
10708
  return !PURE_VIEW_STATE_KINDS.has(action.kind);
10585
10709
  }
10586
10710
  var NO_STRUCTURAL_EXEMPTIONS = /* @__PURE__ */ new Set();
10587
10711
  function editsOnlyNonSchedulingColumns(action) {
10588
- if (action.kind === "inline-edit") {
10712
+ if (action.kind === DISPATCH_ACTION_KIND.INLINE_EDIT) {
10589
10713
  return NON_SCHEDULING_INLINE_COLUMNS.has(action.column);
10590
10714
  }
10591
- if (action.kind === "bulk-edit") {
10715
+ if (action.kind === DISPATCH_ACTION_KIND.BULK_EDIT) {
10592
10716
  return action.edits.every(
10593
10717
  (edit) => NON_SCHEDULING_INLINE_COLUMNS.has(edit.column)
10594
10718
  );
@@ -10602,13 +10726,13 @@ function isSchedulingDispatch(action, structuralStaleKinds) {
10602
10726
  return true;
10603
10727
  }
10604
10728
  function dispatchChangesSchedulingState(action) {
10605
- if (action.kind === "activity-lookahead-sync") {
10729
+ if (action.kind === DISPATCH_ACTION_KIND.ACTIVITY_LOOKAHEAD_SYNC) {
10606
10730
  return action.persistedProgress !== void 0;
10607
10731
  }
10608
10732
  return isSchedulingDispatch(action, NO_STRUCTURAL_EXEMPTIONS);
10609
10733
  }
10610
10734
  function resolveRunCriticalPath(action) {
10611
- if (action.kind === "activity-lookahead-sync") {
10735
+ if (action.kind === DISPATCH_ACTION_KIND.ACTIVITY_LOOKAHEAD_SYNC) {
10612
10736
  return action.persistedProgress !== void 0;
10613
10737
  }
10614
10738
  return isSchedulingDispatch(
@@ -10623,9 +10747,11 @@ function resolveRunExpectedProgress(action) {
10623
10747
  );
10624
10748
  }
10625
10749
  function dispatchChangesProgress(action) {
10626
- if (action.kind === "activity-set-progress") return true;
10627
- if (action.kind === "inline-edit") return action.column === COLUMN.PROGRESS;
10628
- if (action.kind === "bulk-edit") {
10750
+ if (action.kind === DISPATCH_ACTION_KIND.ACTIVITY_SET_PROGRESS) return true;
10751
+ if (action.kind === DISPATCH_ACTION_KIND.INLINE_EDIT) {
10752
+ return action.column === COLUMN.PROGRESS;
10753
+ }
10754
+ if (action.kind === DISPATCH_ACTION_KIND.BULK_EDIT) {
10629
10755
  return action.edits.some((edit) => edit.column === COLUMN.PROGRESS);
10630
10756
  }
10631
10757
  return false;
@@ -10642,11 +10768,11 @@ var PROGRESS_AFFECTING_COLUMNS = /* @__PURE__ */ new Set([
10642
10768
  COLUMN.REAL_COST
10643
10769
  ]);
10644
10770
  function shouldRecomputeParentProgress(action) {
10645
- if (action.kind === "activity-set-progress") return true;
10646
- if (action.kind === "inline-edit") {
10771
+ if (action.kind === DISPATCH_ACTION_KIND.ACTIVITY_SET_PROGRESS) return true;
10772
+ if (action.kind === DISPATCH_ACTION_KIND.INLINE_EDIT) {
10647
10773
  return PROGRESS_AFFECTING_COLUMNS.has(action.column);
10648
10774
  }
10649
- if (action.kind === "bulk-edit") {
10775
+ if (action.kind === DISPATCH_ACTION_KIND.BULK_EDIT) {
10650
10776
  return action.edits.some(
10651
10777
  (edit) => PROGRESS_AFFECTING_COLUMNS.has(edit.column)
10652
10778
  );
@@ -10682,7 +10808,103 @@ function resolveDerivedPasses(action, autoSchedule, options) {
10682
10808
  return passes;
10683
10809
  }
10684
10810
 
10811
+ // src/internal/state/write-capture.ts
10812
+ var WRITE_OPERATION_KIND = {
10813
+ INSERT: "insert",
10814
+ REMOVE: "remove",
10815
+ LINK_ADD: "link-add",
10816
+ LINK_REMOVE: "link-remove",
10817
+ LINK_FIELD: "link-field"
10818
+ };
10819
+ var WriteCapture = class {
10820
+ _journal = null;
10821
+ begin() {
10822
+ this._journal = {
10823
+ dirty: /* @__PURE__ */ new Set(),
10824
+ before: /* @__PURE__ */ new Map(),
10825
+ ops: [],
10826
+ linkFieldCaptured: /* @__PURE__ */ new Set(),
10827
+ correlativeBefore: /* @__PURE__ */ new Map(),
10828
+ scheduledBefore: /* @__PURE__ */ new Map(),
10829
+ progressFallbackBefore: /* @__PURE__ */ new Map()
10830
+ };
10831
+ }
10832
+ peek() {
10833
+ return this._journal;
10834
+ }
10835
+ end() {
10836
+ this._journal = null;
10837
+ }
10838
+ note(key, current) {
10839
+ const journal = this._journal;
10840
+ if (!journal) return;
10841
+ if (!journal.before.has(key))
10842
+ journal.before.set(key, cloneCoreActivity(current));
10843
+ journal.dirty.add(key);
10844
+ }
10845
+ noteInsert(activityId) {
10846
+ this._journal?.ops.push({ kind: WRITE_OPERATION_KIND.INSERT, activityId });
10847
+ }
10848
+ noteRemove(activityId, current) {
10849
+ this._journal?.ops.push({
10850
+ kind: WRITE_OPERATION_KIND.REMOVE,
10851
+ activityId,
10852
+ before: cloneCoreActivity(current)
10853
+ });
10854
+ }
10855
+ noteLinkAdd(linkId) {
10856
+ this._journal?.ops.push({ kind: WRITE_OPERATION_KIND.LINK_ADD, linkId });
10857
+ }
10858
+ noteLinkRemove(linkId, current) {
10859
+ this._journal?.ops.push({
10860
+ kind: WRITE_OPERATION_KIND.LINK_REMOVE,
10861
+ linkId,
10862
+ before: cloneLink(current)
10863
+ });
10864
+ }
10865
+ noteCorrelativeBefore(activityId, before) {
10866
+ const journal = this._journal;
10867
+ if (!journal || journal.correlativeBefore.has(activityId)) return;
10868
+ const capturedBefore = journal.before.get(activityId)?.correlativeId;
10869
+ journal.correlativeBefore.set(
10870
+ activityId,
10871
+ typeof capturedBefore === "number" ? capturedBefore : before
10872
+ );
10873
+ }
10874
+ noteScheduledBefore(activityId, current) {
10875
+ const journal = this._journal;
10876
+ if (!journal) return;
10877
+ const beforeImage = cloneCoreActivity(current);
10878
+ if (!journal.scheduledBefore.has(activityId)) {
10879
+ journal.scheduledBefore.set(activityId, beforeImage);
10880
+ }
10881
+ if (!journal.before.has(activityId)) {
10882
+ journal.before.set(activityId, beforeImage);
10883
+ }
10884
+ journal.dirty.add(activityId);
10885
+ }
10886
+ noteLinkField(linkId, current) {
10887
+ const journal = this._journal;
10888
+ if (!journal || journal.linkFieldCaptured.has(linkId)) return;
10889
+ journal.linkFieldCaptured.add(linkId);
10890
+ journal.ops.push({
10891
+ kind: WRITE_OPERATION_KIND.LINK_FIELD,
10892
+ linkId,
10893
+ before: cloneLink(current)
10894
+ });
10895
+ }
10896
+ noteProgressFallback(activityId, current) {
10897
+ const journal = this._journal;
10898
+ if (!journal || journal.progressFallbackBefore.has(activityId)) return;
10899
+ journal.progressFallbackBefore.set(activityId, current);
10900
+ }
10901
+ };
10902
+ function cloneLink(link) {
10903
+ return { ...link };
10904
+ }
10905
+
10685
10906
  // src/dispatch/shared/post-mutation.ts
10907
+ var AUTOSCHEDULE_SCOPE = { ROOTS: "roots" };
10686
10908
  async function runPostMutation(deps, args) {
10687
10909
  const progressInvalidation = resolveProgressInvalidation(deps.adapter);
10688
10910
  const passes = resolvePasses(args, progressInvalidation);
@@ -10738,10 +10960,10 @@ function resolveProgressInvalidation(adapter) {
10738
10960
  }
10739
10961
  function collectStructuralProgressInvalidations(adapter, operations, affectParent) {
10740
10962
  for (const operation of operations) {
10741
- if (operation.kind === "insert") {
10963
+ if (operation.kind === WRITE_OPERATION_KIND.INSERT) {
10742
10964
  const inserted = adapter.getActivity(operation.activityId);
10743
10965
  if (inserted) affectParent(inserted.parentId);
10744
- } else if (operation.kind === "remove") {
10966
+ } else if (operation.kind === WRITE_OPERATION_KIND.REMOVE) {
10745
10967
  affectParent(operation.before.parentId);
10746
10968
  }
10747
10969
  }
@@ -10765,7 +10987,7 @@ function collectFieldProgressInvalidations(adapter, beforeById, dirtySeeds, affe
10765
10987
  }
10766
10988
  }
10767
10989
  async function runAutoschedule(deps, autoscheduleFrom, preventSummaryTargetPullback = false) {
10768
- const options = autoscheduleFrom === "roots" ? {} : { triggerId: autoscheduleFrom };
10990
+ const options = autoscheduleFrom === AUTOSCHEDULE_SCOPE.ROOTS ? {} : { triggerId: autoscheduleFrom };
10769
10991
  if (preventSummaryTargetPullback) {
10770
10992
  options.preventSummaryTargetPullback = true;
10771
10993
  }
@@ -10856,7 +11078,10 @@ var CONSTRAINT_EDIT_COLUMNS = /* @__PURE__ */ new Set([
10856
11078
  COLUMN.CONSTRAINT_TYPE,
10857
11079
  COLUMN.CONSTRAINT_DATE
10858
11080
  ]);
10859
- var MUST_CONSTRAINTS = /* @__PURE__ */ new Set(["mso", "mfo"]);
11081
+ var MUST_CONSTRAINTS = /* @__PURE__ */ new Set([
11082
+ CONSTRAINT_TYPE.MSO,
11083
+ CONSTRAINT_TYPE.MFO
11084
+ ]);
10860
11085
  function isConstraintEditColumn(column) {
10861
11086
  return CONSTRAINT_EDIT_COLUMNS.has(column);
10862
11087
  }
@@ -10987,6 +11212,10 @@ function snapshotToLink(l) {
10987
11212
  }
10988
11213
 
10989
11214
  // src/dispatch/shared/change-set.ts
11215
+ var SIR_DETECTION_PHASE = {
11216
+ BEFORE_DIFF: "before-diff",
11217
+ AFTER_DIFF: "after-diff"
11218
+ };
10990
11219
  async function assembleChangeSet(adapter, args) {
10991
11220
  const allTouched = collectChangeSetIds(adapter, args);
10992
11221
  const before = new Map(args.beforeSnap);
@@ -10996,7 +11225,7 @@ async function assembleChangeSet(adapter, args) {
10996
11225
  mergeDirtyBeforeImages(adapter, captured, insertedIds, before, allTouched);
10997
11226
  }
10998
11227
  const sirDetection = args.sirDetection;
10999
- const beforeDiffEffects = sirDetection === "before-diff" ? detectSirAutoReject(before, adapter, allTouched) : [];
11228
+ const beforeDiffEffects = sirDetection === SIR_DETECTION_PHASE.BEFORE_DIFF ? detectSirAutoReject(before, adapter, allTouched) : [];
11000
11229
  const correlativeBefore = buildCorrelativeBeforeMap(
11001
11230
  args.correlativeShifts,
11002
11231
  allTouched
@@ -11007,7 +11236,7 @@ async function assembleChangeSet(adapter, args) {
11007
11236
  allTouched,
11008
11237
  correlativeBefore
11009
11238
  );
11010
- const effects = sirDetection === "after-diff" ? detectSirAutoReject(before, adapter, allTouched) : beforeDiffEffects;
11239
+ const effects = sirDetection === SIR_DETECTION_PHASE.AFTER_DIFF ? detectSirAutoReject(before, adapter, allTouched) : beforeDiffEffects;
11011
11240
  const warnings = args.warnings ?? [];
11012
11241
  const linkChanges = mergeLinkChanges(
11013
11242
  args.links ?? [],
@@ -11026,7 +11255,7 @@ async function assembleChangeSet(adapter, args) {
11026
11255
  function buildCapturedCriticalPathLinkChanges(adapter, captured) {
11027
11256
  const changes = [];
11028
11257
  for (const operation of captured.ops) {
11029
- if (operation.kind !== "link-field") continue;
11258
+ if (operation.kind !== WRITE_OPERATION_KIND.LINK_FIELD) continue;
11030
11259
  const after = adapter.getLink(operation.linkId);
11031
11260
  if (!after) continue;
11032
11261
  const fields = {};
@@ -11041,7 +11270,7 @@ function buildCapturedCriticalPathLinkChanges(adapter, captured) {
11041
11270
  if (Object.keys(fields).length === 0) continue;
11042
11271
  changes.push({
11043
11272
  id: operation.linkId,
11044
- kind: "updated",
11273
+ kind: ENTITY_CHANGE_KIND.UPDATED,
11045
11274
  fields,
11046
11275
  after: snapshotToLink(after)
11047
11276
  });
@@ -11059,7 +11288,7 @@ function mergeLinkChanges(explicit, captured) {
11059
11288
  continue;
11060
11289
  }
11061
11290
  const current = merged[index];
11062
- if ((current.kind === "updated" || current.kind === "created") && change.kind === "updated") {
11291
+ if ((current.kind === ENTITY_CHANGE_KIND.UPDATED || current.kind === ENTITY_CHANGE_KIND.CREATED) && change.kind === ENTITY_CHANGE_KIND.UPDATED) {
11063
11292
  merged[index] = {
11064
11293
  ...current,
11065
11294
  fields: { ...current.fields, ...change.fields },
@@ -11077,8 +11306,8 @@ function mergeLinkChanges(explicit, captured) {
11077
11306
  continue;
11078
11307
  }
11079
11308
  const current = merged[index];
11080
- if (current.kind === "deleted") continue;
11081
- const capturedFields = current.kind === "created" ? Object.fromEntries(
11309
+ if (current.kind === ENTITY_CHANGE_KIND.DELETED) continue;
11310
+ const capturedFields = current.kind === ENTITY_CHANGE_KIND.CREATED ? Object.fromEntries(
11082
11311
  Object.entries(change.fields ?? {}).map(([field, value]) => [
11083
11312
  field,
11084
11313
  { before: void 0, after: value.after }
@@ -11123,7 +11352,7 @@ function mergeDirtyBeforeImages(adapter, captured, insertedIds, before, touched)
11123
11352
  }
11124
11353
  function collectInsertedIds(captured) {
11125
11354
  return new Set(
11126
- captured.ops.filter((operation) => operation.kind === "insert").map((operation) => operation.activityId)
11355
+ captured.ops.filter((operation) => operation.kind === WRITE_OPERATION_KIND.INSERT).map((operation) => operation.activityId)
11127
11356
  );
11128
11357
  }
11129
11358
 
@@ -11132,7 +11361,7 @@ function buildLinkChangesForBatch(applied, beforeLinks, adapter) {
11132
11361
  const out = [];
11133
11362
  for (const { op, finalLinkId, rejected } of applied) {
11134
11363
  if (rejected !== null) continue;
11135
- if (op.kind === "create") {
11364
+ if (op.kind === LINK_OPERATION_KIND.CREATE) {
11136
11365
  if (!finalLinkId) continue;
11137
11366
  const after = adapter.getLink(finalLinkId);
11138
11367
  if (!after) continue;
@@ -11163,7 +11392,7 @@ function buildLinkChangesForBatch(applied, beforeLinks, adapter) {
11163
11392
  if (Object.keys(fields2).length > 0) {
11164
11393
  out.push({
11165
11394
  id: String(finalLinkId),
11166
- kind: "updated",
11395
+ kind: ENTITY_CHANGE_KIND.UPDATED,
11167
11396
  fields: fields2,
11168
11397
  after: snapshotToLink(after)
11169
11398
  });
@@ -11172,7 +11401,7 @@ function buildLinkChangesForBatch(applied, beforeLinks, adapter) {
11172
11401
  }
11173
11402
  out.push({
11174
11403
  id: String(finalLinkId),
11175
- kind: "created",
11404
+ kind: ENTITY_CHANGE_KIND.CREATED,
11176
11405
  fields: {
11177
11406
  source: { before: void 0, after: String(after.source) },
11178
11407
  target: { before: void 0, after: String(after.target) },
@@ -11183,12 +11412,12 @@ function buildLinkChangesForBatch(applied, beforeLinks, adapter) {
11183
11412
  });
11184
11413
  continue;
11185
11414
  }
11186
- if (op.kind === "delete") {
11415
+ if (op.kind === LINK_OPERATION_KIND.DELETE) {
11187
11416
  if (adapter.getLink(op.linkId)) continue;
11188
11417
  const beforeLink2 = beforeLinks.get(op.linkId);
11189
11418
  out.push({
11190
11419
  id: String(op.linkId),
11191
- kind: "deleted",
11420
+ kind: ENTITY_CHANGE_KIND.DELETED,
11192
11421
  fields: beforeLink2 ? {
11193
11422
  source: { before: String(beforeLink2.source), after: void 0 },
11194
11423
  target: { before: String(beforeLink2.target), after: void 0 },
@@ -11214,7 +11443,7 @@ function buildLinkChangesForBatch(applied, beforeLinks, adapter) {
11214
11443
  }
11215
11444
  out.push({
11216
11445
  id: String(op.linkId),
11217
- kind: "updated",
11446
+ kind: ENTITY_CHANGE_KIND.UPDATED,
11218
11447
  fields,
11219
11448
  after: snapshotToLink(afterLink)
11220
11449
  });
@@ -11240,7 +11469,7 @@ function diffIncomingLinkLagChanges(beforeLags, adapter, activityId) {
11240
11469
  if (before === void 0 || before === Number(link.lag)) continue;
11241
11470
  out.push({
11242
11471
  id: String(link.id),
11243
- kind: "updated",
11472
+ kind: ENTITY_CHANGE_KIND.UPDATED,
11244
11473
  fields: {
11245
11474
  lag: {
11246
11475
  before,
@@ -11382,6 +11611,16 @@ async function dispatchInlineEdit(action, options, deps) {
11382
11611
  name: e.name,
11383
11612
  properties: e.properties ?? {}
11384
11613
  }));
11614
+ if (pipeline.trackEvent && !(action.column === COLUMN.PROGRESS && Number(parsed2.value) <= 0)) {
11615
+ trackingEvents.unshift({
11616
+ name: pipeline.trackEvent,
11617
+ properties: {
11618
+ activity_name: activitySnap.name,
11619
+ activity_id: activitySnap.id,
11620
+ activity_index: activitySnap.correlativeId
11621
+ }
11622
+ });
11623
+ }
11385
11624
  const constraintWarning = toConstraintWarning(
11386
11625
  action.activityId,
11387
11626
  changes.constraintWarning
@@ -11393,7 +11632,7 @@ async function dispatchInlineEdit(action, options, deps) {
11393
11632
  beforeSnap,
11394
11633
  touchedIds,
11395
11634
  scheduledIds,
11396
- sirDetection: "before-diff",
11635
+ sirDetection: SIR_DETECTION_PHASE.BEFORE_DIFF,
11397
11636
  links: linkChanges,
11398
11637
  trackingEvents,
11399
11638
  ...constraintWarning ? { warnings: [constraintWarning] } : {},
@@ -11403,9 +11642,8 @@ async function dispatchInlineEdit(action, options, deps) {
11403
11642
  }
11404
11643
 
11405
11644
  // src/dispatch/handlers/link.ts
11406
- var LINK_TYPE_VALUES = new Set(Object.values(LINK_TYPE));
11407
11645
  function isValidLinkType(value) {
11408
- return typeof value === "string" && LINK_TYPE_VALUES.has(value);
11646
+ return isLinkType(value);
11409
11647
  }
11410
11648
  function hasOwn(value, property) {
11411
11649
  return Object.hasOwn(value, property);
@@ -11618,7 +11856,7 @@ function pickAutoscheduleTrigger(applied, beforeLinks, adapter) {
11618
11856
  if (operation.rejected !== null) continue;
11619
11857
  const target = autoscheduleTarget(operation.op, beforeLinks, adapter);
11620
11858
  if (target !== null)
11621
- return adapter.hasChildren(target) ? "roots" : String(target);
11859
+ return adapter.hasChildren(target) ? AUTOSCHEDULE_SCOPE.ROOTS : String(target);
11622
11860
  }
11623
11861
  return null;
11624
11862
  }
@@ -11664,7 +11902,13 @@ async function dispatchInlineEditLinks(action, options, deps) {
11664
11902
  return { ok: false, reason: REJECTION_REASON.ACTIVITY_NOT_FOUND };
11665
11903
  }
11666
11904
  const isPredecessors = action.column === COLUMN.CUSTOM_PREDECESSORS;
11667
- const { specs: specsInDays } = parsePredecessorString(action.newValue);
11905
+ const { specs: specsInDays, errors } = parsePredecessorString(
11906
+ action.newValue,
11907
+ { daysPerWeek: sector.hoursPerWeek / sector.hoursPerDay }
11908
+ );
11909
+ if (errors.length > 0) {
11910
+ return { ok: false, reason: REJECTION_REASON.INVALID_VALUE };
11911
+ }
11668
11912
  const specs = specsInDays.map((spec) => ({
11669
11913
  ...spec,
11670
11914
  lag: lagDaysToHours(roundLagDays(spec.lag), sector.hoursPerDay)
@@ -11896,9 +12140,9 @@ function readNumber3(activity, key) {
11896
12140
  var NEW_ACTIVITY_DEFAULTS = Object.freeze({
11897
12141
  proplannerId: null,
11898
12142
  description: "",
11899
- type: "task",
12143
+ type: ACTIVITY_TYPE.TASK,
11900
12144
  progress: 0,
11901
- constraintType: "asap",
12145
+ constraintType: CONSTRAINT_TYPE.ASAP,
11902
12146
  constraintDate: null,
11903
12147
  autoScheduling: true,
11904
12148
  assignedDefaultCalendar: false,
@@ -12051,9 +12295,15 @@ function resolveStartDate(parent, fallback, override) {
12051
12295
  }
12052
12296
 
12053
12297
  // src/creation/parent-mutation-pipeline.ts
12298
+ var PARENT_MUTATION_SOURCE = {
12299
+ CREATE: "create",
12300
+ REPARENT: "reparent"
12301
+ };
12054
12302
  function snapshotOf(parent) {
12055
12303
  const type = parent.type;
12056
- if (type !== "task" && type !== "milestone") return null;
12304
+ if (type !== ACTIVITY_TYPE.TASK && type !== ACTIVITY_TYPE.MILESTONE) {
12305
+ return null;
12306
+ }
12057
12307
  const startDate = parent.startDate;
12058
12308
  const endDate = parent.endDate;
12059
12309
  if (!(startDate instanceof Date) || !(endDate instanceof Date)) return null;
@@ -12086,7 +12336,7 @@ function buildParentMutations(input) {
12086
12336
  }
12087
12337
  if (wasPromotableLeaf) {
12088
12338
  fields.type = PROMOTION_TARGET_TYPE;
12089
- if ((input.promotionSource ?? "create") === "create") {
12339
+ if ((input.promotionSource ?? PARENT_MUTATION_SOURCE.CREATE) === PARENT_MUTATION_SOURCE.CREATE) {
12090
12340
  fields.constraintType = CONSTRAINT_TYPE.ASAP;
12091
12341
  fields.constraintDate = null;
12092
12342
  }
@@ -12187,7 +12437,9 @@ function computeFractionalCidAtIndex(adapter, parentKey, targetIndex, excludeId)
12187
12437
 
12188
12438
  // src/dispatch/creation-overrides.ts
12189
12439
  var PUBLIC_CREATION_OVERRIDE_FIELDS = /* @__PURE__ */ new Set([
12190
- ...[...CREATION_OVERRIDE_FIELDS].filter((field) => field !== "durationHours"),
12440
+ ...[...CREATION_OVERRIDE_FIELDS].filter(
12441
+ (field) => field !== ACTIVITY_PROPERTY.DURATION_HOURS
12442
+ ),
12191
12443
  "durationDays"
12192
12444
  ]);
12193
12445
  function normalizeActivityCreationOverrides(raw, hoursPerDay) {
@@ -12209,7 +12461,7 @@ function normalizeActivityCreationOverrides(raw, hoursPerDay) {
12209
12461
  ok: true,
12210
12462
  value: {
12211
12463
  ...rest,
12212
- ...durationDays === 0 && (rest.type === void 0 || rest.type === "task") ? { type: "milestone" } : {},
12464
+ ...durationDays === 0 && (rest.type === void 0 || rest.type === ACTIVITY_TYPE.TASK) ? { type: ACTIVITY_TYPE.MILESTONE } : {},
12213
12465
  ...durationDays === void 0 ? {} : { durationHours: durationToHours(durationDays, hoursPerDay) }
12214
12466
  }
12215
12467
  };
@@ -12540,7 +12792,7 @@ function buildParentDemotionMutations(input) {
12540
12792
  durationHours: canonicalDuration,
12541
12793
  progress: 0,
12542
12794
  autoScheduling: true,
12543
- constraintType: "asap",
12795
+ constraintType: CONSTRAINT_TYPE.ASAP,
12544
12796
  constraintDate: null,
12545
12797
  hasNewActivities: false,
12546
12798
  ...canonicalEndDateField(
@@ -12692,7 +12944,7 @@ async function dispatchActivityDelete(action, options, deps) {
12692
12944
  },
12693
12945
  {
12694
12946
  action,
12695
- autoscheduleFrom: "roots",
12947
+ autoscheduleFrom: AUTOSCHEDULE_SCOPE.ROOTS,
12696
12948
  recomputeParentsFrom: parentsToCheck,
12697
12949
  now: deps.now,
12698
12950
  options
@@ -12720,7 +12972,7 @@ async function dispatchActivityDelete(action, options, deps) {
12720
12972
  beforeSnap,
12721
12973
  touchedIds,
12722
12974
  scheduledIds,
12723
- sirDetection: "after-diff",
12975
+ sirDetection: SIR_DETECTION_PHASE.AFTER_DIFF,
12724
12976
  links: buildLinkDeletions(beforeLinks),
12725
12977
  trackingEvents: [trackingEvent],
12726
12978
  hoursPerDay: sector.hoursPerDay,
@@ -12759,7 +13011,7 @@ function buildLinkDeletions(beforeLinks) {
12759
13011
  for (const [id, before] of beforeLinks.entries()) {
12760
13012
  out.push({
12761
13013
  id,
12762
- kind: "deleted",
13014
+ kind: ENTITY_CHANGE_KIND.DELETED,
12763
13015
  fields: {
12764
13016
  source: { before: String(before.source), after: void 0 },
12765
13017
  target: { before: String(before.target), after: void 0 },
@@ -12867,7 +13119,7 @@ async function dispatchActivityBatch(action, options, deps) {
12867
13119
  },
12868
13120
  {
12869
13121
  action,
12870
- autoscheduleFrom: action.items.length > 0 || action.links.length > 0 ? "roots" : null,
13122
+ autoscheduleFrom: action.items.length > 0 || action.links.length > 0 ? AUTOSCHEDULE_SCOPE.ROOTS : null,
12871
13123
  recomputeParentsFrom: createdIds,
12872
13124
  now: deps.now,
12873
13125
  options
@@ -12881,7 +13133,7 @@ async function dispatchActivityBatch(action, options, deps) {
12881
13133
  links: buildLinkChangesForBatch(appliedLinks, beforeLinks, deps.adapter),
12882
13134
  hoursPerDay: deps.sector.hoursPerDay,
12883
13135
  correlativeShifts: existingCorrelativeShifts,
12884
- ...action.mode === ACTIVITY_BATCH_MODE.REPLACE ? { sirDetection: "after-diff" } : {}
13136
+ ...action.mode === ACTIVITY_BATCH_MODE.REPLACE ? { sirDetection: SIR_DETECTION_PHASE.AFTER_DIFF } : {}
12885
13137
  });
12886
13138
  return {
12887
13139
  ok: true,
@@ -13240,7 +13492,7 @@ function dispatchSirSync(action, deps) {
13240
13492
  }
13241
13493
  const change = {
13242
13494
  id,
13243
- kind: "updated",
13495
+ kind: ENTITY_CHANGE_KIND.UPDATED,
13244
13496
  fields: { pendingRequestIds: { before, after } },
13245
13497
  after: structuredCloneActivity(updated)
13246
13498
  };
@@ -13416,7 +13668,7 @@ async function dispatchPersistenceAcknowledge(action, deps) {
13416
13668
  );
13417
13669
  activityChanges.push({
13418
13670
  id: assignment.id,
13419
- kind: "updated",
13671
+ kind: ENTITY_CHANGE_KIND.UPDATED,
13420
13672
  fields: {
13421
13673
  proplannerId: {
13422
13674
  before: previousProplannerId,
@@ -13433,7 +13685,7 @@ async function dispatchPersistenceAcknowledge(action, deps) {
13433
13685
  deps.adapter.setLinkProplannerId(assignment.id, assignment.proplannerId);
13434
13686
  linkChanges.push({
13435
13687
  id: assignment.id,
13436
- kind: "updated",
13688
+ kind: ENTITY_CHANGE_KIND.UPDATED,
13437
13689
  fields: {
13438
13690
  proplannerId: {
13439
13691
  before: previousProplannerId,
@@ -13496,7 +13748,7 @@ async function dispatchActivityLookaheadSync(action, options, deps) {
13496
13748
  if (Object.keys(fields).length === 0) continue;
13497
13749
  activities.push({
13498
13750
  id,
13499
- kind: "updated",
13751
+ kind: ENTITY_CHANGE_KIND.UPDATED,
13500
13752
  fields,
13501
13753
  after: {
13502
13754
  ...snapshot,
@@ -13554,6 +13806,285 @@ function hasInvalidPersistedProgress(action) {
13554
13806
  return progress !== void 0 && (action.activityIds.length !== 1 || !Number.isFinite(progress) || progress < 0 || progress > 100);
13555
13807
  }
13556
13808
 
13809
+ // src/dispatch/handlers/activity-lookahead-convert.ts
13810
+ function buildLookaheadConversionPlan(input, deps) {
13811
+ const { adapter } = deps;
13812
+ const requested = new Set(
13813
+ input.conversionRootIds.map((id) => String(id))
13814
+ );
13815
+ if (requested.size === 0) {
13816
+ throw new Error("Conversion requires at least one root");
13817
+ }
13818
+ for (const rootId of requested) validateRequestedRoot(rootId, adapter);
13819
+ const conversionRootIds = adapter.getVisualOrderIds().filter(
13820
+ (activityId) => requested.has(activityId) && !hasAncestorInSet(activityId, requested, adapter)
13821
+ );
13822
+ const branches = conversionRootIds.map(
13823
+ (rootId) => planConversionBranch(rootId, adapter)
13824
+ );
13825
+ const conversionGroups = branches.map(
13826
+ ({ conversionRootId, convertedActivities }) => ({
13827
+ conversionRootId,
13828
+ convertedActivities
13829
+ })
13830
+ );
13831
+ const milestoneMoves = branches.flatMap((branch) => branch.milestoneMoves);
13832
+ const activityIdsToDelete = branches.flatMap(
13833
+ (branch) => branch.activityIdsToDelete
13834
+ );
13835
+ const formerParents = branches.map((branch) => branch.formerParent);
13836
+ const idsToDelete = new Set(activityIdsToDelete);
13837
+ const linkIdsToDelete = collectIncidentLinkIds(idsToDelete, adapter);
13838
+ return {
13839
+ sourceStateRevision: deps.stateRevision,
13840
+ conversionRootIds,
13841
+ conversionGroups,
13842
+ milestoneMoves,
13843
+ activityIdsToDelete,
13844
+ linkIdsToDelete,
13845
+ formerParents
13846
+ };
13847
+ }
13848
+ async function dispatchActivityLookaheadConvert(action, options, deps) {
13849
+ if (action.expectedStateRevision !== deps.stateRevision) {
13850
+ return { ok: false, reason: REJECTION_REASON.STALE_STATE_REVISION };
13851
+ }
13852
+ const plan = buildLookaheadConversionPlan(action, deps);
13853
+ if (!conversionTopologyIsValid(plan, deps.adapter)) {
13854
+ return { ok: false, reason: REJECTION_REASON.HIERARCHY_CYCLE };
13855
+ }
13856
+ const { adapter, scheduler } = deps;
13857
+ scheduler.invalidateAllCaches();
13858
+ const context = await captureConversionMutationContext(plan, adapter);
13859
+ releaseDeletedCustomIds(plan, deps);
13860
+ applyConversionStructure(plan, adapter);
13861
+ applyFormerParentState(plan, context.deletedIds, adapter);
13862
+ const correlativeShifts = recomputeConversionRollups(plan, adapter);
13863
+ foldCorrelativeShifts(
13864
+ adapter,
13865
+ correlativeShifts,
13866
+ context.deletedIds,
13867
+ context.beforeSnap,
13868
+ context.touchedIds
13869
+ );
13870
+ const { scheduledIds } = await runPostMutation(
13871
+ {
13872
+ adapter,
13873
+ scheduler,
13874
+ sector: deps.sector,
13875
+ defaultBaseCalendarId: deps.defaultBaseCalendarId
13876
+ },
13877
+ {
13878
+ action,
13879
+ autoscheduleFrom: "roots",
13880
+ recomputeParentsFrom: context.touchedIds,
13881
+ now: deps.now,
13882
+ options,
13883
+ recomputeParentProgress: true
13884
+ }
13885
+ );
13886
+ const changes = await assembleChangeSet(adapter, {
13887
+ source: action,
13888
+ beforeSnap: context.beforeSnap,
13889
+ touchedIds: context.touchedIds,
13890
+ scheduledIds,
13891
+ sirDetection: "after-diff",
13892
+ links: buildLinkDeletions(context.beforeLinks),
13893
+ hoursPerDay: deps.sector.hoursPerDay,
13894
+ correlativeShifts
13895
+ });
13896
+ return buildConversionResult(plan, context, changes);
13897
+ }
13898
+ function planConversionBranch(rootId, adapter) {
13899
+ const root = requiredActivity(rootId, adapter);
13900
+ const branch = collectDescendantIds([rootId], adapter);
13901
+ branch.delete(rootId);
13902
+ if (branch.size === 0) {
13903
+ throw new Error(`Conversion root ${rootId} has no descendants`);
13904
+ }
13905
+ const descendants = adapter.getVisualOrderIds().filter((activityId) => branch.has(activityId)).map((activityId) => requiredActivity(activityId, adapter));
13906
+ validateFiniteActivity(root);
13907
+ for (const descendant of descendants) validateFiniteActivity(descendant);
13908
+ const convertible = descendants.filter(
13909
+ (activity) => activity.type !== ACTIVITY_TYPE.MILESTONE
13910
+ );
13911
+ const milestones = descendants.filter(
13912
+ (activity) => activity.type === ACTIVITY_TYPE.MILESTONE
13913
+ );
13914
+ const persistedIds = collectPersistedIds(root, convertible);
13915
+ return {
13916
+ conversionRootId: rootId,
13917
+ convertedActivities: convertible.map(
13918
+ (activity) => buildConvertedSnapshot(activity, persistedIds)
13919
+ ),
13920
+ milestoneMoves: buildMilestoneMoves(root, milestones),
13921
+ activityIdsToDelete: convertible.map((activity) => activity.id),
13922
+ formerParent: {
13923
+ activity: structuredCloneActivity(root),
13924
+ hasConvertedActivities: convertible.length > 0
13925
+ }
13926
+ };
13927
+ }
13928
+ function collectPersistedIds(root, converted) {
13929
+ const persistedIds = /* @__PURE__ */ new Map();
13930
+ if (converted.length > 0) persistedIds.set(root.id, persistedIdOf(root));
13931
+ for (const activity of converted) {
13932
+ persistedIds.set(activity.id, persistedIdOf(activity));
13933
+ }
13934
+ return persistedIds;
13935
+ }
13936
+ function buildConvertedSnapshot(activity, persistedIds) {
13937
+ const snapshot = structuredCloneActivity(activity);
13938
+ const parentKey = normalizeParentKey(activity.parentId);
13939
+ const persistedParentId = persistedIds.get(parentKey);
13940
+ snapshot.parentId = persistedParentId === void 0 ? null : String(persistedParentId);
13941
+ return snapshot;
13942
+ }
13943
+ function buildMilestoneMoves(root, milestones) {
13944
+ const moves = [];
13945
+ const parentId = normalizeParentKey(root.parentId);
13946
+ let afterSiblingId = root.id;
13947
+ for (const milestone of milestones) {
13948
+ moves.push({ activityId: milestone.id, parentId, afterSiblingId });
13949
+ afterSiblingId = milestone.id;
13950
+ }
13951
+ return moves;
13952
+ }
13953
+ async function captureConversionMutationContext(plan, adapter) {
13954
+ const deletedIds = new Set(plan.activityIdsToDelete);
13955
+ const touchedIds = /* @__PURE__ */ new Set([
13956
+ ...plan.conversionRootIds,
13957
+ ...plan.activityIdsToDelete,
13958
+ ...plan.milestoneMoves.map(({ activityId }) => activityId),
13959
+ ...plan.milestoneMoves.map(({ parentId }) => parentId).filter((parentId) => parentId !== ROOT_PARENT_ID)
13960
+ ]);
13961
+ return {
13962
+ deletedIds,
13963
+ touchedIds,
13964
+ beforeSnap: await snapshotActivities(adapter, touchedIds),
13965
+ beforeLinks: snapshotLinks(plan.linkIdsToDelete, adapter),
13966
+ viewStateChanges: captureDeletedViewState(adapter, deletedIds)
13967
+ };
13968
+ }
13969
+ function releaseDeletedCustomIds(plan, deps) {
13970
+ for (const activityId of plan.activityIdsToDelete) {
13971
+ const customId = deps.adapter.getActivity(activityId)?.customId;
13972
+ if (customId) deps.customIdTracker.releaseCustomId(customId);
13973
+ }
13974
+ }
13975
+ function applyConversionStructure(plan, adapter) {
13976
+ for (const move of plan.milestoneMoves) {
13977
+ adapter.setActivityFields(move.activityId, {
13978
+ parentId: move.parentId,
13979
+ correlativeId: computeInsertionCorrelativeId(
13980
+ adapter,
13981
+ move.parentId,
13982
+ move.afterSiblingId,
13983
+ void 0
13984
+ )
13985
+ });
13986
+ }
13987
+ for (const linkId of plan.linkIdsToDelete) adapter.removeLink(linkId);
13988
+ for (const activityId of [...plan.activityIdsToDelete].reverse()) {
13989
+ adapter.removeActivity(activityId);
13990
+ }
13991
+ for (const { activity } of plan.formerParents) {
13992
+ adapter.setActivityField(
13993
+ activity.id,
13994
+ ACTIVITY_PROPERTY.TYPE,
13995
+ ACTIVITY_TYPE.TASK
13996
+ );
13997
+ }
13998
+ }
13999
+ function applyFormerParentState(plan, deletedIds, adapter) {
14000
+ for (const { activity, hasConvertedActivities } of plan.formerParents) {
14001
+ const live = requiredActivity(activity.id, adapter);
14002
+ const cleanup = buildParentNewActivitiesCleanup({
14003
+ parent: live,
14004
+ idsRemoved: deletedIds
14005
+ });
14006
+ adapter.setActivityFields(activity.id, {
14007
+ isLookahead: activity.isLookahead || hasConvertedActivities,
14008
+ hasLookaheadTasks: activity.hasLookaheadTasks || hasConvertedActivities,
14009
+ ...cleanup?.fields ?? {}
14010
+ });
14011
+ }
14012
+ }
14013
+ function recomputeConversionRollups(plan, adapter) {
14014
+ for (const { activity } of plan.formerParents) {
14015
+ recomputeRollupCascadesForParent(activity.parentId, adapter);
14016
+ }
14017
+ return recomputeCorrelativeIds(adapter);
14018
+ }
14019
+ function buildConversionResult(plan, context, changes) {
14020
+ const deletedSnapshots = /* @__PURE__ */ new Map();
14021
+ for (const activityId of context.deletedIds) {
14022
+ const snapshot = context.beforeSnap.get(activityId);
14023
+ if (snapshot) deletedSnapshots.set(activityId, snapshot);
14024
+ }
14025
+ return {
14026
+ ok: true,
14027
+ changes: context.viewStateChanges.length === 0 ? changes : { ...changes, viewState: context.viewStateChanges },
14028
+ conversionGroups: plan.conversionGroups.map(
14029
+ ({ conversionRootId, convertedActivities }) => ({
14030
+ conversionRootId,
14031
+ convertedActivities: convertedActivities.map(
14032
+ (activity) => structuredCloneActivity(activity)
14033
+ )
14034
+ })
14035
+ ),
14036
+ __beforeSnap: deletedSnapshots,
14037
+ __beforeLinks: context.beforeLinks
14038
+ };
14039
+ }
14040
+ function validateRequestedRoot(rootId, adapter) {
14041
+ const activity = adapter.getActivity(rootId);
14042
+ if (!activity) throw new Error(`Conversion root ${rootId} was not found`);
14043
+ if (activity.type === ACTIVITY_TYPE.PROJECT && activity.correlativeId === ROOT_PROJECT_CORRELATIVE_ID) {
14044
+ throw new Error(`Conversion root ${rootId} is the visual project root`);
14045
+ }
14046
+ }
14047
+ function requiredActivity(activityId, adapter) {
14048
+ const activity = adapter.getActivity(activityId);
14049
+ if (!activity)
14050
+ throw new Error(`Conversion activity ${activityId} is missing`);
14051
+ return activity;
14052
+ }
14053
+ function persistedIdOf(activity) {
14054
+ if (activity.proplannerId == null) {
14055
+ throw new Error(
14056
+ `Conversion activity ${activity.id} has no persisted identifier`
14057
+ );
14058
+ }
14059
+ return activity.proplannerId;
14060
+ }
14061
+ function validateFiniteActivity(activity) {
14062
+ if (!Number.isFinite(activity.startDate.getTime())) {
14063
+ throw new Error(`Conversion activity ${activity.id} has invalid startDate`);
14064
+ }
14065
+ if (!Number.isFinite(activity.endDate.getTime())) {
14066
+ throw new Error(`Conversion activity ${activity.id} has invalid endDate`);
14067
+ }
14068
+ }
14069
+ function conversionTopologyIsValid(plan, adapter) {
14070
+ const proposedPort = adapter.fork();
14071
+ applyConversionStructure(plan, proposedPort);
14072
+ return validateTopologyCommit({
14073
+ port: adapter,
14074
+ proposedPort,
14075
+ currentLinks: adapter.getAllLinks(),
14076
+ proposedLinks: proposedPort.getAllLinks()
14077
+ }).ok;
14078
+ }
14079
+ function snapshotLinks(linkIds, adapter) {
14080
+ const snapshots = /* @__PURE__ */ new Map();
14081
+ for (const linkId of linkIds) {
14082
+ const link = adapter.getLink(linkId);
14083
+ if (link) snapshots.set(linkId, { ...link });
14084
+ }
14085
+ return snapshots;
14086
+ }
14087
+
13557
14088
  // src/internal/hierarchy/invalid-links.ts
13558
14089
  function collectInvalidLinkIdsForCycle(movedActivityIds, adapter) {
13559
14090
  const moved = /* @__PURE__ */ new Set();
@@ -13706,7 +14237,7 @@ async function dispatchActivityMove(action, options, deps) {
13706
14237
  newChildId: action.activityId,
13707
14238
  getParent: (id) => adapter.getActivity(id) ?? null,
13708
14239
  isCurrentlyLeaf: wasLeaf,
13709
- promotionSource: "reparent"
14240
+ promotionSource: PARENT_MUTATION_SOURCE.REPARENT
13710
14241
  });
13711
14242
  if (promotion) {
13712
14243
  for (const [key, value] of Object.entries(promotion.fields)) {
@@ -13819,7 +14350,7 @@ async function dispatchActivityMove(action, options, deps) {
13819
14350
  beforeSnap,
13820
14351
  touchedIds: touched,
13821
14352
  scheduledIds,
13822
- sirDetection: "before-diff",
14353
+ sirDetection: SIR_DETECTION_PHASE.BEFORE_DIFF,
13823
14354
  trackingEvents: [trackingEvent],
13824
14355
  hoursPerDay: sector.hoursPerDay
13825
14356
  })
@@ -13927,7 +14458,7 @@ async function dispatchActivityIndent(action, options, deps) {
13927
14458
  newChildId: activityId,
13928
14459
  getParent: (id) => adapter.getActivity(id) ?? null,
13929
14460
  isCurrentlyLeaf: wasLeaf,
13930
- promotionSource: "reparent"
14461
+ promotionSource: PARENT_MUTATION_SOURCE.REPARENT
13931
14462
  });
13932
14463
  if (promotion) {
13933
14464
  for (const [key, value] of Object.entries(promotion.fields)) {
@@ -13955,7 +14486,7 @@ async function dispatchActivityIndent(action, options, deps) {
13955
14486
  adapter.setActivityField(
13956
14487
  newParentId,
13957
14488
  ACTIVITY_PROPERTY.CONSTRAINT_TYPE,
13958
- "asap"
14489
+ CONSTRAINT_TYPE.ASAP
13959
14490
  );
13960
14491
  adapter.setActivityField(
13961
14492
  newParentId,
@@ -14231,7 +14762,7 @@ async function dispatchActivityOutdent(action, options, deps) {
14231
14762
  },
14232
14763
  {
14233
14764
  action,
14234
- autoscheduleFrom: succeededIds.length > 0 ? "roots" : null,
14765
+ autoscheduleFrom: succeededIds.length > 0 ? AUTOSCHEDULE_SCOPE.ROOTS : null,
14235
14766
  recomputeParentsFrom: succeededIds,
14236
14767
  now: deps.now,
14237
14768
  options
@@ -14294,7 +14825,7 @@ async function dispatchActivitySetProgress(action, options, deps) {
14294
14825
  }
14295
14826
  const editGate = pipeline.canEdit(activitySnap, ctx.hierarchy);
14296
14827
  if (!editGate.allowed) {
14297
- const declaredButtonOverride = action.origin === "action-button" && (editGate.reason === "has_lookahead_tasks" || editGate.reason === "summary");
14828
+ const declaredButtonOverride = action.origin === ACTIVITY_PROGRESS_ORIGIN.ACTION_BUTTON && (editGate.reason === EDIT_DENIAL_REASON.HAS_LOOKAHEAD_TASKS || editGate.reason === EDIT_DENIAL_REASON.SUMMARY);
14298
14829
  if (!declaredButtonOverride) {
14299
14830
  return {
14300
14831
  ok: false,
@@ -14415,7 +14946,7 @@ async function dispatchDatesBatch(action, options, deps) {
14415
14946
  },
14416
14947
  {
14417
14948
  action,
14418
- autoscheduleFrom: needsAutoSchedule ? "roots" : null,
14949
+ autoscheduleFrom: needsAutoSchedule ? AUTOSCHEDULE_SCOPE.ROOTS : null,
14419
14950
  recomputeParentsFrom: touchedIds,
14420
14951
  now: deps.now,
14421
14952
  options
@@ -14429,7 +14960,7 @@ async function dispatchDatesBatch(action, options, deps) {
14429
14960
  beforeSnap,
14430
14961
  touchedIds,
14431
14962
  scheduledIds,
14432
- sirDetection: "before-diff",
14963
+ sirDetection: SIR_DETECTION_PHASE.BEFORE_DIFF,
14433
14964
  links: linkChanges,
14434
14965
  trackingEvents,
14435
14966
  warnings,
@@ -14576,7 +15107,7 @@ async function dispatchBulkEdit(action, options, deps) {
14576
15107
  }
14577
15108
  const postMutationArgs = {
14578
15109
  action,
14579
- autoscheduleFrom: needsAutoSchedule ? "roots" : null,
15110
+ autoscheduleFrom: needsAutoSchedule ? AUTOSCHEDULE_SCOPE.ROOTS : null,
14580
15111
  recomputeParentsFrom: touchedIds,
14581
15112
  now: deps.now,
14582
15113
  options
@@ -14621,7 +15152,7 @@ async function dispatchBulkEdit(action, options, deps) {
14621
15152
  beforeSnap,
14622
15153
  touchedIds,
14623
15154
  scheduledIds,
14624
- sirDetection: "before-diff",
15155
+ sirDetection: SIR_DETECTION_PHASE.BEFORE_DIFF,
14625
15156
  links: linkChanges,
14626
15157
  trackingEvents,
14627
15158
  warnings,
@@ -14758,6 +15289,51 @@ function mergeBeforeSnapshots2(beforeSnap, ids, deps) {
14758
15289
  }
14759
15290
  }
14760
15291
 
15292
+ // src/shared/load-diagnostics.ts
15293
+ var LOAD_DIAGNOSTIC_SAMPLE_LIMIT = 10;
15294
+ var LOAD_DIAGNOSTIC_CODE = {
15295
+ INVALID_BASELINE_POINT: "invalid_baseline_point",
15296
+ UNKNOWN_CONSTRAINT: "unknown_constraint",
15297
+ ORPHAN_ACTIVITY: "orphan_activity",
15298
+ INVALID_LINK: "invalid_link",
15299
+ DUPLICATE_LINK: "duplicate_link"
15300
+ };
15301
+ var LOAD_DIAGNOSTIC_CODE_ORDER = [
15302
+ LOAD_DIAGNOSTIC_CODE.INVALID_BASELINE_POINT,
15303
+ LOAD_DIAGNOSTIC_CODE.UNKNOWN_CONSTRAINT,
15304
+ LOAD_DIAGNOSTIC_CODE.ORPHAN_ACTIVITY,
15305
+ LOAD_DIAGNOSTIC_CODE.INVALID_LINK,
15306
+ LOAD_DIAGNOSTIC_CODE.DUPLICATE_LINK
15307
+ ];
15308
+ var noopLoadDiagnosticRecorder = () => {
15309
+ };
15310
+ function createLoadDiagnosticsCollector() {
15311
+ const counts = /* @__PURE__ */ new Map();
15312
+ const samples = /* @__PURE__ */ new Map();
15313
+ const record = (code, sampleId) => {
15314
+ counts.set(code, (counts.get(code) ?? 0) + 1);
15315
+ const codeSamples = samples.get(code) ?? [];
15316
+ if (codeSamples.length < LOAD_DIAGNOSTIC_SAMPLE_LIMIT && !codeSamples.includes(sampleId)) {
15317
+ codeSamples.push(sampleId);
15318
+ samples.set(code, codeSamples);
15319
+ }
15320
+ };
15321
+ const snapshot = () => Object.freeze(
15322
+ LOAD_DIAGNOSTIC_CODE_ORDER.flatMap((code) => {
15323
+ const count = counts.get(code);
15324
+ if (count === void 0) return [];
15325
+ return [
15326
+ Object.freeze({
15327
+ code,
15328
+ count,
15329
+ sampleIds: Object.freeze([...samples.get(code) ?? []])
15330
+ })
15331
+ ];
15332
+ })
15333
+ );
15334
+ return { record, snapshot };
15335
+ }
15336
+
14761
15337
  // src/baselines/normalize-baseline-point.ts
14762
15338
  function parseBaselineDate(value) {
14763
15339
  return typeof value === "string" && value.length > 0 ? parseBackendDate(value) : value instanceof Date ? value : null;
@@ -14767,11 +15343,17 @@ function parseFiniteNonNegative(value) {
14767
15343
  if (!Number.isFinite(numeric) || numeric < 0) return null;
14768
15344
  return numeric;
14769
15345
  }
14770
- function normalizeBaselinePoint(point, reporter) {
15346
+ function normalizeBaselinePoint(point, reporter, diagnostic) {
14771
15347
  const durationDays = parseFiniteNonNegative(point.duration);
14772
15348
  const cost = parseFiniteNonNegative(point.cost);
14773
15349
  const workHours = parseFiniteNonNegative(point.hh_work);
14774
15350
  if (durationDays === null || cost === null || workHours === null) {
15351
+ if (diagnostic) {
15352
+ diagnostic.record(
15353
+ LOAD_DIAGNOSTIC_CODE.INVALID_BASELINE_POINT,
15354
+ diagnostic.sampleId
15355
+ );
15356
+ }
14775
15357
  reporter.warn(
14776
15358
  `[baseline] dropping point with non-finite/negative magnitude \u2014 duration=${JSON.stringify(point.duration)}, cost=${JSON.stringify(point.cost)}, hh_work=${JSON.stringify(point.hh_work)}`
14777
15359
  );
@@ -14793,7 +15375,7 @@ function normalizeBaselinePoint(point, reporter) {
14793
15375
  }
14794
15376
 
14795
15377
  // src/baselines/apply-baseline-points.ts
14796
- function applyBaselinePoints(adapter, points, reporter) {
15378
+ function applyBaselinePoints(adapter, points, reporter, recordDiagnostic = noopLoadDiagnosticRecorder) {
14797
15379
  const idByProplanner = /* @__PURE__ */ new Map();
14798
15380
  adapter.forEachActivity((a, id) => {
14799
15381
  const pid = a.proplannerId;
@@ -14802,9 +15384,21 @@ function applyBaselinePoints(adapter, points, reporter) {
14802
15384
  const grouped = /* @__PURE__ */ new Map();
14803
15385
  for (const p of points) {
14804
15386
  const activityId = p.activityId;
14805
- if (typeof activityId !== "number") continue;
15387
+ if (typeof activityId !== "number") {
15388
+ recordDiagnostic(
15389
+ LOAD_DIAGNOSTIC_CODE.INVALID_BASELINE_POINT,
15390
+ String(activityId ?? "unknown")
15391
+ );
15392
+ continue;
15393
+ }
14806
15394
  const coreId = idByProplanner.get(activityId);
14807
- if (coreId === void 0) continue;
15395
+ if (coreId === void 0) {
15396
+ recordDiagnostic(
15397
+ LOAD_DIAGNOSTIC_CODE.INVALID_BASELINE_POINT,
15398
+ String(activityId)
15399
+ );
15400
+ continue;
15401
+ }
14808
15402
  const arr = grouped.get(coreId);
14809
15403
  if (arr) arr.push(p);
14810
15404
  else grouped.set(coreId, [p]);
@@ -14814,7 +15408,12 @@ function applyBaselinePoints(adapter, points, reporter) {
14814
15408
  adapter.setActivityField(
14815
15409
  coreId,
14816
15410
  "baselinePoints",
14817
- group.map((point) => normalizeBaselinePoint(point, reporter)).filter((point) => point !== null)
15411
+ group.map(
15412
+ (point) => normalizeBaselinePoint(point, reporter, {
15413
+ record: recordDiagnostic,
15414
+ sampleId: coreId
15415
+ })
15416
+ ).filter((point) => point !== null)
14818
15417
  );
14819
15418
  changed.push(coreId);
14820
15419
  }
@@ -14859,12 +15458,13 @@ function emitBaselineSnapshotColumns(state) {
14859
15458
  }
14860
15459
 
14861
15460
  // src/baselines/apply-baseline-overlay.ts
14862
- function applyBaselineOverlay(state, points, now, reporter, defaultBaseCalendarId = null) {
15461
+ function applyBaselineOverlay(state, points, now, reporter, defaultBaseCalendarId = null, recordDiagnostic = noopLoadDiagnosticRecorder) {
14863
15462
  const changed = /* @__PURE__ */ new Set();
14864
15463
  for (const id of applyBaselinePoints(
14865
15464
  state,
14866
15465
  points,
14867
- reporter
15466
+ reporter,
15467
+ recordDiagnostic
14868
15468
  )) {
14869
15469
  changed.add(id);
14870
15470
  }
@@ -15103,7 +15703,7 @@ async function dispatchCalendarReconcile(action, options, deps) {
15103
15703
  },
15104
15704
  {
15105
15705
  action,
15106
- autoscheduleFrom: "roots",
15706
+ autoscheduleFrom: AUTOSCHEDULE_SCOPE.ROOTS,
15107
15707
  recomputeParentsFrom: touchedIds,
15108
15708
  now: deps.now,
15109
15709
  options
@@ -15174,7 +15774,7 @@ function dispatchActivityCopy(action, deps) {
15174
15774
  throw new Error(`Selected activity ${id} is missing`);
15175
15775
  return {
15176
15776
  originalId: id,
15177
- originalParentId: activity.parentId ?? "0",
15777
+ originalParentId: activity.parentId ?? ROOT_PARENT_ID,
15178
15778
  overrides: copyOverrides(activity)
15179
15779
  };
15180
15780
  }),
@@ -15183,7 +15783,7 @@ function dispatchActivityCopy(action, deps) {
15183
15783
  ).map((link) => cloneDomainValue(link))
15184
15784
  };
15185
15785
  const selection = dispatchSelectionReplace(
15186
- { kind: "selection-replace", activityIds: [] },
15786
+ { kind: DISPATCH_ACTION_KIND.SELECTION_REPLACE, activityIds: [] },
15187
15787
  { adapter: deps.adapter }
15188
15788
  );
15189
15789
  if (!selection.ok) return selection;
@@ -15245,6 +15845,7 @@ async function dispatchActivityPasteCopied(action, options, deps) {
15245
15845
  const afterSiblingId = mappedParent === void 0 ? previousRootId ?? destination.afterSiblingId : void 0;
15246
15846
  const created = await createActivityCore(
15247
15847
  {
15848
+ kind: DISPATCH_ACTION_KIND.ACTIVITY_CREATE,
15248
15849
  parentId: mappedParent ?? destination.parentId,
15249
15850
  ...afterSiblingId === void 0 ? {} : { afterSiblingId },
15250
15851
  overrides: cloneDomainValue(copied.overrides),
@@ -15278,7 +15879,7 @@ async function dispatchActivityPasteCopied(action, options, deps) {
15278
15879
  const target = originalToNew.get(copiedLink.target);
15279
15880
  if (source === void 0 || target === void 0) return invariantFailure();
15280
15881
  const operation = {
15281
- kind: "create",
15882
+ kind: LINK_OPERATION_KIND.CREATE,
15282
15883
  source,
15283
15884
  target,
15284
15885
  type: copiedLink.type,
@@ -15330,94 +15931,97 @@ async function dispatchActivityPasteCopied(action, options, deps) {
15330
15931
 
15331
15932
  // src/dispatch/dispatch.ts
15332
15933
  async function performDispatch(action, options, deps) {
15333
- if (action.kind === "activity-copy") {
15934
+ if (action.kind === DISPATCH_ACTION_KIND.ACTIVITY_COPY) {
15334
15935
  return dispatchActivityCopy(action, {
15335
15936
  adapter: deps.adapter,
15336
15937
  clipboard: deps.activityClipboard
15337
15938
  });
15338
15939
  }
15339
- if (action.kind === "calendar-reconcile") {
15940
+ if (action.kind === DISPATCH_ACTION_KIND.CALENDAR_RECONCILE) {
15340
15941
  return dispatchCalendarReconcile(action, options, deps);
15341
15942
  }
15342
- if (action.kind === "activity-clipboard-clear") {
15943
+ if (action.kind === DISPATCH_ACTION_KIND.ACTIVITY_CLIPBOARD_CLEAR) {
15343
15944
  return dispatchActivityClipboardClear(action, deps.activityClipboard);
15344
15945
  }
15345
- if (action.kind === "activity-paste-copied") {
15946
+ if (action.kind === DISPATCH_ACTION_KIND.ACTIVITY_PASTE_COPIED) {
15346
15947
  return dispatchActivityPasteCopied(action, options, deps);
15347
15948
  }
15348
- if (action.kind === "activity-batch") {
15949
+ if (action.kind === ACTIVITY_BATCH_ACTION_KIND) {
15349
15950
  return dispatchActivityBatch(action, options, deps);
15350
15951
  }
15351
- if (action.kind === "persistence-acknowledge") {
15952
+ if (action.kind === DISPATCH_ACTION_KIND.PERSISTENCE_ACKNOWLEDGE) {
15352
15953
  return dispatchPersistenceAcknowledge(action, deps);
15353
15954
  }
15354
- if (action.kind === "baseline-apply") {
15955
+ if (action.kind === DISPATCH_ACTION_KIND.BASELINE_APPLY) {
15355
15956
  return dispatchBaselineApply(action, deps);
15356
15957
  }
15357
- if (action.kind === "ponderator-criterion-set") {
15958
+ if (action.kind === DISPATCH_ACTION_KIND.PONDERATOR_CRITERION_SET) {
15358
15959
  return dispatchPonderatorCriterionSet(action, deps);
15359
15960
  }
15360
- if (action.kind === "status-criteria-set") {
15961
+ if (action.kind === DISPATCH_ACTION_KIND.STATUS_CRITERIA_SET) {
15361
15962
  return dispatchStatusCriteriaSet(action, deps);
15362
15963
  }
15363
- if (action.kind === "link-create" || action.kind === "link-update" || action.kind === "link-delete") {
15964
+ if (action.kind === DISPATCH_ACTION_KIND.LINK_CREATE || action.kind === DISPATCH_ACTION_KIND.LINK_UPDATE || action.kind === DISPATCH_ACTION_KIND.LINK_DELETE) {
15364
15965
  return dispatchLink(action, options, deps);
15365
15966
  }
15366
- if (action.kind === "links-batch") {
15967
+ if (action.kind === DISPATCH_ACTION_KIND.LINKS_BATCH) {
15367
15968
  return dispatchLinksBatch(action, options, deps);
15368
15969
  }
15369
- if (action.kind === "activity-create") {
15970
+ if (action.kind === DISPATCH_ACTION_KIND.ACTIVITY_CREATE) {
15370
15971
  return dispatchActivityCreate(action, options, deps);
15371
15972
  }
15372
- if (action.kind === "activity-delete") {
15973
+ if (action.kind === DISPATCH_ACTION_KIND.ACTIVITY_DELETE) {
15373
15974
  return dispatchActivityDelete(action, options, deps);
15374
15975
  }
15375
- if (action.kind === "activity-move") {
15976
+ if (action.kind === DISPATCH_ACTION_KIND.ACTIVITY_MOVE) {
15376
15977
  return dispatchActivityMove(action, options, deps);
15377
15978
  }
15378
- if (action.kind === "activity-indent") {
15979
+ if (action.kind === DISPATCH_ACTION_KIND.ACTIVITY_INDENT) {
15379
15980
  return dispatchActivityIndent(action, options, deps);
15380
15981
  }
15381
- if (action.kind === "activity-outdent") {
15982
+ if (action.kind === DISPATCH_ACTION_KIND.ACTIVITY_OUTDENT) {
15382
15983
  return dispatchActivityOutdent(action, options, deps);
15383
15984
  }
15384
- if (action.kind === "activity-set-progress") {
15985
+ if (action.kind === DISPATCH_ACTION_KIND.ACTIVITY_SET_PROGRESS) {
15385
15986
  return dispatchActivitySetProgress(action, options, deps);
15386
15987
  }
15387
- if (action.kind === "dates-batch") {
15988
+ if (action.kind === DISPATCH_ACTION_KIND.DATES_BATCH) {
15388
15989
  return dispatchDatesBatch(action, options, deps);
15389
15990
  }
15390
- if (action.kind === "bulk-edit") {
15991
+ if (action.kind === DISPATCH_ACTION_KIND.BULK_EDIT) {
15391
15992
  return dispatchBulkEdit(action, options, deps);
15392
15993
  }
15393
- if (action.kind === "selection-toggle") {
15994
+ if (action.kind === DISPATCH_ACTION_KIND.SELECTION_TOGGLE) {
15394
15995
  return dispatchSelectionToggle(action, selectionDeps(deps));
15395
15996
  }
15396
- if (action.kind === "selection-replace") {
15997
+ if (action.kind === DISPATCH_ACTION_KIND.SELECTION_REPLACE) {
15397
15998
  return dispatchSelectionReplace(action, selectionDeps(deps));
15398
15999
  }
15399
- if (action.kind === "visibility-set") {
16000
+ if (action.kind === DISPATCH_ACTION_KIND.VISIBILITY_SET) {
15400
16001
  return dispatchVisibilitySet(action, selectionDeps(deps));
15401
16002
  }
15402
- if (action.kind === "filter-set") {
16003
+ if (action.kind === DISPATCH_ACTION_KIND.FILTER_SET) {
15403
16004
  return dispatchFilterSet(action, {
15404
16005
  adapter: deps.adapter,
15405
16006
  hoursPerDay: deps.sector.hoursPerDay
15406
16007
  });
15407
16008
  }
15408
- if (action.kind === "sort-set") {
16009
+ if (action.kind === DISPATCH_ACTION_KIND.SORT_SET) {
15409
16010
  return dispatchSortSet(action, { adapter: deps.adapter });
15410
16011
  }
15411
- if (action.kind === "sir-sync") {
16012
+ if (action.kind === DISPATCH_ACTION_KIND.SIR_SYNC) {
15412
16013
  return dispatchSirSync(action, deps);
15413
16014
  }
15414
- if (action.kind === "activity-lookahead-sync") {
16015
+ if (action.kind === DISPATCH_ACTION_KIND.ACTIVITY_LOOKAHEAD_SYNC) {
15415
16016
  return dispatchActivityLookaheadSync(action, options, deps);
15416
16017
  }
15417
- if (action.kind === "inline-edit" && (action.column === COLUMN.CUSTOM_PREDECESSORS || action.column === COLUMN.CUSTOM_SUCESSORS)) {
16018
+ if (action.kind === DISPATCH_ACTION_KIND.ACTIVITY_LOOKAHEAD_CONVERT) {
16019
+ return dispatchActivityLookaheadConvert(action, options, deps);
16020
+ }
16021
+ if (action.kind === DISPATCH_ACTION_KIND.INLINE_EDIT && (action.column === COLUMN.CUSTOM_PREDECESSORS || action.column === COLUMN.CUSTOM_SUCESSORS)) {
15418
16022
  return dispatchInlineEditLinks(action, options, deps);
15419
16023
  }
15420
- if (action.kind !== "inline-edit") {
16024
+ if (action.kind !== DISPATCH_ACTION_KIND.INLINE_EDIT) {
15421
16025
  return assertNever(
15422
16026
  action,
15423
16027
  `[ScheduleCore] dispatch kind "${action.kind}" not supported yet`
@@ -15444,7 +16048,7 @@ function coerceActivityFieldValue(field, value) {
15444
16048
 
15445
16049
  // src/calendar/adapter.ts
15446
16050
  function createWorkCalendarAdapter(instance, options = {}) {
15447
- const defaultUnit = options.defaultUnit ?? "hour";
16051
+ const defaultUnit = options.defaultUnit ?? CALENDAR_UNIT.HOUR;
15448
16052
  return {
15449
16053
  getCalendar(calendarId) {
15450
16054
  const calendar = instance.getCalendar(String(calendarId));
@@ -18248,90 +18852,6 @@ function collectDescendantIdsBFS(adapter, rootId) {
18248
18852
  return result;
18249
18853
  }
18250
18854
 
18251
- // src/internal/state/write-capture.ts
18252
- var WriteCapture = class {
18253
- _journal = null;
18254
- begin() {
18255
- this._journal = {
18256
- dirty: /* @__PURE__ */ new Set(),
18257
- before: /* @__PURE__ */ new Map(),
18258
- ops: [],
18259
- linkFieldCaptured: /* @__PURE__ */ new Set(),
18260
- correlativeBefore: /* @__PURE__ */ new Map(),
18261
- scheduledBefore: /* @__PURE__ */ new Map(),
18262
- progressFallbackBefore: /* @__PURE__ */ new Map()
18263
- };
18264
- }
18265
- peek() {
18266
- return this._journal;
18267
- }
18268
- end() {
18269
- this._journal = null;
18270
- }
18271
- note(key, current) {
18272
- const journal = this._journal;
18273
- if (!journal) return;
18274
- if (!journal.before.has(key))
18275
- journal.before.set(key, cloneCoreActivity(current));
18276
- journal.dirty.add(key);
18277
- }
18278
- noteInsert(activityId) {
18279
- this._journal?.ops.push({ kind: "insert", activityId });
18280
- }
18281
- noteRemove(activityId, current) {
18282
- this._journal?.ops.push({
18283
- kind: "remove",
18284
- activityId,
18285
- before: cloneCoreActivity(current)
18286
- });
18287
- }
18288
- noteLinkAdd(linkId) {
18289
- this._journal?.ops.push({ kind: "link-add", linkId });
18290
- }
18291
- noteLinkRemove(linkId, current) {
18292
- this._journal?.ops.push({
18293
- kind: "link-remove",
18294
- linkId,
18295
- before: cloneLink(current)
18296
- });
18297
- }
18298
- noteCorrelativeBefore(activityId, before) {
18299
- const journal = this._journal;
18300
- if (!journal || journal.correlativeBefore.has(activityId)) return;
18301
- journal.correlativeBefore.set(activityId, before);
18302
- }
18303
- noteScheduledBefore(activityId, current) {
18304
- const journal = this._journal;
18305
- if (!journal) return;
18306
- const beforeImage = cloneCoreActivity(current);
18307
- if (!journal.scheduledBefore.has(activityId)) {
18308
- journal.scheduledBefore.set(activityId, beforeImage);
18309
- }
18310
- if (!journal.before.has(activityId)) {
18311
- journal.before.set(activityId, beforeImage);
18312
- }
18313
- journal.dirty.add(activityId);
18314
- }
18315
- noteLinkField(linkId, current) {
18316
- const journal = this._journal;
18317
- if (!journal || journal.linkFieldCaptured.has(linkId)) return;
18318
- journal.linkFieldCaptured.add(linkId);
18319
- journal.ops.push({
18320
- kind: "link-field",
18321
- linkId,
18322
- before: cloneLink(current)
18323
- });
18324
- }
18325
- noteProgressFallback(activityId, current) {
18326
- const journal = this._journal;
18327
- if (!journal || journal.progressFallbackBefore.has(activityId)) return;
18328
- journal.progressFallbackBefore.set(activityId, current);
18329
- }
18330
- };
18331
- function cloneLink(link) {
18332
- return { ...link };
18333
- }
18334
-
18335
18855
  // src/internal/state/calendar-calculator.ts
18336
18856
  var CalendarCalculator = class {
18337
18857
  _cache = {
@@ -18985,9 +19505,9 @@ var ScheduleState = class _ScheduleState {
18985
19505
  this._reInsertRemovedActivities(ops);
18986
19506
  this._reAddRemovedLinks(ops);
18987
19507
  this._restoreLinkFields(ops);
18988
- this._restoreCorrelatives(correlativeBefore);
18989
19508
  this._restoreActivityFields(scheduledBefore);
18990
19509
  this._restoreActivityFields(before);
19510
+ this._restoreCorrelatives(correlativeBefore);
18991
19511
  this._restoreProgressFallbacks(progressFallbackBefore);
18992
19512
  if (this._viewStateBefore !== null) {
18993
19513
  this._viewState.restore(this._viewStateBefore);
@@ -19018,24 +19538,33 @@ var ScheduleState = class _ScheduleState {
19018
19538
  }
19019
19539
  _undoLinkAdds(ops) {
19020
19540
  for (const op of ops)
19021
- if (op.kind === "link-add") this._detachLink(op.linkId);
19541
+ if (op.kind === WRITE_OPERATION_KIND.LINK_ADD) {
19542
+ this._detachLink(op.linkId);
19543
+ }
19022
19544
  }
19023
19545
  _undoInserts(ops) {
19024
19546
  for (const op of ops)
19025
- if (op.kind === "insert") this._activities.delete(op.activityId);
19547
+ if (op.kind === WRITE_OPERATION_KIND.INSERT) {
19548
+ this._activities.delete(op.activityId);
19549
+ }
19026
19550
  }
19027
19551
  _reInsertRemovedActivities(ops) {
19028
19552
  for (const op of ops)
19029
- if (op.kind === "remove") this._activities.set(op.activityId, op.before);
19553
+ if (op.kind === WRITE_OPERATION_KIND.REMOVE) {
19554
+ this._activities.set(op.activityId, op.before);
19555
+ }
19030
19556
  }
19031
19557
  _reAddRemovedLinks(ops) {
19032
19558
  for (const op of ops)
19033
- if (op.kind === "link-remove") this._attachLink(op.before);
19559
+ if (op.kind === WRITE_OPERATION_KIND.LINK_REMOVE) {
19560
+ this._attachLink(op.before);
19561
+ }
19034
19562
  }
19035
19563
  _restoreLinkFields(ops) {
19036
19564
  for (const op of ops)
19037
- if (op.kind === "link-field" && this._links.has(op.linkId))
19565
+ if (op.kind === WRITE_OPERATION_KIND.LINK_FIELD && this._links.has(op.linkId)) {
19038
19566
  this._links.set(op.linkId, op.before);
19567
+ }
19039
19568
  }
19040
19569
  _restoreActivityFields(before) {
19041
19570
  for (const [id, snapshot] of before) {
@@ -19202,7 +19731,8 @@ function withoutDerivedFields(entry, derivedFields) {
19202
19731
  ([field]) => !derivedFields.has(field)
19203
19732
  )
19204
19733
  );
19205
- if (entry.kind === "updated" && Object.keys(fields).length === 0) return null;
19734
+ if (entry.kind === ENTITY_CHANGE_KIND.UPDATED && Object.keys(fields).length === 0)
19735
+ return null;
19206
19736
  return {
19207
19737
  ...entry,
19208
19738
  ...entry.fields === void 0 ? {} : { fields },
@@ -19215,7 +19745,7 @@ function buildHistoryChangeSet(changes) {
19215
19745
  after: null
19216
19746
  }));
19217
19747
  const linksWithoutAfter = changes.links.map((entry) => withoutDerivedFields(entry, DERIVED_LINK_FIELDS)).filter((entry) => entry !== null);
19218
- const source = changes.source.kind === "activity-batch" ? { ...changes.source, items: [], links: [] } : changes.source;
19748
+ const source = changes.source.kind === ACTIVITY_BATCH_ACTION_KIND ? { ...changes.source, items: [], links: [] } : changes.source;
19219
19749
  return cloneDomainValue({
19220
19750
  ...changes,
19221
19751
  source,
@@ -19247,12 +19777,12 @@ function captureCreatedSnapshots(state, changeSet) {
19247
19777
  const afterSnap = /* @__PURE__ */ new Map();
19248
19778
  const afterLinks = /* @__PURE__ */ new Map();
19249
19779
  for (const ch of changeSet.activities) {
19250
- if (ch.kind !== "created") continue;
19780
+ if (ch.kind !== ENTITY_CHANGE_KIND.CREATED) continue;
19251
19781
  const live = state.getActivity(String(ch.id));
19252
19782
  if (live) afterSnap.set(String(ch.id), structuredCloneActivity(live));
19253
19783
  }
19254
19784
  for (const ch of changeSet.links) {
19255
- if (ch.kind === "deleted") continue;
19785
+ if (ch.kind === ENTITY_CHANGE_KIND.DELETED) continue;
19256
19786
  const live = state.getLink(String(ch.id));
19257
19787
  if (live) afterLinks.set(String(ch.id), { ...live });
19258
19788
  }
@@ -19264,7 +19794,7 @@ function computeCoalesceKey(action) {
19264
19794
  return `inline-edit:${String(action.activityId)}:${action.column}`;
19265
19795
  }
19266
19796
  function isSimpleInlineEntry(e) {
19267
- return e.changeSet.activities.length === 1 && e.changeSet.activities[0]?.kind === "updated" && e.changeSet.links.length === 0 && !e.beforeSnap?.size && !e.afterSnap?.size;
19797
+ return e.changeSet.activities.length === 1 && e.changeSet.activities[0]?.kind === ENTITY_CHANGE_KIND.UPDATED && e.changeSet.links.length === 0 && !e.beforeSnap?.size && !e.afterSnap?.size;
19268
19798
  }
19269
19799
  function canCoalesce(top, next) {
19270
19800
  if (!isSimpleInlineEntry(top) || !isSimpleInlineEntry(next)) return false;
@@ -19293,19 +19823,29 @@ function mergeCoalesced(top, next) {
19293
19823
  };
19294
19824
  return buildUndoEntry(changeSet);
19295
19825
  }
19826
+ var DISPATCH_HISTORY_POLICY = {
19827
+ RECORD: "record",
19828
+ SKIP: "skip",
19829
+ CHECKPOINT_ON_SUCCESS: "checkpoint-on-success"
19830
+ };
19831
+ var CHANGE_SET_SIDE = {
19832
+ BEFORE: "before",
19833
+ AFTER: "after"
19834
+ };
19296
19835
  function getDispatchHistoryPolicy(action) {
19297
19836
  if (action.kind === DISPATCH_ACTION_KIND.PERSISTENCE_ACKNOWLEDGE) {
19298
- return "checkpoint-on-success";
19837
+ return DISPATCH_HISTORY_POLICY.CHECKPOINT_ON_SUCCESS;
19299
19838
  }
19300
19839
  if (action.kind === DISPATCH_ACTION_KIND.SIR_SYNC || action.kind === DISPATCH_ACTION_KIND.CALENDAR_RECONCILE || action.kind === DISPATCH_ACTION_KIND.ACTIVITY_LOOKAHEAD_SYNC || action.kind === DISPATCH_ACTION_KIND.BASELINE_APPLY || action.kind === DISPATCH_ACTION_KIND.PONDERATOR_CRITERION_SET || action.kind === DISPATCH_ACTION_KIND.STATUS_CRITERIA_SET || action.kind === DISPATCH_ACTION_KIND.ACTIVITY_CLIPBOARD_CLEAR || action.kind === DISPATCH_ACTION_KIND.ACTIVITY_COPY || action.kind === DISPATCH_ACTION_KIND.SELECTION_TOGGLE || action.kind === DISPATCH_ACTION_KIND.SELECTION_REPLACE || action.kind === DISPATCH_ACTION_KIND.VISIBILITY_SET || action.kind === DISPATCH_ACTION_KIND.FILTER_SET || action.kind === DISPATCH_ACTION_KIND.SORT_SET) {
19301
- return "skip";
19840
+ return DISPATCH_HISTORY_POLICY.SKIP;
19302
19841
  }
19303
- return "record";
19842
+ return DISPATCH_HISTORY_POLICY.RECORD;
19304
19843
  }
19305
19844
  function needsResync(entry) {
19306
19845
  for (const change of entry.changeSet.activities) {
19307
- if (change.kind === "created" || change.kind === "deleted") return true;
19308
- if (change.kind === "updated" && change.fields && COLUMN.CUSTOM_ID in change.fields)
19846
+ if (change.kind === ENTITY_CHANGE_KIND.CREATED || change.kind === ENTITY_CHANGE_KIND.DELETED)
19847
+ return true;
19848
+ if (change.kind === ENTITY_CHANGE_KIND.UPDATED && change.fields && COLUMN.CUSTOM_ID in change.fields)
19309
19849
  return true;
19310
19850
  }
19311
19851
  return false;
@@ -19315,33 +19855,41 @@ function buildInverseChangeSet(state, entry, side) {
19315
19855
  const links = [];
19316
19856
  for (const change of entry.changeSet.activities) {
19317
19857
  const activityId = String(change.id);
19318
- if (change.kind === "updated") {
19858
+ if (change.kind === ENTITY_CHANGE_KIND.UPDATED) {
19319
19859
  const snapshot = state.getActivity(activityId);
19320
19860
  activities.push({
19321
19861
  id: activityId,
19322
- kind: "updated",
19862
+ kind: ENTITY_CHANGE_KIND.UPDATED,
19323
19863
  fields: historyFields(change.fields, side),
19324
19864
  after: snapshot ? structuredCloneActivity(snapshot) : null
19325
19865
  });
19326
- } else if (change.kind === "deleted") {
19327
- if (side === "before") {
19866
+ } else if (change.kind === ENTITY_CHANGE_KIND.DELETED) {
19867
+ if (side === CHANGE_SET_SIDE.BEFORE) {
19328
19868
  const snapshot = state.getActivity(activityId);
19329
19869
  activities.push({
19330
19870
  id: activityId,
19331
- kind: "created",
19871
+ kind: ENTITY_CHANGE_KIND.CREATED,
19332
19872
  after: snapshot ? structuredCloneActivity(snapshot) : null
19333
19873
  });
19334
19874
  } else {
19335
- activities.push({ id: activityId, kind: "deleted", after: null });
19875
+ activities.push({
19876
+ id: activityId,
19877
+ kind: ENTITY_CHANGE_KIND.DELETED,
19878
+ after: null
19879
+ });
19336
19880
  }
19337
19881
  } else {
19338
- if (side === "before") {
19339
- activities.push({ id: activityId, kind: "deleted", after: null });
19882
+ if (side === CHANGE_SET_SIDE.BEFORE) {
19883
+ activities.push({
19884
+ id: activityId,
19885
+ kind: ENTITY_CHANGE_KIND.DELETED,
19886
+ after: null
19887
+ });
19340
19888
  } else {
19341
19889
  const snapshot = state.getActivity(activityId);
19342
19890
  activities.push({
19343
19891
  id: activityId,
19344
- kind: "created",
19892
+ kind: ENTITY_CHANGE_KIND.CREATED,
19345
19893
  after: snapshot ? structuredCloneActivity(snapshot) : null
19346
19894
  });
19347
19895
  }
@@ -19349,44 +19897,52 @@ function buildInverseChangeSet(state, entry, side) {
19349
19897
  }
19350
19898
  for (const change of entry.changeSet.links) {
19351
19899
  const linkId = String(change.id);
19352
- if (change.kind === "updated") {
19900
+ if (change.kind === ENTITY_CHANGE_KIND.UPDATED) {
19353
19901
  const lk = state.getLink(linkId);
19354
19902
  links.push({
19355
19903
  id: linkId,
19356
- kind: "updated",
19904
+ kind: ENTITY_CHANGE_KIND.UPDATED,
19357
19905
  fields: historyFields(change.fields, side),
19358
19906
  after: lk ? snapshotToLink(lk) : null
19359
19907
  });
19360
- } else if (change.kind === "deleted") {
19361
- if (side === "before") {
19908
+ } else if (change.kind === ENTITY_CHANGE_KIND.DELETED) {
19909
+ if (side === CHANGE_SET_SIDE.BEFORE) {
19362
19910
  const lk = state.getLink(linkId);
19363
19911
  links.push({
19364
19912
  id: linkId,
19365
- kind: "created",
19913
+ kind: ENTITY_CHANGE_KIND.CREATED,
19366
19914
  after: lk ? snapshotToLink(lk) : null
19367
19915
  });
19368
19916
  } else {
19369
- links.push({ id: linkId, kind: "deleted", after: null });
19917
+ links.push({
19918
+ id: linkId,
19919
+ kind: ENTITY_CHANGE_KIND.DELETED,
19920
+ after: null
19921
+ });
19370
19922
  }
19371
19923
  } else {
19372
- if (side === "before") {
19373
- links.push({ id: linkId, kind: "deleted", after: null });
19924
+ if (side === CHANGE_SET_SIDE.BEFORE) {
19925
+ links.push({
19926
+ id: linkId,
19927
+ kind: ENTITY_CHANGE_KIND.DELETED,
19928
+ after: null
19929
+ });
19374
19930
  } else {
19375
19931
  const lk = state.getLink(linkId);
19376
19932
  links.push({
19377
19933
  id: linkId,
19378
- kind: "created",
19934
+ kind: ENTITY_CHANGE_KIND.CREATED,
19379
19935
  after: lk ? snapshotToLink(lk) : null
19380
19936
  });
19381
19937
  }
19382
19938
  }
19383
19939
  }
19384
19940
  const viewState = (entry.changeSet.viewState ?? []).map(
19385
- (change) => side === "before" ? invertViewStateChange(change) : change
19941
+ (change) => side === CHANGE_SET_SIDE.BEFORE ? invertViewStateChange(change) : change
19386
19942
  );
19387
19943
  return {
19388
19944
  source: {
19389
- kind: side === "before" ? CHANGE_SET_SOURCE_KIND.UNDO : CHANGE_SET_SOURCE_KIND.REDO
19945
+ kind: side === CHANGE_SET_SIDE.BEFORE ? CHANGE_SET_SOURCE_KIND.UNDO : CHANGE_SET_SOURCE_KIND.REDO
19390
19946
  },
19391
19947
  activities,
19392
19948
  links,
@@ -19401,7 +19957,7 @@ function historyFields(fields, side) {
19401
19957
  return Object.fromEntries(
19402
19958
  Object.entries(fields).map(([field, values]) => [
19403
19959
  field,
19404
- side === "before" ? {
19960
+ side === CHANGE_SET_SIDE.BEFORE ? {
19405
19961
  before: cloneDomainValue(values.after),
19406
19962
  after: cloneDomainValue(values.before)
19407
19963
  } : {
@@ -19432,26 +19988,26 @@ function changeSetIsSubstantive(cs) {
19432
19988
  return cs.activities.length > 0 || cs.links.length > 0 || (cs.viewState?.length ?? 0) > 0 || (cs.effects?.length ?? 0) > 0;
19433
19989
  }
19434
19990
  function applyUndo(state, entry) {
19435
- applyChangeSetSide(state, entry, "before");
19991
+ applyChangeSetSide(state, entry, CHANGE_SET_SIDE.BEFORE);
19436
19992
  }
19437
19993
  function applyRedo(state, entry) {
19438
- applyChangeSetSide(state, entry, "after");
19994
+ applyChangeSetSide(state, entry, CHANGE_SET_SIDE.AFTER);
19439
19995
  }
19440
19996
  function applyChangeSetSide(state, entry, side) {
19441
19997
  const cs = entry.changeSet;
19442
19998
  for (const ch of cs.activities) {
19443
- if (ch.kind === "updated") {
19999
+ if (ch.kind === ENTITY_CHANGE_KIND.UPDATED) {
19444
20000
  if (!ch.fields) continue;
19445
20001
  for (const [field, fieldValue] of Object.entries(ch.fields)) {
19446
20002
  setActivityFieldDynamic(
19447
20003
  state,
19448
20004
  ch.id,
19449
20005
  field,
19450
- side === "before" ? fieldValue.before : fieldValue.after
20006
+ side === CHANGE_SET_SIDE.BEFORE ? fieldValue.before : fieldValue.after
19451
20007
  );
19452
20008
  }
19453
- } else if (ch.kind === "deleted") {
19454
- if (side === "before") {
20009
+ } else if (ch.kind === ENTITY_CHANGE_KIND.DELETED) {
20010
+ if (side === CHANGE_SET_SIDE.BEFORE) {
19455
20011
  const snap = entry.beforeSnap?.get(String(ch.id));
19456
20012
  if (!snap) {
19457
20013
  throw new Error(
@@ -19463,7 +20019,7 @@ function applyChangeSetSide(state, entry, side) {
19463
20019
  state.removeActivity(String(ch.id));
19464
20020
  }
19465
20021
  } else {
19466
- if (side === "before") {
20022
+ if (side === CHANGE_SET_SIDE.BEFORE) {
19467
20023
  state.removeActivity(String(ch.id));
19468
20024
  } else {
19469
20025
  const snap = entry.afterSnap?.get(String(ch.id));
@@ -19477,13 +20033,13 @@ function applyChangeSetSide(state, entry, side) {
19477
20033
  }
19478
20034
  }
19479
20035
  for (const ch of cs.links) {
19480
- if (ch.kind === "updated") {
20036
+ if (ch.kind === ENTITY_CHANGE_KIND.UPDATED) {
19481
20037
  if (!ch.fields) continue;
19482
20038
  if (Object.hasOwn(ch.fields, "source") || Object.hasOwn(ch.fields, "target")) {
19483
- const snapshot = side === "before" ? entry.beforeLinks?.get(String(ch.id)) : entry.afterLinks?.get(String(ch.id));
20039
+ const snapshot = side === CHANGE_SET_SIDE.BEFORE ? entry.beforeLinks?.get(String(ch.id)) : entry.afterLinks?.get(String(ch.id));
19484
20040
  if (!snapshot) {
19485
20041
  throw new Error(
19486
- `${side === "before" ? "undo" : "redo"}: missing link snapshot for ${ch.id}`
20042
+ `${side === CHANGE_SET_SIDE.BEFORE ? "undo" : "redo"}: missing link snapshot for ${ch.id}`
19487
20043
  );
19488
20044
  }
19489
20045
  state.removeLink(String(ch.id));
@@ -19495,11 +20051,11 @@ function applyChangeSetSide(state, entry, side) {
19495
20051
  state,
19496
20052
  String(ch.id),
19497
20053
  field,
19498
- side === "before" ? fv.before : fv.after
20054
+ side === CHANGE_SET_SIDE.BEFORE ? fv.before : fv.after
19499
20055
  );
19500
20056
  }
19501
- } else if (ch.kind === "deleted") {
19502
- if (side === "before") {
20057
+ } else if (ch.kind === ENTITY_CHANGE_KIND.DELETED) {
20058
+ if (side === CHANGE_SET_SIDE.BEFORE) {
19503
20059
  const lk = entry.beforeLinks?.get(String(ch.id));
19504
20060
  if (!lk) {
19505
20061
  throw new Error(
@@ -19511,7 +20067,7 @@ function applyChangeSetSide(state, entry, side) {
19511
20067
  state.removeLink(String(ch.id));
19512
20068
  }
19513
20069
  } else {
19514
- if (side === "before") {
20070
+ if (side === CHANGE_SET_SIDE.BEFORE) {
19515
20071
  state.removeLink(String(ch.id));
19516
20072
  } else {
19517
20073
  const lk = entry.afterLinks?.get(String(ch.id));
@@ -19528,17 +20084,17 @@ function applyChangeSetSide(state, entry, side) {
19528
20084
  if (change.checked) {
19529
20085
  state.setChecked(
19530
20086
  change.activityId,
19531
- side === "before" ? change.checked.before : change.checked.after
20087
+ side === CHANGE_SET_SIDE.BEFORE ? change.checked.before : change.checked.after
19532
20088
  );
19533
20089
  }
19534
20090
  if (change.visible) {
19535
20091
  state.setVisible(
19536
20092
  change.activityId,
19537
- side === "before" ? change.visible.before : change.visible.after
20093
+ side === CHANGE_SET_SIDE.BEFORE ? change.visible.before : change.visible.after
19538
20094
  );
19539
20095
  }
19540
20096
  }
19541
- const progressFallbacks = side === "before" ? entry.progressFallbackBefore : entry.progressFallbackAfter;
20097
+ const progressFallbacks = side === CHANGE_SET_SIDE.BEFORE ? entry.progressFallbackBefore : entry.progressFallbackAfter;
19542
20098
  for (const [activityId, value] of progressFallbacks ?? []) {
19543
20099
  state.setProgressFallback(activityId, value);
19544
20100
  }
@@ -19675,11 +20231,11 @@ function collectResequencedParents(changes, parentOf) {
19675
20231
  };
19676
20232
  for (const change of changes.activities) {
19677
20233
  const activityId = String(change.id);
19678
- if (change.kind === "created") {
20234
+ if (change.kind === ENTITY_CHANGE_KIND.CREATED) {
19679
20235
  addParentOf(activityId);
19680
20236
  continue;
19681
20237
  }
19682
- if (change.kind === "deleted") {
20238
+ if (change.kind === ENTITY_CHANGE_KIND.DELETED) {
19683
20239
  const deletedFields = change.fields;
19684
20240
  if (deletedFields && "parentId" in deletedFields) {
19685
20241
  touched.add(parentKeyOf2(deletedFields.parentId?.before));
@@ -19742,56 +20298,62 @@ function buildStateSnapshot(activities, links, calendars, baseCalendars = []) {
19742
20298
  };
19743
20299
  }
19744
20300
 
20301
+ // src/boundary/save/field-policy.ts
20302
+ var SAVE_FIELD_POLICY = {
20303
+ TRACKED: "tracked",
20304
+ IGNORED: "ignored"
20305
+ };
20306
+
19745
20307
  // src/boundary/save/activity-changes.ts
19746
20308
  var ACTIVITY_SAVE_FIELD_POLICY = {
19747
- id: "ignored",
19748
- proplannerId: "ignored",
19749
- parentId: "tracked",
19750
- name: "tracked",
19751
- description: "tracked",
19752
- type: "tracked",
19753
- startDate: "tracked",
19754
- endDate: "tracked",
19755
- durationHours: "tracked",
19756
- constraintType: "tracked",
19757
- constraintDate: "tracked",
19758
- autoScheduling: "tracked",
19759
- calendarId: "tracked",
19760
- assignedDefaultCalendar: "ignored",
19761
- dateOrigin: "tracked",
19762
- progress: "tracked",
19763
- cost: "tracked",
19764
- usedCost: "tracked",
19765
- realCost: "tracked",
19766
- workHours: "tracked",
19767
- realWorkHours: "tracked",
19768
- ponderator: "tracked",
19769
- hasCustomPonderator: "tracked",
19770
- correlativeId: "tracked",
19771
- uniqueCorrelativeId: "tracked",
19772
- customId: "tracked",
19773
- subcontractId: "tracked",
19774
- isLookahead: "tracked",
19775
- hasLookaheadTasks: "ignored",
19776
- newActivityIds: "tracked",
19777
- hasNewActivities: "tracked",
19778
- isNewActivity: "ignored",
19779
- pendingRequestIds: "ignored",
19780
- responsableIds: "tracked",
19781
- tagIds: "tracked",
19782
- baselinePoints: "ignored",
19783
- baselineSnapshot: "ignored",
19784
- recursiveDurationHours: "ignored",
19785
- isCritical: "ignored",
19786
- freeSlackHours: "ignored",
19787
- calendarDuration: "ignored",
19788
- expectedProgress: "ignored",
19789
- expectedProgressBaseline: "ignored",
19790
- status: "ignored",
19791
- criticalPath: "ignored"
20309
+ id: SAVE_FIELD_POLICY.IGNORED,
20310
+ proplannerId: SAVE_FIELD_POLICY.IGNORED,
20311
+ parentId: SAVE_FIELD_POLICY.TRACKED,
20312
+ name: SAVE_FIELD_POLICY.TRACKED,
20313
+ description: SAVE_FIELD_POLICY.TRACKED,
20314
+ type: SAVE_FIELD_POLICY.TRACKED,
20315
+ startDate: SAVE_FIELD_POLICY.TRACKED,
20316
+ endDate: SAVE_FIELD_POLICY.TRACKED,
20317
+ durationHours: SAVE_FIELD_POLICY.TRACKED,
20318
+ constraintType: SAVE_FIELD_POLICY.TRACKED,
20319
+ constraintDate: SAVE_FIELD_POLICY.TRACKED,
20320
+ autoScheduling: SAVE_FIELD_POLICY.TRACKED,
20321
+ calendarId: SAVE_FIELD_POLICY.TRACKED,
20322
+ assignedDefaultCalendar: SAVE_FIELD_POLICY.IGNORED,
20323
+ dateOrigin: SAVE_FIELD_POLICY.TRACKED,
20324
+ progress: SAVE_FIELD_POLICY.TRACKED,
20325
+ cost: SAVE_FIELD_POLICY.TRACKED,
20326
+ usedCost: SAVE_FIELD_POLICY.TRACKED,
20327
+ realCost: SAVE_FIELD_POLICY.TRACKED,
20328
+ workHours: SAVE_FIELD_POLICY.TRACKED,
20329
+ realWorkHours: SAVE_FIELD_POLICY.TRACKED,
20330
+ ponderator: SAVE_FIELD_POLICY.TRACKED,
20331
+ hasCustomPonderator: SAVE_FIELD_POLICY.TRACKED,
20332
+ correlativeId: SAVE_FIELD_POLICY.TRACKED,
20333
+ uniqueCorrelativeId: SAVE_FIELD_POLICY.TRACKED,
20334
+ customId: SAVE_FIELD_POLICY.TRACKED,
20335
+ subcontractId: SAVE_FIELD_POLICY.TRACKED,
20336
+ isLookahead: SAVE_FIELD_POLICY.TRACKED,
20337
+ hasLookaheadTasks: SAVE_FIELD_POLICY.IGNORED,
20338
+ newActivityIds: SAVE_FIELD_POLICY.TRACKED,
20339
+ hasNewActivities: SAVE_FIELD_POLICY.TRACKED,
20340
+ isNewActivity: SAVE_FIELD_POLICY.IGNORED,
20341
+ pendingRequestIds: SAVE_FIELD_POLICY.IGNORED,
20342
+ responsableIds: SAVE_FIELD_POLICY.TRACKED,
20343
+ tagIds: SAVE_FIELD_POLICY.TRACKED,
20344
+ baselinePoints: SAVE_FIELD_POLICY.IGNORED,
20345
+ baselineSnapshot: SAVE_FIELD_POLICY.IGNORED,
20346
+ recursiveDurationHours: SAVE_FIELD_POLICY.IGNORED,
20347
+ isCritical: SAVE_FIELD_POLICY.IGNORED,
20348
+ freeSlackHours: SAVE_FIELD_POLICY.IGNORED,
20349
+ calendarDuration: SAVE_FIELD_POLICY.IGNORED,
20350
+ expectedProgress: SAVE_FIELD_POLICY.IGNORED,
20351
+ expectedProgressBaseline: SAVE_FIELD_POLICY.IGNORED,
20352
+ status: SAVE_FIELD_POLICY.IGNORED,
20353
+ criticalPath: SAVE_FIELD_POLICY.IGNORED
19792
20354
  };
19793
20355
  var PERSISTABLE_ACTIVITY_FIELDS = Object.keys(ACTIVITY_SAVE_FIELD_POLICY).filter((field) => {
19794
- return ACTIVITY_SAVE_FIELD_POLICY[field] === "tracked";
20356
+ return ACTIVITY_SAVE_FIELD_POLICY[field] === SAVE_FIELD_POLICY.TRACKED;
19795
20357
  });
19796
20358
  var DATE_FIELDS2 = /* @__PURE__ */ new Set([
19797
20359
  "startDate",
@@ -19850,19 +20412,19 @@ function idArrayEquals(current, saved) {
19850
20412
 
19851
20413
  // src/boundary/save/link-changes.ts
19852
20414
  var LINK_SAVE_FIELD_POLICY = {
19853
- id: "ignored",
19854
- source: "tracked",
19855
- target: "tracked",
19856
- type: "tracked",
19857
- lag: "tracked",
19858
- freeSlackHours: "ignored",
19859
- isCritical: "ignored",
19860
- ganttId: "ignored",
19861
- sectorId: "ignored",
19862
- proplannerId: "ignored"
20415
+ id: SAVE_FIELD_POLICY.IGNORED,
20416
+ source: SAVE_FIELD_POLICY.TRACKED,
20417
+ target: SAVE_FIELD_POLICY.TRACKED,
20418
+ type: SAVE_FIELD_POLICY.TRACKED,
20419
+ lag: SAVE_FIELD_POLICY.TRACKED,
20420
+ freeSlackHours: SAVE_FIELD_POLICY.IGNORED,
20421
+ isCritical: SAVE_FIELD_POLICY.IGNORED,
20422
+ ganttId: SAVE_FIELD_POLICY.IGNORED,
20423
+ sectorId: SAVE_FIELD_POLICY.IGNORED,
20424
+ proplannerId: SAVE_FIELD_POLICY.IGNORED
19863
20425
  };
19864
20426
  var TRACKED_LINK_FIELDS = Object.keys(LINK_SAVE_FIELD_POLICY).filter((field) => {
19865
- return LINK_SAVE_FIELD_POLICY[field] === "tracked";
20427
+ return LINK_SAVE_FIELD_POLICY[field] === SAVE_FIELD_POLICY.TRACKED;
19866
20428
  });
19867
20429
  function linkChangedSince(baseline, current) {
19868
20430
  return TRACKED_LINK_FIELDS.some(
@@ -20223,24 +20785,24 @@ var WORKING_DAY_TRUE_VALUES = /* @__PURE__ */ new Set([
20223
20785
  "true"
20224
20786
  ]);
20225
20787
  var DEFAULT_ACTIVITY_CRETER = ACTIVITY_PONDERATOR_CRITERION.DURATION;
20226
- var DEFAULT_CONSTRAINT_TYPE = "asap";
20788
+ var DEFAULT_CONSTRAINT_TYPE = CONSTRAINT_TYPE.ASAP;
20227
20789
  var CONSTRAINT_LABEL_MAP = {
20228
- ASAP: "asap",
20229
- ALAP: "alap",
20230
- SNET: "snet",
20231
- SNLT: "snlt",
20232
- FNET: "fnet",
20233
- FNLT: "fnlt",
20234
- MSO: "mso",
20235
- MFO: "mfo",
20236
- "AS SOON AS POSSIBLE": "asap",
20237
- "AS LATE AS POSSIBLE": "alap",
20238
- "START NO EARLIER THAN": "snet",
20239
- "START NO LATER THAN": "snlt",
20240
- "FINISH NO EARLIER THAN": "fnet",
20241
- "FINISH NO LATER THAN": "fnlt",
20242
- "MUST START ON": "mso",
20243
- "MUST FINISH ON": "mfo"
20790
+ ASAP: CONSTRAINT_TYPE.ASAP,
20791
+ ALAP: CONSTRAINT_TYPE.ALAP,
20792
+ SNET: CONSTRAINT_TYPE.SNET,
20793
+ SNLT: CONSTRAINT_TYPE.SNLT,
20794
+ FNET: CONSTRAINT_TYPE.FNET,
20795
+ FNLT: CONSTRAINT_TYPE.FNLT,
20796
+ MSO: CONSTRAINT_TYPE.MSO,
20797
+ MFO: CONSTRAINT_TYPE.MFO,
20798
+ "AS SOON AS POSSIBLE": CONSTRAINT_TYPE.ASAP,
20799
+ "AS LATE AS POSSIBLE": CONSTRAINT_TYPE.ALAP,
20800
+ "START NO EARLIER THAN": CONSTRAINT_TYPE.SNET,
20801
+ "START NO LATER THAN": CONSTRAINT_TYPE.SNLT,
20802
+ "FINISH NO EARLIER THAN": CONSTRAINT_TYPE.FNET,
20803
+ "FINISH NO LATER THAN": CONSTRAINT_TYPE.FNLT,
20804
+ "MUST START ON": CONSTRAINT_TYPE.MSO,
20805
+ "MUST FINISH ON": CONSTRAINT_TYPE.MFO
20244
20806
  };
20245
20807
 
20246
20808
  // src/boundary/backend/normalize-activity.ts
@@ -20253,13 +20815,19 @@ function normalizeActivities(rawActivities, context) {
20253
20815
  });
20254
20816
  forceRootProjectToRoot(activities);
20255
20817
  const activityIds = new Set(activities.map((activity) => activity.id));
20256
- reparentOrphansToRoot(activities, activityIds, context.reporter);
20818
+ reparentOrphansToRoot(
20819
+ activities,
20820
+ activityIds,
20821
+ context.reporter,
20822
+ context.recordDiagnostic
20823
+ );
20257
20824
  return { activities, activityIds, hiddenIds };
20258
20825
  }
20259
- function parseConstraintLabel(label, reporter) {
20826
+ function parseConstraintLabel(label, reporter, recordDiagnostic, activityId) {
20260
20827
  if (!label) return null;
20261
20828
  const normalized2 = CONSTRAINT_LABEL_MAP[label.toUpperCase()];
20262
20829
  if (normalized2 === void 0) {
20830
+ recordDiagnostic(LOAD_DIAGNOSTIC_CODE.UNKNOWN_CONSTRAINT, activityId);
20263
20831
  reporter.warn(
20264
20832
  `[parseFromBackend] unknown constraint label "${label}" \u2014 defaulting to "asap"`
20265
20833
  );
@@ -20267,9 +20835,14 @@ function parseConstraintLabel(label, reporter) {
20267
20835
  }
20268
20836
  return normalized2;
20269
20837
  }
20270
- function resolveConstraint(raw, reporter) {
20271
- const constraintType = parseConstraintLabel(raw.constraint, reporter);
20272
- const constraintTakesDate = constraintType !== "asap" && constraintType !== "alap";
20838
+ function resolveConstraint(raw, reporter, recordDiagnostic) {
20839
+ const constraintType = parseConstraintLabel(
20840
+ raw.constraint,
20841
+ reporter,
20842
+ recordDiagnostic,
20843
+ String(raw.unique_id)
20844
+ );
20845
+ const constraintTakesDate = constraintType !== CONSTRAINT_TYPE.ASAP && constraintType !== CONSTRAINT_TYPE.ALAP;
20273
20846
  const constraintDate = constraintTakesDate && raw.constraint_date ? parseBackendDate(raw.constraint_date) : null;
20274
20847
  return { constraintType, constraintDate };
20275
20848
  }
@@ -20324,9 +20897,14 @@ function parseCriticality(raw, reporter) {
20324
20897
  );
20325
20898
  return false;
20326
20899
  }
20327
- function parseBaselinePoints(raw, reporter) {
20900
+ function parseBaselinePoints(raw, reporter, recordDiagnostic, activityId) {
20328
20901
  if (!Array.isArray(raw)) return [];
20329
- return raw.map((point) => normalizeBaselinePoint(point, reporter)).filter((point) => point !== null);
20902
+ return raw.map(
20903
+ (point) => normalizeBaselinePoint(point, reporter, {
20904
+ record: recordDiagnostic,
20905
+ sampleId: activityId
20906
+ })
20907
+ ).filter((point) => point !== null);
20330
20908
  }
20331
20909
  function parseActivity(raw, context) {
20332
20910
  const calendarId = resolveCalendarId2(
@@ -20338,9 +20916,10 @@ function parseActivity(raw, context) {
20338
20916
  const progress = Number(raw.progress);
20339
20917
  const { constraintType, constraintDate } = resolveConstraint(
20340
20918
  raw,
20341
- context.reporter
20919
+ context.reporter,
20920
+ context.recordDiagnostic
20342
20921
  );
20343
- const isMilestone = raw.type === "milestone";
20922
+ const isMilestone = raw.type === ACTIVITY_TYPE.MILESTONE;
20344
20923
  const startDate = parseBackendDate(raw.start_date);
20345
20924
  const endDate = isMilestone ? startDate : parseBackendDate(raw.end_date);
20346
20925
  const durationDays = isMilestone ? 0 : Number(raw.duration);
@@ -20381,7 +20960,12 @@ function parseActivity(raw, context) {
20381
20960
  pendingRequestIds: parseIdList(raw.pendingRequests),
20382
20961
  responsableIds: parseIdList(raw.responsables),
20383
20962
  tagIds: parseIdList(raw.tags),
20384
- baselinePoints: parseBaselinePoints(raw.baseline_points, context.reporter),
20963
+ baselinePoints: parseBaselinePoints(
20964
+ raw.baseline_points,
20965
+ context.reporter,
20966
+ context.recordDiagnostic,
20967
+ String(raw.unique_id)
20968
+ ),
20385
20969
  baselineSnapshot: null,
20386
20970
  recursiveDurationHours: durationToHours(
20387
20971
  Number(raw.sumOfDurationRecursively ?? 0),
@@ -20405,17 +20989,18 @@ function normalizeCustomId(raw) {
20405
20989
  }
20406
20990
  function forceRootProjectToRoot(activities) {
20407
20991
  const rootProject = activities.find(
20408
- (activity) => activity.correlativeId === 0 && activity.type === "project"
20992
+ (activity) => activity.correlativeId === 0 && activity.type === ACTIVITY_TYPE.PROJECT
20409
20993
  );
20410
20994
  if (rootProject) rootProject.parentId = null;
20411
20995
  }
20412
- function reparentOrphansToRoot(activities, ids, reporter) {
20996
+ function reparentOrphansToRoot(activities, ids, reporter, recordDiagnostic) {
20413
20997
  for (const activity of activities) {
20414
20998
  if (activity.parentId === null) continue;
20415
20999
  if (!ids.has(activity.parentId)) {
20416
21000
  reporter.warn(
20417
21001
  `[parseFromBackend] activity "${activity.id}" references unknown parent "${activity.parentId}" \u2014 re-parenting to root (null)`
20418
21002
  );
21003
+ recordDiagnostic(LOAD_DIAGNOSTIC_CODE.ORPHAN_ACTIVITY, activity.id);
20419
21004
  activity.parentId = null;
20420
21005
  }
20421
21006
  }
@@ -20639,14 +21224,11 @@ function isMissingValue(value) {
20639
21224
  }
20640
21225
 
20641
21226
  // src/boundary/backend/normalize-link.ts
20642
- function isLinkTypeCode(value) {
20643
- return value === "0" || value === "1" || value === "2" || value === "3";
20644
- }
20645
21227
  function resolveLinkType(rawType) {
20646
21228
  if (typeof rawType !== "string") return null;
20647
21229
  const fromLabel = parseLinkTypeCode(rawType);
20648
21230
  if (fromLabel) return fromLabel;
20649
- if (isLinkTypeCode(rawType)) return rawType;
21231
+ if (isLinkType(rawType)) return rawType;
20650
21232
  return null;
20651
21233
  }
20652
21234
  function normalizePersistedLinkId(rawId) {
@@ -20665,13 +21247,17 @@ function normalizeLinks(rawLinks, context) {
20665
21247
  parseLink(rawLink, context.knownActivityIds, context.hoursPerDay)
20666
21248
  );
20667
21249
  } catch (parseError2) {
21250
+ context.recordDiagnostic(
21251
+ LOAD_DIAGNOSTIC_CODE.INVALID_LINK,
21252
+ String(rawLink.unique_id ?? rawLink.id)
21253
+ );
20668
21254
  context.reporter.warn(
20669
21255
  "[parseFromBackend] dropping invalid link",
20670
21256
  parseError2
20671
21257
  );
20672
21258
  }
20673
21259
  }
20674
- return dedupeLinksBySignature(parsedLinks);
21260
+ return dedupeLinksBySignature(parsedLinks, context.recordDiagnostic);
20675
21261
  }
20676
21262
  function parseLink(link, activityIds, hoursPerDay) {
20677
21263
  const id = String(link.unique_id ?? link.id);
@@ -20709,12 +21295,19 @@ function parseLink(link, activityIds, hoursPerDay) {
20709
21295
  ...proplannerId === void 0 ? {} : { proplannerId }
20710
21296
  };
20711
21297
  }
20712
- function dedupeLinksBySignature(links) {
21298
+ function dedupeLinksBySignature(links, recordDiagnostic) {
20713
21299
  const bySignature = /* @__PURE__ */ new Map();
20714
21300
  for (const link of links) {
20715
21301
  const signature = `${link.source}-${link.target}-${link.type}`;
20716
21302
  const existing = bySignature.get(signature);
20717
- if (!existing || linkIdAsNumber(link) > linkIdAsNumber(existing)) {
21303
+ if (!existing) {
21304
+ bySignature.set(signature, link);
21305
+ continue;
21306
+ }
21307
+ const incomingWins = linkIdAsNumber(link) > linkIdAsNumber(existing);
21308
+ const discarded = incomingWins ? existing : link;
21309
+ recordDiagnostic(LOAD_DIAGNOSTIC_CODE.DUPLICATE_LINK, discarded.id);
21310
+ if (incomingWins) {
20718
21311
  bySignature.set(signature, link);
20719
21312
  }
20720
21313
  }
@@ -20772,7 +21365,7 @@ function parseSector(sector) {
20772
21365
  }
20773
21366
 
20774
21367
  // src/boundary/backend/parse-from-backend.ts
20775
- function parseFromBackend(input, reporter = noopReporter) {
21368
+ function parseFromBackend(input, reporter = noopReporter, recordDiagnostic = noopLoadDiagnosticRecorder) {
20776
21369
  const sector = parseSector(input.sector);
20777
21370
  const { calendars, baseCalendars, knownCalendarIds, defaultCalendarId } = normalizeCalendars(
20778
21371
  input.calendars,
@@ -20786,13 +21379,15 @@ function parseFromBackend(input, reporter = noopReporter) {
20786
21379
  knownCalendarIds,
20787
21380
  defaultCalendarId,
20788
21381
  hoursPerDay: sector.hoursPerDay,
20789
- reporter
21382
+ reporter,
21383
+ recordDiagnostic
20790
21384
  }
20791
21385
  );
20792
21386
  const links = normalizeLinks(input.links, {
20793
21387
  knownActivityIds: activityIds,
20794
21388
  hoursPerDay: sector.hoursPerDay,
20795
- reporter
21389
+ reporter,
21390
+ recordDiagnostic
20796
21391
  });
20797
21392
  return {
20798
21393
  sector,
@@ -21008,6 +21603,11 @@ function maxSuffixFromArray(suffixes) {
21008
21603
  }
21009
21604
 
21010
21605
  // src/generators/custom-id/generation-strategies.ts
21606
+ var GENERATION_STRATEGY = {
21607
+ PARENT_CONVERSION: "parentConversion",
21608
+ PASTE_REFERENCE: "pasteReference",
21609
+ NO_CONTEXT: "noContext"
21610
+ };
21011
21611
  function parentConversionStrategy(defaultPrefix) {
21012
21612
  return { prefix: defaultPrefix, baseSuffix: null };
21013
21613
  }
@@ -21023,12 +21623,12 @@ function noContextStrategy(defaultPrefix) {
21023
21623
  }
21024
21624
  function selectGenerationStrategy(customId, useActivityCustomIdAsReference) {
21025
21625
  if (isParentConversionCase(customId, useActivityCustomIdAsReference)) {
21026
- return "parentConversion";
21626
+ return GENERATION_STRATEGY.PARENT_CONVERSION;
21027
21627
  }
21028
21628
  if (isPasteOrLineReferenceCase(customId, useActivityCustomIdAsReference)) {
21029
- return "pasteReference";
21629
+ return GENERATION_STRATEGY.PASTE_REFERENCE;
21030
21630
  }
21031
- return "noContext";
21631
+ return GENERATION_STRATEGY.NO_CONTEXT;
21032
21632
  }
21033
21633
 
21034
21634
  // src/generators/custom-id/tracker.ts
@@ -21341,15 +21941,15 @@ var CustomIdTracker = class _CustomIdTracker {
21341
21941
  customId
21342
21942
  );
21343
21943
  let capturedNextSuffix = null;
21344
- if (strategyKey === "parentConversion" && this.prefixMap.has(prefix)) {
21944
+ if (strategyKey === GENERATION_STRATEGY.PARENT_CONVERSION && this.prefixMap.has(prefix)) {
21345
21945
  this._ensureFreshBounds(prefix);
21346
21946
  const currentMax = this.prefixMap.get(prefix).max;
21347
21947
  capturedNextSuffix = addToSuffix(currentMax, this.suffixIncrement);
21348
21948
  }
21349
- if (strategyKey === "parentConversion") {
21949
+ if (strategyKey === GENERATION_STRATEGY.PARENT_CONVERSION) {
21350
21950
  this.releaseCustomId(customId);
21351
21951
  }
21352
- const effectiveBaseSuffix = strategyKey === "parentConversion" && capturedNextSuffix ? capturedNextSuffix : baseSuffix;
21952
+ const effectiveBaseSuffix = strategyKey === GENERATION_STRATEGY.PARENT_CONVERSION && capturedNextSuffix ? capturedNextSuffix : baseSuffix;
21353
21953
  const nextSuffix = this.getNextAvailableSuffix(prefix, effectiveBaseSuffix);
21354
21954
  if (nextSuffix === null) {
21355
21955
  const generatedId2 = this._generateDefaultCustomId();
@@ -21365,9 +21965,9 @@ var CustomIdTracker = class _CustomIdTracker {
21365
21965
  }
21366
21966
  _applyGenerationStrategy(strategyKey, customId) {
21367
21967
  switch (strategyKey) {
21368
- case "parentConversion":
21968
+ case GENERATION_STRATEGY.PARENT_CONVERSION:
21369
21969
  return parentConversionStrategy(this.defaultPrefix);
21370
- case "pasteReference":
21970
+ case GENERATION_STRATEGY.PASTE_REFERENCE:
21371
21971
  return pasteReferenceStrategy(customId, this.suffixIncrement);
21372
21972
  default:
21373
21973
  return noContextStrategy(this.defaultPrefix);
@@ -21483,7 +22083,7 @@ function buildComparator(order, context) {
21483
22083
  function demoteChildlessSummaries(state) {
21484
22084
  const idsToDemote = [];
21485
22085
  state.forEachActivity((activity, activityId) => {
21486
- if (activity.type !== "project") return;
22086
+ if (activity.type !== ACTIVITY_TYPE.PROJECT) return;
21487
22087
  if (state.getChildren(String(activityId)).length === 0) {
21488
22088
  idsToDemote.push(String(activityId));
21489
22089
  }
@@ -21601,7 +22201,7 @@ function normalizeLoadedConstraintDates(state) {
21601
22201
  const type = activity.constraintType;
21602
22202
  if (!type || !activity.constraintDate) return;
21603
22203
  const constraintDate = activity.constraintDate;
21604
- if (activity.type === "milestone" && (constraintDate.getUTCHours() !== 0 || constraintDate.getUTCMinutes() !== 0)) {
22204
+ if (activity.type === ACTIVITY_TYPE.MILESTONE && (constraintDate.getUTCHours() !== 0 || constraintDate.getUTCMinutes() !== 0)) {
21605
22205
  return;
21606
22206
  }
21607
22207
  const calendar = state.calendarReader.getCalendar(
@@ -21617,7 +22217,7 @@ function normalizeLoadedConstraintDates(state) {
21617
22217
  }
21618
22218
  function normalizeMilestoneConstraintDatesForDisplay(state) {
21619
22219
  state.forEachActivity((activity) => {
21620
- if (activity.type !== "milestone") return;
22220
+ if (activity.type !== ACTIVITY_TYPE.MILESTONE) return;
21621
22221
  const type = activity.constraintType;
21622
22222
  if (!type || !activity.constraintDate) return;
21623
22223
  const calendar = state.calendarReader.getCalendar(
@@ -21643,6 +22243,7 @@ function initializeCore(input) {
21643
22243
  const initializedAt = clock?.() ?? null;
21644
22244
  const loadNow = initializedAt ? endOfLocalDay(initializedAt) : null;
21645
22245
  const reporter = input.reporter ?? noopReporter;
22246
+ const loadDiagnostics = createLoadDiagnosticsCollector();
21646
22247
  const parsed2 = parseFromBackend(
21647
22248
  {
21648
22249
  sector: input.sector,
@@ -21651,7 +22252,8 @@ function initializeCore(input) {
21651
22252
  calendars: input.calendars,
21652
22253
  baseCalendars: input.baseCalendars
21653
22254
  },
21654
- reporter
22255
+ reporter,
22256
+ loadDiagnostics.record
21655
22257
  );
21656
22258
  const sector = parsed2.sector;
21657
22259
  sector.statusCriteria = resolveStatusCriteria(input.statusCriteria);
@@ -21691,7 +22293,8 @@ function initializeCore(input) {
21691
22293
  input.baselinePoints,
21692
22294
  loadNow,
21693
22295
  reporter,
21694
- defaultBaseCalendarId
22296
+ defaultBaseCalendarId,
22297
+ loadDiagnostics.record
21695
22298
  );
21696
22299
  }
21697
22300
  const initPromise = runInitialPasses({
@@ -21713,6 +22316,7 @@ function initializeCore(input) {
21713
22316
  baseCalendars,
21714
22317
  clock,
21715
22318
  reporter,
22319
+ loadDiagnostics: loadDiagnostics.snapshot,
21716
22320
  initPromise
21717
22321
  };
21718
22322
  }
@@ -21774,18 +22378,22 @@ function entityChanges(target, source) {
21774
22378
  const before = sourceById.get(id);
21775
22379
  const after = targetById.get(id);
21776
22380
  if (after === void 0) {
21777
- changes.push({ id, kind: "deleted", after: null });
22381
+ changes.push({ id, kind: ENTITY_CHANGE_KIND.DELETED, after: null });
21778
22382
  continue;
21779
22383
  }
21780
22384
  if (before === void 0) {
21781
- changes.push({ id, kind: "created", after: cloneDomainValue(after) });
22385
+ changes.push({
22386
+ id,
22387
+ kind: ENTITY_CHANGE_KIND.CREATED,
22388
+ after: cloneDomainValue(after)
22389
+ });
21782
22390
  continue;
21783
22391
  }
21784
22392
  const fields = changedFields(before, after);
21785
22393
  if (Object.keys(fields).length > 0) {
21786
22394
  changes.push({
21787
22395
  id,
21788
- kind: "updated",
22396
+ kind: ENTITY_CHANGE_KIND.UPDATED,
21789
22397
  fields,
21790
22398
  after: cloneDomainValue(after)
21791
22399
  });
@@ -22000,8 +22608,8 @@ function acknowledgesPersistence(action) {
22000
22608
  }
22001
22609
  function changesRequireFilterProjectionRebuild(changes) {
22002
22610
  for (const change of changes.activities) {
22003
- if (change.kind === "deleted") return true;
22004
- const hasMovedParent = change.kind === "updated" && change.fields !== void 0 && "parentId" in change.fields;
22611
+ if (change.kind === ENTITY_CHANGE_KIND.DELETED) return true;
22612
+ const hasMovedParent = change.kind === ENTITY_CHANGE_KIND.UPDATED && change.fields !== void 0 && "parentId" in change.fields;
22005
22613
  if (hasMovedParent) return true;
22006
22614
  }
22007
22615
  return false;
@@ -22053,6 +22661,7 @@ var ScheduleCore = class _ScheduleCore {
22053
22661
  _undo = new UndoRecorder();
22054
22662
  _opQueue = Promise.resolve();
22055
22663
  _scheduleRevision = 0;
22664
+ _stateRevision = 0;
22056
22665
  _pendingScheduleRevision = 0;
22057
22666
  _criticalPathRevision = -1;
22058
22667
  _activeCriticalPath = null;
@@ -22078,7 +22687,8 @@ var ScheduleCore = class _ScheduleCore {
22078
22687
  ),
22079
22688
  baseCalendars: cloneDomainValue(source.coreRuntime.baseCalendars),
22080
22689
  clock: source.coreRuntime.clock,
22081
- reporter: source.coreRuntime.reporter
22690
+ reporter: source.coreRuntime.reporter,
22691
+ loadDiagnostics: source.coreRuntime.loadDiagnostics
22082
22692
  };
22083
22693
  this._activityClipboard.value = cloneDomainValue(
22084
22694
  source._activityClipboard.value
@@ -22086,6 +22696,7 @@ var ScheduleCore = class _ScheduleCore {
22086
22696
  this._undo = source._undo.fork();
22087
22697
  this._saveTracker = source._saveTracker.fork();
22088
22698
  this._scheduleRevision = source._scheduleRevision;
22699
+ this._stateRevision = source._stateRevision;
22089
22700
  this._pendingScheduleRevision = source._scheduleRevision;
22090
22701
  this._criticalPathRevision = source._criticalPathRevision;
22091
22702
  this._initPromise = Promise.resolve();
@@ -22108,7 +22719,8 @@ var ScheduleCore = class _ScheduleCore {
22108
22719
  initialized.calendars.map((calendar) => [calendar.id, calendar])
22109
22720
  ),
22110
22721
  baseCalendars: initialized.baseCalendars,
22111
- reporter: initialized.reporter
22722
+ reporter: initialized.reporter,
22723
+ loadDiagnostics: initialized.loadDiagnostics
22112
22724
  };
22113
22725
  this._initPromise = initialized.initPromise.then(() => {
22114
22726
  if (this._status === SCHEDULE_CORE_STATUS.DESTROYED) return;
@@ -22173,6 +22785,11 @@ var ScheduleCore = class _ScheduleCore {
22173
22785
  getSector() {
22174
22786
  return cloneDomainValue(this.coreRuntime.sector);
22175
22787
  }
22788
+ /** Returns immutable data-quality diagnostics collected during loading. */
22789
+ getLoadDiagnostics() {
22790
+ this.assertReady();
22791
+ return this.coreRuntime.loadDiagnostics();
22792
+ }
22176
22793
  /**
22177
22794
  * Reads a defensive activity snapshot from a ready schedule.
22178
22795
  *
@@ -22183,6 +22800,17 @@ var ScheduleCore = class _ScheduleCore {
22183
22800
  this.assertReady();
22184
22801
  return readActivity(this.coreRuntime.state, id);
22185
22802
  }
22803
+ /** Returns the canonical progress editability decision without mutation. */
22804
+ getProgressEditability(id) {
22805
+ this.assertReady();
22806
+ const activity = readActivity(this.coreRuntime.state, id);
22807
+ if (!activity) return null;
22808
+ const context = buildPipelineContext(this.coreRuntime.state, {
22809
+ hoursPerDay: this.coreRuntime.sector.hoursPerDay,
22810
+ dateFormat: this.coreRuntime.sector.dateFormat
22811
+ });
22812
+ return progressPipeline.canEdit(activity, context.hierarchy);
22813
+ }
22186
22814
  /**
22187
22815
  * Creates a read-only date prediction bound to the current revision.
22188
22816
  *
@@ -22442,6 +23070,10 @@ var ScheduleCore = class _ScheduleCore {
22442
23070
  getScheduleRevision() {
22443
23071
  return this._scheduleRevision;
22444
23072
  }
23073
+ /** @returns The monotonic canonical-state revision without a readiness guard. */
23074
+ getStateRevision() {
23075
+ return this._stateRevision;
23076
+ }
22445
23077
  /** @returns The undo-history boundary for an external save checkpoint. */
22446
23078
  capturePersistenceHistoryBoundary() {
22447
23079
  this.assertReady();
@@ -22551,6 +23183,21 @@ var ScheduleCore = class _ScheduleCore {
22551
23183
  const admitted = this._beginScheduleMutation(action);
22552
23184
  return this._enqueue(() => this._dispatchInner(action, options, admitted));
22553
23185
  }
23186
+ /** Builds the defensive canonical conversion intent without mutating state. */
23187
+ planLookaheadConversion(input) {
23188
+ this.assertReady();
23189
+ return buildLookaheadConversionPlan(input, {
23190
+ adapter: this.coreRuntime.state,
23191
+ stateRevision: this._stateRevision
23192
+ });
23193
+ }
23194
+ /** Applies one revision-guarded conversion through the serialized dispatcher. */
23195
+ applyLookaheadConversion(input) {
23196
+ return this.dispatch({
23197
+ ...input,
23198
+ kind: DISPATCH_ACTION_KIND.ACTIVITY_LOOKAHEAD_CONVERT
23199
+ });
23200
+ }
22554
23201
  async _dispatchInner(action, options = {}, admitted = false) {
22555
23202
  let changedState = false;
22556
23203
  try {
@@ -22601,6 +23248,7 @@ var ScheduleCore = class _ScheduleCore {
22601
23248
  customIdTracker: this.coreRuntime.customIdTracker,
22602
23249
  reporter: this.coreRuntime.reporter,
22603
23250
  activityClipboard: this._activityClipboard,
23251
+ stateRevision: this._stateRevision,
22604
23252
  defaultBaseCalendarId: this.coreRuntime.baseCalendars.find(
22605
23253
  (calendar) => calendar.baseDefault
22606
23254
  )?.id ?? null,
@@ -22618,7 +23266,7 @@ var ScheduleCore = class _ScheduleCore {
22618
23266
  this.coreRuntime.state.endWriteCapture();
22619
23267
  this.coreRuntime.customIdTracker.commitCustomIdTransaction();
22620
23268
  }
22621
- if (result.ok && historyPolicy === "record" && changeSetIsSubstantive(result.changes)) {
23269
+ if (result.ok && historyPolicy === DISPATCH_HISTORY_POLICY.RECORD && changeSetIsSubstantive(result.changes)) {
22622
23270
  const created = captureCreatedSnapshots(
22623
23271
  this.coreRuntime.state,
22624
23272
  result.changes
@@ -22644,7 +23292,7 @@ var ScheduleCore = class _ScheduleCore {
22644
23292
  );
22645
23293
  }
22646
23294
  if (result.ok) {
22647
- if (historyPolicy === "checkpoint-on-success") {
23295
+ if (historyPolicy === DISPATCH_HISTORY_POLICY.CHECKPOINT_ON_SUCCESS) {
22648
23296
  if (action.kind !== DISPATCH_ACTION_KIND.PERSISTENCE_ACKNOWLEDGE) {
22649
23297
  throw new Error(
22650
23298
  "checkpoint-on-success requires persistence acknowledge"
@@ -22686,7 +23334,9 @@ var ScheduleCore = class _ScheduleCore {
22686
23334
  }
22687
23335
  result = this._withReappliedViewState(action, result);
22688
23336
  if (!result.ok) return { result, changedState: false };
22689
- if (dispatchChangesSchedulingState(action) && changeSetIsSubstantive(result.changes)) {
23337
+ const hasSubstantiveChanges = changeSetIsSubstantive(result.changes);
23338
+ if (hasSubstantiveChanges) this._stateRevision++;
23339
+ if (dispatchChangesSchedulingState(action) && hasSubstantiveChanges) {
22690
23340
  this._recordScheduleMutation(
22691
23341
  options.skipAutoSchedule !== true && options.skipCriticalPath !== true && resolveRunCriticalPath(action)
22692
23342
  );
@@ -22761,7 +23411,7 @@ var ScheduleCore = class _ScheduleCore {
22761
23411
  }
22762
23412
  const affectedParents = new Set(resequencedParents);
22763
23413
  for (const change of changes.activities) {
22764
- if (change.kind === "deleted") {
23414
+ if (change.kind === ENTITY_CHANGE_KIND.DELETED) {
22765
23415
  return { ...changes, order: collectBranchOrder(adapter) };
22766
23416
  }
22767
23417
  const parentId = adapter.getParentId(change.id);
@@ -22955,7 +23605,7 @@ var ScheduleCore = class _ScheduleCore {
22955
23605
  const changes = buildInverseChangeSet(
22956
23606
  this.coreRuntime.state,
22957
23607
  entry,
22958
- "before"
23608
+ CHANGE_SET_SIDE.BEFORE
22959
23609
  );
22960
23610
  this._saveTracker.recordChanges(
22961
23611
  changes.activities,
@@ -23012,7 +23662,7 @@ var ScheduleCore = class _ScheduleCore {
23012
23662
  const changes = buildInverseChangeSet(
23013
23663
  this.coreRuntime.state,
23014
23664
  entry,
23015
- "after"
23665
+ CHANGE_SET_SIDE.AFTER
23016
23666
  );
23017
23667
  this._saveTracker.recordChanges(
23018
23668
  changes.activities,
@@ -23073,6 +23723,7 @@ var ScheduleCore = class _ScheduleCore {
23073
23723
  _rollback(generatorSnapshot) {
23074
23724
  try {
23075
23725
  this.coreRuntime.state.restoreFromCapture();
23726
+ this.coreRuntime.scheduler.invalidateAllCaches();
23076
23727
  this.coreRuntime.customIdTracker.rollbackCustomIdTransaction();
23077
23728
  if (generatorSnapshot) {
23078
23729
  this.coreRuntime.activityIdGenerator.restore(generatorSnapshot[0]);
@@ -23133,6 +23784,6 @@ var CREATION_KIND = {
23133
23784
  ROOT: "root"
23134
23785
  };
23135
23786
 
23136
- export { ACTIVITY_BATCH_ACTION_KIND, ACTIVITY_BATCH_MODE, ACTIVITY_DATE_EDGE, ACTIVITY_FIELD, ACTIVITY_PONDERATOR_CRITERION, ACTIVITY_TYPE, CALENDAR_UNIT, CHANGE_SET_SOURCE_KIND, COLUMN, COMPLETED_PROGRESS, CONSTRAINT_TYPE, CONSTRAINT_TYPE_TO_LABEL, CONSTRAINT_WARNING_KIND, CREATION_KIND, DATE_GESTURE_KIND, DEFAULT_HOURS_PER_DAY, DISPATCH_ACTION_KIND, DISPATCH_ACTION_KINDS, DISPATCH_LINK_OPERATION_KIND, DISPATCH_TRACK_EVENT, FILTER_FIELD, FILTER_LOGIC, FILTER_OPERATOR, FILTER_REJECTION_REASON, FILTER_VALUE_KIND, LINK_BATCH_OPERATION_KIND, LINK_CODE_TO_TYPE, LINK_REJECTION_REASON, LINK_RELATIONSHIP, LINK_TYPE, LINK_TYPE_CODE, NEW_ACTIVITY_DEFAULTS, NOT_STARTED_PROGRESS, ORDER_DIRECTION, REJECTION_REASON, ROOT_PARENT_ID, SCHEDULE_CORE_STATUS, SCHEDULE_EFFECT_KIND, SIR_AUTO_REJECT_REASON, STATUS, STATUS_CRITERIA, ScheduleCore, WORK_TIME_DIRECTION, checkNoUpdatedLinks, computeExpectedProgress, createSchedule, expectedProgressFromBaseline, getActiveBaseline, getUnsavedActivities, isRootParent, normalizeParentKey, parseFromBackend, willRunCriticalPath, yieldToBrowser };
23787
+ export { ACTIVITY_BATCH_ACTION_KIND, ACTIVITY_BATCH_MODE, ACTIVITY_DATE_EDGE, ACTIVITY_FIELD, ACTIVITY_PONDERATOR_CRITERION, ACTIVITY_PROGRESS_ORIGIN, ACTIVITY_TYPE, CALENDAR_UNIT, CHANGE_SET_SOURCE_KIND, COLUMN, COMPLETED_PROGRESS, CONSTRAINT_TYPE, CONSTRAINT_TYPE_TO_LABEL, CONSTRAINT_WARNING_KIND, CREATION_KIND, DATE_GESTURE_KIND, DEFAULT_HOURS_PER_DAY, DISPATCH_ACTION_KIND, DISPATCH_ACTION_KINDS, DISPATCH_LINK_OPERATION_KIND, DISPATCH_TRACK_EVENT, EDIT_ALERT_KEY, EDIT_DENIAL_REASON, ENTITY_CHANGE_KIND, FILTER_FIELD, FILTER_LOGIC, FILTER_OPERATOR, FILTER_REJECTION_REASON, FILTER_VALUE_KIND, LINK_BATCH_OPERATION_KIND, LINK_CODE, LINK_CODE_TO_TYPE, LINK_REJECTION_REASON, LINK_RELATIONSHIP, LINK_TYPE, LINK_TYPE_CODE, NEW_ACTIVITY_DEFAULTS, NOT_STARTED_PROGRESS, ORDER_DIRECTION, REJECTION_REASON, ROOT_PARENT_ID, SCHEDULE_CORE_STATUS, SCHEDULE_EFFECT_KIND, SIR_AUTO_REJECT_REASON, STATUS, STATUS_CRITERIA, ScheduleCore, WORK_TIME_DIRECTION, checkNoUpdatedLinks, computeExpectedProgress, createSchedule, expectedProgressFromBaseline, getActiveBaseline, getUnsavedActivities, isRootParent, normalizeParentKey, parseFromBackend, willRunCriticalPath, yieldToBrowser };
23137
23788
  //# sourceMappingURL=index.js.map
23138
23789
  //# sourceMappingURL=index.js.map