@outbuild-company/schedule-core 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -5,14 +5,12 @@ var Queue = class {
5
5
  enqueue(item) {
6
6
  this.items.push(item);
7
7
  }
8
- /** Removes and returns the oldest item, or `undefined` when empty. */
9
8
  dequeue() {
10
9
  if (this.head >= this.items.length) return void 0;
11
10
  const item = this.items[this.head];
12
11
  this.head += 1;
13
12
  return item;
14
13
  }
15
- /** The oldest item without removing it, or `undefined` when empty. */
16
14
  peek() {
17
15
  if (this.head >= this.items.length) return void 0;
18
16
  return this.items[this.head];
@@ -123,33 +121,24 @@ function isFrozen(activity) {
123
121
 
124
122
  // src/dispatch/reasons.ts
125
123
  var REJECTION_REASON = {
126
- // Pipeline-gate fallbacks (used when a gate rejects without a reason).
127
124
  CANNOT_EDIT: "cannot_edit",
128
125
  PARSE_ERROR: "parse_error",
129
126
  INVALID: "invalid",
130
- // Inline-edit / link validation.
131
127
  CUSTOM_ID_DUPLICATE: "custom_id_duplicate",
132
128
  INVALID_LINK_TYPE: "invalid_link_type",
133
129
  INVALID_LINK_LAG: "invalid_link_lag",
134
130
  INVALID_VALUE: "invalid_value",
135
- // Bulk-edit: the column has no registered pipeline (unknown column, or a
136
- // link column like custom_predecessors that dispatches as link intents).
137
131
  NO_PIPELINE_FOR_COLUMN: "no_pipeline_for_column",
138
- // Entity lookups.
139
132
  ACTIVITY_NOT_FOUND: "activity_not_found",
140
133
  PARENT_NOT_FOUND: "parent_not_found",
141
134
  ACTIVITY_IDS_EMPTY: "activity_ids_empty",
142
- // Anchored positioning (create / move).
143
135
  ANCHOR_SIBLING_CONFLICT: "anchor_sibling_conflict",
144
136
  ANCHOR_SIBLING_NOT_FOUND: "anchor_sibling_not_found",
145
137
  ANCHOR_SIBLING_WRONG_PARENT: "anchor_sibling_wrong_parent",
146
- // SIR freeze: cannot add a child under an activity with a pending SIR.
147
138
  PARENT_FROZEN_BY_SIR: "parent_frozen_by_sir",
148
- // Hierarchy rules.
149
139
  CANNOT_MOVE_INTO_OWN_DESCENDANT: "cannot_move_into_own_descendant",
150
140
  INDENT_NO_ELIGIBLE_SIBLING: "indent_no_eligible_sibling",
151
141
  OUTDENT_ROOT_LEVEL_NOT_EDITABLE: "outdent_root_level_not_editable",
152
- // Progress button.
153
142
  INVALID_PROGRESS_VALUE: "invalid_progress_value_must_be_0_or_100"
154
143
  };
155
144
 
@@ -220,14 +209,12 @@ function dispatchSelectionReplace(action, deps) {
220
209
  };
221
210
  }
222
211
 
223
- // src/dispatch/visibility.ts
224
- function dispatchVisibilitySet(action, deps) {
225
- const { adapter } = deps;
226
- const targetVisible = new Set(action.visibleIds.map(String));
212
+ // src/dispatch/shared/apply-visible-set.ts
213
+ function applyVisibleSet(adapter, visibleIds) {
227
214
  const viewState = [];
228
215
  adapter.forEachActivity((_snapshot, activityId) => {
229
216
  const id = String(activityId);
230
- const willBeVisible = targetVisible.has(id);
217
+ const willBeVisible = visibleIds.has(id);
231
218
  const before = adapter.isVisible(id);
232
219
  if (before === willBeVisible) return;
233
220
  adapter.setVisible(id, willBeVisible);
@@ -236,6 +223,349 @@ function dispatchVisibilitySet(action, deps) {
236
223
  visible: { before, after: willBeVisible }
237
224
  });
238
225
  });
226
+ return viewState;
227
+ }
228
+
229
+ // src/dispatch/visibility.ts
230
+ function dispatchVisibilitySet(action, deps) {
231
+ const { adapter } = deps;
232
+ const targetVisible = new Set(action.visibleIds.map(String));
233
+ const viewState = applyVisibleSet(adapter, targetVisible);
234
+ const changes = {
235
+ source: action,
236
+ activities: [],
237
+ links: [],
238
+ calendars: [],
239
+ trackingEvents: [],
240
+ viewState
241
+ };
242
+ return { ok: true, changes };
243
+ }
244
+
245
+ // src/internal/filter/field-registry.ts
246
+ var MILLISECONDS_PER_DAY = 1e3 * 60 * 60 * 24;
247
+ function toDays(hours, hoursPerDay) {
248
+ if (hours === null) return null;
249
+ if (hoursPerDay <= 0) return null;
250
+ return hours / hoursPerDay;
251
+ }
252
+ function calendarDaySpan(startDate, endDate) {
253
+ const elapsed = endDate.getTime() - startDate.getTime();
254
+ return Math.floor(elapsed / MILLISECONDS_PER_DAY) + 1;
255
+ }
256
+ var FIELD_REGISTRY = {
257
+ name: { valueKind: "string", extract: (activity) => activity.name },
258
+ description: {
259
+ valueKind: "string",
260
+ extract: (activity) => activity.description
261
+ },
262
+ customId: { valueKind: "string", extract: (activity) => activity.customId },
263
+ correlativeId: {
264
+ valueKind: "number",
265
+ extract: (activity) => activity.correlativeId
266
+ },
267
+ uniqueCorrelativeId: {
268
+ valueKind: "number",
269
+ extract: (activity) => Number(activity.uniqueCorrelativeId)
270
+ },
271
+ progress: { valueKind: "number", extract: (activity) => activity.progress },
272
+ durationDays: {
273
+ valueKind: "number",
274
+ extract: (activity, context) => toDays(activity.durationHours, context.hoursPerDay)
275
+ },
276
+ calendarDuration: {
277
+ valueKind: "number",
278
+ extract: (activity) => calendarDaySpan(activity.startDate, activity.endDate)
279
+ },
280
+ cost: { valueKind: "number", extract: (activity) => activity.cost },
281
+ usedCost: { valueKind: "number", extract: (activity) => activity.usedCost },
282
+ realCost: { valueKind: "number", extract: (activity) => activity.realCost },
283
+ workHours: { valueKind: "number", extract: (activity) => activity.workHours },
284
+ realWorkHours: {
285
+ valueKind: "number",
286
+ extract: (activity) => activity.realWorkHours
287
+ },
288
+ ponderator: {
289
+ valueKind: "number",
290
+ extract: (activity) => activity.ponderator
291
+ },
292
+ freeSlackDays: {
293
+ valueKind: "number",
294
+ extract: (activity, context) => toDays(activity.freeSlackHours, context.hoursPerDay)
295
+ },
296
+ totalSlackDays: {
297
+ valueKind: "number",
298
+ extract: (activity, context) => toDays(
299
+ activity.criticalPath?.totalSlackHours ?? null,
300
+ context.hoursPerDay
301
+ )
302
+ },
303
+ expectedProgressBaseline: {
304
+ valueKind: "number",
305
+ extract: (activity) => activity.expectedProgressBaseline
306
+ },
307
+ baselineDurationDays: {
308
+ valueKind: "number",
309
+ extract: (activity) => activity.baselineSnapshot?.durationDays ?? null
310
+ },
311
+ baselineCost: {
312
+ valueKind: "number",
313
+ extract: (activity) => activity.baselineSnapshot?.cost ?? null
314
+ },
315
+ baselineWorkHours: {
316
+ valueKind: "number",
317
+ extract: (activity) => activity.baselineSnapshot?.workHours ?? null
318
+ },
319
+ startDate: { valueKind: "date", extract: (activity) => activity.startDate },
320
+ endDate: { valueKind: "date", extract: (activity) => activity.endDate },
321
+ constraintDate: {
322
+ valueKind: "date",
323
+ extract: (activity) => activity.constraintDate
324
+ },
325
+ baselineStartDate: {
326
+ valueKind: "date",
327
+ extract: (activity) => activity.baselineSnapshot?.startDate ?? null
328
+ },
329
+ baselineEndDate: {
330
+ valueKind: "date",
331
+ extract: (activity) => activity.baselineSnapshot?.endDate ?? null
332
+ },
333
+ earlyStart: {
334
+ valueKind: "date",
335
+ extract: (activity) => activity.criticalPath?.earlyStart ?? null
336
+ },
337
+ earlyFinish: {
338
+ valueKind: "date",
339
+ extract: (activity) => activity.criticalPath?.earlyFinish ?? null
340
+ },
341
+ lateStart: {
342
+ valueKind: "date",
343
+ extract: (activity) => activity.criticalPath?.lateStart ?? null
344
+ },
345
+ lateFinish: {
346
+ valueKind: "date",
347
+ extract: (activity) => activity.criticalPath?.lateFinish ?? null
348
+ },
349
+ responsableIds: {
350
+ valueKind: "id-array",
351
+ extract: (activity) => activity.responsableIds
352
+ },
353
+ tagIds: { valueKind: "id-array", extract: (activity) => activity.tagIds },
354
+ status: { valueKind: "enum", extract: (activity) => activity.status },
355
+ constraintType: {
356
+ valueKind: "enum",
357
+ extract: (activity) => activity.constraintType
358
+ },
359
+ calendarId: {
360
+ valueKind: "enum",
361
+ extract: (activity) => activity.calendarId === null ? null : String(activity.calendarId)
362
+ },
363
+ subcontractId: {
364
+ valueKind: "enum",
365
+ extract: (activity) => activity.subcontractId
366
+ },
367
+ isCritical: { valueKind: "enum", extract: (activity) => activity.isCritical }
368
+ };
369
+ function getFieldDescriptor(field) {
370
+ return FIELD_REGISTRY[field] ?? null;
371
+ }
372
+
373
+ // src/internal/filter/evaluate-filter.ts
374
+ function toTargetDate(value) {
375
+ if (value instanceof Date) return value;
376
+ if (typeof value === "string" || typeof value === "number") {
377
+ return new Date(value);
378
+ }
379
+ return new Date(Number.NaN);
380
+ }
381
+ function matchString(value, target, operator) {
382
+ const isAbsent = value === null;
383
+ if (operator === "includes") {
384
+ return !isAbsent && String(value).toLowerCase().includes(target.toLowerCase());
385
+ }
386
+ if (operator === "notIncludes") {
387
+ return isAbsent || !String(value).toLowerCase().includes(target.toLowerCase());
388
+ }
389
+ if (operator === "is") return !isAbsent && String(value) === target;
390
+ if (operator === "isNot") return isAbsent || String(value) !== target;
391
+ return false;
392
+ }
393
+ function matchNumber(value, target, operator) {
394
+ if (value === null || typeof value !== "number") {
395
+ return operator === "notEquals";
396
+ }
397
+ if (operator === "equals") return value === target;
398
+ if (operator === "notEquals") return value !== target;
399
+ if (operator === "greaterThan") return value > target;
400
+ if (operator === "lessThan") return value < target;
401
+ if (operator === "greaterOrEqual") return value >= target;
402
+ if (operator === "lessOrEqual") return value <= target;
403
+ return false;
404
+ }
405
+ function matchDate(value, target, operator) {
406
+ if (!(value instanceof Date)) return false;
407
+ if (operator === "after") return value.getTime() > target.getTime();
408
+ if (operator === "before") return value.getTime() < target.getTime();
409
+ return false;
410
+ }
411
+ function matchIdArray(value, allowed, operator) {
412
+ const ids = Array.isArray(value) ? value : [];
413
+ const intersects = ids.some((id) => allowed.has(String(id)));
414
+ if (operator === "someOf") return intersects;
415
+ if (operator === "notSomeOf") return !intersects;
416
+ return false;
417
+ }
418
+ function matchEnum(value, allowed, operator) {
419
+ const isMember = value !== null && allowed.has(String(value));
420
+ if (operator === "someOf") return isMember;
421
+ if (operator === "notSomeOf") return !isMember;
422
+ return false;
423
+ }
424
+ function toAllowedSet(value) {
425
+ const items = Array.isArray(value) ? value : [value];
426
+ return new Set(items.map((item) => String(item)));
427
+ }
428
+ function matchCriterion(activity, criterion, context) {
429
+ const descriptor = getFieldDescriptor(criterion.field);
430
+ if (descriptor === null) return false;
431
+ const value = descriptor.extract(activity, context);
432
+ const { operator } = criterion;
433
+ if (descriptor.valueKind === "string") {
434
+ return matchString(value, String(criterion.value), operator);
435
+ }
436
+ if (descriptor.valueKind === "number") {
437
+ return matchNumber(value, Number(criterion.value), operator);
438
+ }
439
+ if (descriptor.valueKind === "date") {
440
+ return matchDate(value, toTargetDate(criterion.value), operator);
441
+ }
442
+ if (descriptor.valueKind === "id-array") {
443
+ return matchIdArray(value, toAllowedSet(criterion.value), operator);
444
+ }
445
+ return matchEnum(value, toAllowedSet(criterion.value), operator);
446
+ }
447
+ function matchesCriteria(activity, filter, context) {
448
+ if (filter.criteria.length === 0) return true;
449
+ if (filter.logic === "or") {
450
+ return filter.criteria.some(
451
+ (criterion) => matchCriterion(activity, criterion, context)
452
+ );
453
+ }
454
+ return filter.criteria.every(
455
+ (criterion) => matchCriterion(activity, criterion, context)
456
+ );
457
+ }
458
+ function overlapsRange(activity, range) {
459
+ const taskStart = activity.startDate.getTime();
460
+ const taskEnd = activity.endDate.getTime();
461
+ const windowStart = range.start.getTime();
462
+ const windowEnd = range.end.getTime();
463
+ const fullyInside = taskStart >= windowStart && taskEnd <= windowEnd;
464
+ const startsInside = taskStart >= windowStart && taskStart <= windowEnd;
465
+ const windowStartsInside = windowStart >= taskStart && windowStart <= taskEnd;
466
+ return fullyInside || startsInside || windowStartsInside;
467
+ }
468
+ function addAncestors(matchedId, parentOf, visibleIds) {
469
+ let ancestorId = parentOf(matchedId);
470
+ while (ancestorId !== null && !visibleIds.has(String(ancestorId))) {
471
+ visibleIds.add(String(ancestorId));
472
+ ancestorId = parentOf(ancestorId);
473
+ }
474
+ }
475
+ function evaluateVisibleIds(input) {
476
+ const { activities, parentOf, filter, context } = input;
477
+ const range = filter.dateRange;
478
+ const visibleIds = /* @__PURE__ */ new Set();
479
+ const matchedIds = [];
480
+ for (const activity of activities) {
481
+ const passesCriteria = matchesCriteria(activity, filter, context);
482
+ const passesRange = range === void 0 || overlapsRange(activity, range);
483
+ if (passesCriteria && passesRange) {
484
+ visibleIds.add(String(activity.id));
485
+ matchedIds.push(activity.id);
486
+ }
487
+ }
488
+ for (const matchedId of matchedIds) {
489
+ addAncestors(matchedId, parentOf, visibleIds);
490
+ }
491
+ return visibleIds;
492
+ }
493
+
494
+ // src/internal/filter/validate.ts
495
+ var OPERATORS_BY_KIND = {
496
+ string: /* @__PURE__ */ new Set(["includes", "notIncludes", "is", "isNot"]),
497
+ number: /* @__PURE__ */ new Set([
498
+ "equals",
499
+ "notEquals",
500
+ "greaterThan",
501
+ "lessThan",
502
+ "greaterOrEqual",
503
+ "lessOrEqual"
504
+ ]),
505
+ date: /* @__PURE__ */ new Set(["after", "before"]),
506
+ "id-array": /* @__PURE__ */ new Set(["someOf", "notSomeOf"]),
507
+ enum: /* @__PURE__ */ new Set(["someOf", "notSomeOf"])
508
+ };
509
+ function validateCriterion(criterion) {
510
+ const descriptor = getFieldDescriptor(criterion.field);
511
+ if (descriptor === null) return "unknown_field";
512
+ if (!OPERATORS_BY_KIND[descriptor.valueKind].has(criterion.operator)) {
513
+ return "unknown_operator";
514
+ }
515
+ return validateValueForKind(criterion, descriptor.valueKind);
516
+ }
517
+ function validateValueForKind(criterion, valueKind) {
518
+ const { value } = criterion;
519
+ if (valueKind === "id-array" || valueKind === "enum") {
520
+ return Array.isArray(value) ? null : "invalid_value";
521
+ }
522
+ if (Array.isArray(value)) return "invalid_value";
523
+ if (valueKind === "number") {
524
+ return Number.isFinite(Number(value)) ? null : "invalid_value";
525
+ }
526
+ if (valueKind === "date") {
527
+ return isValidDateValue(value) ? null : "invalid_value";
528
+ }
529
+ return null;
530
+ }
531
+ function isValidDateValue(value) {
532
+ if (value instanceof Date) return true;
533
+ if (typeof value === "string" || typeof value === "number") {
534
+ return !Number.isNaN(new Date(value).getTime());
535
+ }
536
+ return false;
537
+ }
538
+
539
+ // src/dispatch/filter.ts
540
+ function isEmptyFilter(filter) {
541
+ return filter.criteria.length === 0 && filter.dateRange === void 0;
542
+ }
543
+ function resolveVisibleIds(adapter, filter, hoursPerDay) {
544
+ const activities = adapter.getAllActivities();
545
+ if (isEmptyFilter(filter)) {
546
+ return new Set(activities.map((activity) => String(activity.id)));
547
+ }
548
+ return evaluateVisibleIds({
549
+ activities,
550
+ parentOf: (activityId) => adapter.getParentId(activityId),
551
+ filter,
552
+ context: { hoursPerDay }
553
+ });
554
+ }
555
+ function dispatchFilterSet(action, deps) {
556
+ const { adapter, hoursPerDay } = deps;
557
+ for (const criterion of action.criteria) {
558
+ const rejection = validateCriterion(criterion);
559
+ if (rejection !== null) return { ok: false, reason: rejection };
560
+ }
561
+ const filter = action.dateRange === void 0 ? { criteria: action.criteria, logic: action.logic } : {
562
+ criteria: action.criteria,
563
+ logic: action.logic,
564
+ dateRange: action.dateRange
565
+ };
566
+ adapter.setActiveFilter(isEmptyFilter(filter) ? null : filter);
567
+ const visibleIds = resolveVisibleIds(adapter, filter, hoursPerDay);
568
+ const viewState = applyVisibleSet(adapter, visibleIds);
239
569
  const changes = {
240
570
  source: action,
241
571
  activities: [],
@@ -628,19 +958,22 @@ var ACTIVITY_TYPE = {
628
958
  MILESTONE: "milestone"
629
959
  };
630
960
  var TIMING = {
631
- // 16ms = full frame budget; 8ms = yield twice per frame so the
632
- // browser still has half a frame to paint and handle input.
633
961
  YIELD_SLICE_MS: 8
634
962
  };
635
963
 
636
964
  // src/shared/timing.ts
637
965
  var isNode = typeof window === "undefined";
638
- var channel = !isNode && typeof MessageChannel !== "undefined" ? new MessageChannel() : null;
966
+ var hasMessageChannel = !isNode && typeof MessageChannel !== "undefined";
639
967
  function yieldToBrowser() {
640
- if (isNode || !channel) return Promise.resolve();
968
+ if (!hasMessageChannel) return Promise.resolve();
641
969
  return new Promise((resolve) => {
642
- channel.port1.onmessage = () => resolve();
643
- channel.port2.postMessage(null);
970
+ const oneShotChannel = new MessageChannel();
971
+ oneShotChannel.port1.onmessage = () => {
972
+ oneShotChannel.port1.close();
973
+ oneShotChannel.port2.close();
974
+ resolve();
975
+ };
976
+ oneShotChannel.port2.postMessage(null);
644
977
  });
645
978
  }
646
979
 
@@ -1248,7 +1581,6 @@ function calculateSuccessorStartFromLink(predecessor, successor, link, adapter)
1248
1581
  startDate: date2,
1249
1582
  durationHours: sourceLag,
1250
1583
  task: predecessor
1251
- // sourceLag always on predecessor calendar
1252
1584
  });
1253
1585
  }
1254
1586
  if (targetLag !== 0) {
@@ -1256,7 +1588,6 @@ function calculateSuccessorStartFromLink(predecessor, successor, link, adapter)
1256
1588
  startDate: date2,
1257
1589
  durationHours: targetLag,
1258
1590
  task: successor
1259
- // targetLag always on successor calendar
1260
1591
  });
1261
1592
  }
1262
1593
  if (trueLag !== 0) {
@@ -1264,7 +1595,6 @@ function calculateSuccessorStartFromLink(predecessor, successor, link, adapter)
1264
1595
  startDate: date2,
1265
1596
  durationHours: trueLag,
1266
1597
  task: successor
1267
- // trueLag always on successor calendar
1268
1598
  });
1269
1599
  }
1270
1600
  if (successor.durationHours === 0) {
@@ -1914,8 +2244,6 @@ function parseEntry(entry) {
1914
2244
  lag = sign === "-" ? -value : value;
1915
2245
  }
1916
2246
  return {
1917
- // frozen logic: invariant guaranteed by ENTRY_RE — capture group 1 `(\d+)`
1918
- // is non-optional, so a successful match always defines correlativeId
1919
2247
  correlativeId,
1920
2248
  type,
1921
2249
  lag
@@ -2022,36 +2350,6 @@ function lagDaysToHours(lagDays, hoursPerDay) {
2022
2350
 
2023
2351
  // src/autoscheduler/date-math/impl-current.ts
2024
2352
  var currentImpl = {
2025
- /**
2026
- * Legacy rule observed empirically from 4 fixtures:
2027
- *
2028
- * midnight = setHours(0, 0, 0, 0) on a copy of rawDate (local TZ)
2029
- * if (midnight.getTime() === rawDate.getTime())
2030
- * return calendar.getClosestWorkTime(raw, 'future') // snap forward
2031
- * else
2032
- * return midnight // preserve day
2033
- *
2034
- * Rationale (inferred): when the user types/picks a date AT local
2035
- * midnight (e.g., Saturday 00:00 local = "just Saturday"), legacy
2036
- * interprets it as "start of the week/day" and snaps to the next
2037
- * working hour. When they pick a time WITHIN a day (e.g., Sunday
2038
- * 08:00 local), legacy treats it as "this specific day" and preserves
2039
- * the day at local midnight, even if the day is non-working.
2040
- *
2041
- * Fixture evidence:
2042
- * - test3: raw=Apr 26 06:00Z (Sun 08:00 CEST) → Apr 25 22:00Z (Sun 00:00 CEST)
2043
- * - create-rename-drag: raw=Apr 23 22:00Z (Fri 00:00 CEST) → Apr 24 06:00Z (snap)
2044
- * - create-rename-drag: raw=Apr 25 22:00Z (Sun 00:00 CEST) → Apr 27 06:00Z (snap)
2045
- *
2046
- * UTC contract: `setUTCHours(0)` makes the normalization deterministic
2047
- * regardless of the runtime's local TZ. The work-calendar package (and
2048
- * any future strict-UTC calendar engine) requires UTC-keyed inputs, so
2049
- * the day boundary must be computed in UTC too. Legacy fixtures
2050
- * recorded under local-TZ midnight may need their `metadata.tz` honored
2051
- * upstream — `pipeline-context.ts` plumbs that field but this function
2052
- * does not yet consume it (its caller supplies a raw Date with the
2053
- * recorded instant intact).
2054
- */
2055
2353
  rawInputToConstraintDate(rawDate, calendar) {
2056
2354
  const midnight = new Date(rawDate);
2057
2355
  midnight.setUTCHours(0, 0, 0, 0);
@@ -2067,16 +2365,6 @@ var currentImpl = {
2067
2365
  }
2068
2366
  return midnight;
2069
2367
  },
2070
- /**
2071
- * Legacy behavior replicated (from `modifyLagCustom.js:29-35`):
2072
- * `calendar.calculateDuration(sourceDate, targetDate)`
2073
- *
2074
- * Returns working hours between the two dates according to the task's
2075
- * calendar (working days + working hours range). Positive when
2076
- * targetDate > sourceDate, zero when aligned. Negative branch
2077
- * exists in calendar.calculateDuration (reverse walk) but our
2078
- * current usage always has target after source post-move.
2079
- */
2080
2368
  computeLagBetweenTasks(sourceDate, targetDate, calendar) {
2081
2369
  return calendar.calculateDuration(sourceDate, targetDate);
2082
2370
  }
@@ -2113,36 +2401,16 @@ var AutoScheduler = class {
2113
2401
  getCurrentCalculationId() {
2114
2402
  return this.currentCalculationId;
2115
2403
  }
2116
- /**
2117
- * Invalidates the cached full-graph topological order. Call after any
2118
- * structural mutation: link create/delete, activity create/delete,
2119
- * activity reparent (indent/outdent/move).
2120
- */
2121
2404
  invalidateTopoCache() {
2122
2405
  this.topoCache.invalidate();
2123
2406
  }
2124
- /**
2125
- * Invalidates the cached expanded parent-link set. Call on link create /
2126
- * delete, activity reparent, activity create / delete, and on the rare
2127
- * field edits that affect chain-pruning (`duration`, `auto_scheduling`).
2128
- */
2129
2407
  invalidateExpandedLinksCache() {
2130
2408
  this.expandedLinksCache.invalidate();
2131
2409
  }
2132
- /**
2133
- * Convenience: invalidate every cache held by the scheduler.
2134
- */
2135
2410
  invalidateAllCaches() {
2136
2411
  this.topoCache.invalidate();
2137
2412
  this.expandedLinksCache.invalidate();
2138
2413
  }
2139
- /**
2140
- * Main entry point. Runs the full scheduling algorithm.
2141
- *
2142
- * Returns a ScheduleResult with the plans, updated IDs, and status.
2143
- * The caller (integration layer) is responsible for applying the results
2144
- * back to gantt.
2145
- */
2146
2414
  async schedule(options = {}) {
2147
2415
  const calculationId = ++this.currentCalculationId;
2148
2416
  const isCurrent = createIsCurrent(
@@ -2511,16 +2779,6 @@ function sortDeepestFirst(ids, depths) {
2511
2779
  // src/internal/post-processors/runner.ts
2512
2780
  var POST_PROCESSORS = {
2513
2781
  updateActivityDuration: runUpdateActivityDuration,
2514
- // `updateMilestoneData` eliminado del registro (2026-06-10, MIL-B2):
2515
- // post-processor fantasma — ninguna pipeline lo emitía. Su garantía
2516
- // (duration=0, end_date=start_date al convertir a milestone) vive en
2517
- // durationPipeline (fix MIL-B1) + calculateEndDate(start, 0) === start
2518
- // (test en calendar/adapter.test.ts). Ver BUGS_milestones_2026-06-10.md
2519
- // (vault).
2520
- // `executeFixForConstraints` (legacy) se reimplementa fuera de este registro
2521
- // como `revertNoOpConstraintEdit` (post-pass del dispatch de constraint, tras
2522
- // la cascada) — NO como post-processor por-pipeline. `recordLastStartDate`
2523
- // guarda el baseline del gesto (start al editar duración) que ese revert lee.
2524
2782
  updateTaskTiming: runNoOp("updateTaskTiming"),
2525
2783
  adjustLinkLagOnTaskMove,
2526
2784
  recordLastStartDate: runRecordLastStartDate
@@ -2943,7 +3201,6 @@ function buildDescendantCascade(activity, newValue, autoScheduling, hierarchy, r
2943
3201
  const descendants = hierarchy.getDescendantIds(activity.id);
2944
3202
  return descendants.map((id) => ({
2945
3203
  activityId: id,
2946
- // Descendants of a recursive progress change inherit the primary value.
2947
3204
  fields: descendantFields(
2948
3205
  newValue,
2949
3206
  autoScheduling,
@@ -3256,7 +3513,6 @@ var startDatePipeline = {
3256
3513
  {
3257
3514
  startDate: finalStart,
3258
3515
  ...setEndDate(finalEnd),
3259
- // Sanea la duration de un milestone corrupto en el mismo move.
3260
3516
  ...milestoneActivity ? setDuration(0) : {},
3261
3517
  ...setConstraintTypeImplied(),
3262
3518
  ...setConstraintDate(constraintDate)
@@ -3535,9 +3791,11 @@ var calendarIdPipeline = {
3535
3791
  if (isEmpty(value)) return parseError("empty_calendar");
3536
3792
  return parsed(value);
3537
3793
  },
3538
- validate(activity, _oldValue, newValue) {
3794
+ validate(activity, _oldValue, newValue, ctx) {
3539
3795
  if (isUnchangedCalendar(activity.calendarId, newValue))
3540
3796
  return invalid("unchanged");
3797
+ if (!ctx.calendars.getCalendar(newValue))
3798
+ return invalid("unknown_calendar");
3541
3799
  return valid();
3542
3800
  },
3543
3801
  transform(activity, newValue, ctx) {
@@ -3752,9 +4010,6 @@ var COLUMN_PIPELINES = /* @__PURE__ */ new Map([
3752
4010
  [COLUMN.CONSTRAINT_DATE, constraintDatePipeline],
3753
4011
  [COLUMN.CALENDAR_ID, calendarIdPipeline],
3754
4012
  [COLUMN.CUSTOM_ID, customIdPipeline],
3755
- // Naming exception: `subcontractId` stays camelCase for parity with
3756
- // production (backend BD + legacy column + `BackendActivityInput.subcontractId`).
3757
- // Snake-case unification deferred to a global pass.
3758
4013
  [COLUMN.SUBCONTRACT_ID, subcontractIdPipeline],
3759
4014
  [COLUMN.RESPONSABLES, responsablesPipeline],
3760
4015
  [COLUMN.TAGS, tagsPipeline]
@@ -3879,7 +4134,13 @@ function cloneCriticalPath(value) {
3879
4134
  };
3880
4135
  }
3881
4136
 
4137
+ // src/shared/clone-domain-value.ts
4138
+ function cloneDomainValue(value) {
4139
+ return structuredClone(value);
4140
+ }
4141
+
3882
4142
  // src/dispatch/shared/snapshots.ts
4143
+ var YIELD_EVERY_N_ENTRIES = 200;
3883
4144
  function collectTouchedIds(primary, changes) {
3884
4145
  const ids = /* @__PURE__ */ new Set([String(primary)]);
3885
4146
  for (const mutation of changes.cascadeMutations ?? []) {
@@ -3887,9 +4148,12 @@ function collectTouchedIds(primary, changes) {
3887
4148
  }
3888
4149
  return ids;
3889
4150
  }
3890
- function snapshotActivities(adapter, ids) {
4151
+ async function snapshotActivities(adapter, ids) {
3891
4152
  const out = /* @__PURE__ */ new Map();
4153
+ let processed = 0;
3892
4154
  for (const id of ids) {
4155
+ processed += 1;
4156
+ if (processed % YIELD_EVERY_N_ENTRIES === 0) await yieldToBrowser();
3893
4157
  const a = adapter.getActivity(id);
3894
4158
  if (a) out.set(id, structuredCloneActivity(a));
3895
4159
  }
@@ -3898,6 +4162,10 @@ function snapshotActivities(adapter, ids) {
3898
4162
  function structuredCloneActivity(activity) {
3899
4163
  return cloneCoreActivity(activity);
3900
4164
  }
4165
+ function snapshotSingleActivity(adapter, activityId) {
4166
+ const liveActivity = adapter.getActivity(activityId);
4167
+ return liveActivity ? cloneCoreActivity(liveActivity) : null;
4168
+ }
3901
4169
  function applyFieldChanges(adapter, activityId, changes) {
3902
4170
  applyCanonicalPatch(adapter, activityId, changes.patch);
3903
4171
  for (const mutation of changes.cascadeMutations ?? []) {
@@ -3914,35 +4182,69 @@ function applyCanonicalPatch(adapter, activityId, patch) {
3914
4182
  setActivityFieldDynamic(adapter, activityId, key, value);
3915
4183
  }
3916
4184
  }
3917
- function buildActivityChanges(adapter, before, touched) {
4185
+ async function buildActivityChanges(adapter, before, touched, correlativeBefore) {
3918
4186
  const out = [];
4187
+ let processed = 0;
3919
4188
  for (const id of touched) {
3920
- const afterSnap = adapter.getActivity(id);
3921
- if (!afterSnap) {
3922
- out.push({ id, kind: "deleted", after: null });
3923
- continue;
3924
- }
3925
- const beforeSnap = before.get(id);
3926
- const diff = diffActivity(beforeSnap, afterSnap);
3927
- if (beforeSnap && Object.keys(diff).length === 0) continue;
3928
- if (!beforeSnap) {
3929
- out.push({
3930
- id,
3931
- kind: "created",
3932
- fields: diff,
3933
- after: structuredCloneActivity(afterSnap)
3934
- });
3935
- } else {
3936
- out.push({
3937
- id,
3938
- kind: "updated",
3939
- fields: diff,
3940
- after: structuredCloneActivity(afterSnap)
3941
- });
3942
- }
4189
+ processed += 1;
4190
+ if (processed % YIELD_EVERY_N_ENTRIES === 0) await yieldToBrowser();
4191
+ const entry = buildEntryForTouchedId(
4192
+ adapter,
4193
+ before,
4194
+ id,
4195
+ correlativeBefore
4196
+ );
4197
+ if (entry) out.push(entry);
3943
4198
  }
3944
4199
  return out;
3945
4200
  }
4201
+ function buildEntryForTouchedId(adapter, before, activityId, correlativeBefore) {
4202
+ const afterSnap = adapter.getActivity(activityId);
4203
+ if (!afterSnap) {
4204
+ return { id: activityId, kind: "deleted", after: null };
4205
+ }
4206
+ const beforeSnap = before.get(activityId);
4207
+ if (!beforeSnap && correlativeBefore?.has(activityId)) {
4208
+ return buildCorrelativeOnlyEntry(
4209
+ activityId,
4210
+ correlativeBefore.get(activityId),
4211
+ afterSnap
4212
+ );
4213
+ }
4214
+ const diff = diffActivity(beforeSnap, afterSnap);
4215
+ mergeCorrelativeShiftIntoDiff(diff, correlativeBefore, activityId, afterSnap);
4216
+ if (beforeSnap && Object.keys(diff).length === 0) return null;
4217
+ return {
4218
+ id: activityId,
4219
+ kind: beforeSnap ? "updated" : "created",
4220
+ fields: diff,
4221
+ after: structuredCloneActivity(afterSnap)
4222
+ };
4223
+ }
4224
+ function buildCorrelativeOnlyEntry(activityId, correlativeIdBefore, liveActivity) {
4225
+ if (correlativeIdBefore === liveActivity.correlativeId) return null;
4226
+ return {
4227
+ id: activityId,
4228
+ kind: "updated",
4229
+ fields: {
4230
+ correlativeId: {
4231
+ before: correlativeIdBefore,
4232
+ after: liveActivity.correlativeId
4233
+ }
4234
+ },
4235
+ after: structuredCloneActivity(liveActivity)
4236
+ };
4237
+ }
4238
+ function mergeCorrelativeShiftIntoDiff(diff, correlativeBefore, activityId, liveActivity) {
4239
+ if (!correlativeBefore?.has(activityId)) return;
4240
+ if (Object.hasOwn(diff, "correlativeId")) return;
4241
+ const shiftedFrom = correlativeBefore.get(activityId);
4242
+ if (shiftedFrom === liveActivity.correlativeId) return;
4243
+ diff.correlativeId = {
4244
+ before: shiftedFrom,
4245
+ after: liveActivity.correlativeId
4246
+ };
4247
+ }
3946
4248
  function diffActivity(before, after) {
3947
4249
  const fields = {};
3948
4250
  const beforeRec = before ?? {};
@@ -3950,11 +4252,19 @@ function diffActivity(before, after) {
3950
4252
  const keys = /* @__PURE__ */ new Set([...Object.keys(beforeRec), ...Object.keys(afterRec)]);
3951
4253
  for (const k of keys) {
3952
4254
  if (Object.hasOwn(beforeRec, k) !== Object.hasOwn(afterRec, k) || !fieldValueEqual(beforeRec[k], afterRec[k])) {
3953
- fields[k] = { before: beforeRec[k], after: afterRec[k] };
4255
+ fields[k] = {
4256
+ before: cloneFieldValue(beforeRec[k]),
4257
+ after: cloneFieldValue(afterRec[k])
4258
+ };
3954
4259
  }
3955
4260
  }
3956
4261
  return fields;
3957
4262
  }
4263
+ function cloneFieldValue(value) {
4264
+ const isPrimitive = value === null || typeof value !== "object";
4265
+ if (isPrimitive) return value;
4266
+ return cloneDomainValue(value);
4267
+ }
3958
4268
  function fieldValueEqual(left, right) {
3959
4269
  if (Object.is(left, right)) return true;
3960
4270
  if (left instanceof Date && right instanceof Date) {
@@ -4631,12 +4941,6 @@ function mutateTheDateToFutureOrPastInBaseRestriction(dateBaseToCalculate, restr
4631
4941
 
4632
4942
  // src/critical-path/legacy/base/parents-calculations/forward.js
4633
4943
  var CalculateForwardParentsWithLinks = class {
4634
- /**
4635
- * Initializes the calculator with linked activities, the current activity, and the gantt instance.
4636
- * @param {Array<Object>} linkedActivitiesData - Array of linked activities data.
4637
- * @param {Object} activity - The current activity object.
4638
- * @param {Object} gantt - The gantt instance.
4639
- */
4640
4944
  constructor(linkedActivitiesData, activity, gantt) {
4641
4945
  this.linkedActivitiesData = linkedActivitiesData;
4642
4946
  this.activity = activity;
@@ -4648,10 +4952,6 @@ var CalculateForwardParentsWithLinks = class {
4648
4952
  );
4649
4953
  }
4650
4954
  }
4651
- /**
4652
- * Main method to perform the calculation.
4653
- * @returns {Object} The calculation result.
4654
- */
4655
4955
  calculate() {
4656
4956
  const calculationsFromLinks = this.calculateLinks();
4657
4957
  const maxEfFromLinks = getMaxEarlyStartSet(calculationsFromLinks);
@@ -4664,10 +4964,6 @@ var CalculateForwardParentsWithLinks = class {
4664
4964
  }
4665
4965
  return maxEfFromLinks;
4666
4966
  }
4667
- /**
4668
- * Calculates the dates based on the linked activities.
4669
- * @returns {Array<Object>} Array of calculation results from links.
4670
- */
4671
4967
  calculateLinks() {
4672
4968
  const calculations = [];
4673
4969
  for (const linkedActivity of this.linkedActivitiesData) {
@@ -4698,11 +4994,6 @@ var CalculateForwardParentsWithLinks = class {
4698
4994
  }
4699
4995
  return calculations;
4700
4996
  }
4701
- /**
4702
- * Handles the 'Start No Earlier Than' (SNET) constraint.
4703
- * @param {Object|null} maxEfFromLinks - The maximum early finish from links.
4704
- * @returns {Object} The calculation result considering the constraint.
4705
- */
4706
4997
  handleSNETConstraint(maxEfFromLinks) {
4707
4998
  const restriction = calculateRestrictionSnet({
4708
4999
  duration: this.activity.duration,
@@ -4715,11 +5006,6 @@ var CalculateForwardParentsWithLinks = class {
4715
5006
  }
4716
5007
  return maxEfFromLinks.ef > restriction.ef ? maxEfFromLinks : restriction;
4717
5008
  }
4718
- /**
4719
- * Handles the 'Finish No Later Than' (FNLT) constraint.
4720
- * @param {Object|null} maxEfFromLinks - The maximum early finish from links.
4721
- * @returns {Object} The calculation result considering the constraint.
4722
- */
4723
5009
  handleFNLTConstraint(maxEfFromLinks) {
4724
5010
  const restriction = calculateRestriction({
4725
5011
  duration: -this.activity.duration,
@@ -4732,11 +5018,6 @@ var CalculateForwardParentsWithLinks = class {
4732
5018
  }
4733
5019
  return maxEfFromLinks.ef > restriction.ef ? restriction : maxEfFromLinks;
4734
5020
  }
4735
- /**
4736
- * Calculates dates for 'Start to Start' (SS) link type.
4737
- * @param {Object} params - Parameters containing lag and predecessor early start.
4738
- * @returns {Object} The calculation result.
4739
- */
4740
5021
  calculateSSLink({ lag, predecessorEs }) {
4741
5022
  const esLinked = mutateDate({
4742
5023
  linkType: "ss",
@@ -4767,11 +5048,6 @@ var CalculateForwardParentsWithLinks = class {
4767
5048
  );
4768
5049
  return { es, ef };
4769
5050
  }
4770
- /**
4771
- * Calculates dates for 'Finish to Finish' (FF) link type.
4772
- * @param {Object} params - Parameters containing lag and predecessor early finish.
4773
- * @returns {Object} The calculation result.
4774
- */
4775
5051
  calculateFFLink({ lag, predecessorEf }) {
4776
5052
  const efLinked = mutateDate({
4777
5053
  linkType: "ff",
@@ -4802,11 +5078,6 @@ var CalculateForwardParentsWithLinks = class {
4802
5078
  }
4803
5079
  return { es, ef };
4804
5080
  }
4805
- /**
4806
- * Calculates dates for 'Finish to Start' (FS) link type.
4807
- * @param {Object} params - Parameters containing lag and predecessor early finish.
4808
- * @returns {Object} The calculation result.
4809
- */
4810
5081
  calculateFSLink({ lag, predecessorEf }) {
4811
5082
  let efLinked = predecessorEf;
4812
5083
  if (lag === 0) {
@@ -4831,11 +5102,6 @@ var CalculateForwardParentsWithLinks = class {
4831
5102
  );
4832
5103
  return { es, ef };
4833
5104
  }
4834
- /**
4835
- * Calculates dates for 'Start to Finish' (SF) link type.
4836
- * @param {Object} params - Parameters containing lag, predecessor early start, and finish.
4837
- * @returns {Object} The calculation result.
4838
- */
4839
5105
  calculateSFLink({ lag, predecessorEs }) {
4840
5106
  const ef = addDurationToDate(
4841
5107
  this.activityCalendar,
@@ -5141,14 +5407,6 @@ var CalculateBackwardParentsLinks = class {
5141
5407
  });
5142
5408
  return newDate;
5143
5409
  }
5144
- /**
5145
- * Determines if a given date corresponds to the initial work hour of an activity as defined in the activity calendar.
5146
- * This function retrieves the first work interval from the activity calendar and compares the hour portion
5147
- * of the input date to the start hour of the work interval.
5148
- * @param {object} activityCalendar - The calendar object containing work hours and scheduling information for the activity.
5149
- * @param {Date} date - The date to check against the activity's start hour.
5150
- * @returns {boolean} True if the hour of the input date matches the initial work hour of the activity; otherwise, false.
5151
- */
5152
5410
  isActivityInInitHour(activityCalendar, date2) {
5153
5411
  const normalizedDate = date2 instanceof Date ? date2 : new Date(date2);
5154
5412
  const shifts = activityCalendar.getWorkHours(normalizedDate);
@@ -5489,22 +5747,12 @@ var calculation_of_parent_default = CalculationOfParent;
5489
5747
 
5490
5748
  // src/critical-path/legacy/base/third-level-activities/index.js
5491
5749
  var ThirdLevelActivityIdentifier = class {
5492
- /**
5493
- * Constructs the ThirdLevelActivityIdentifier class.
5494
- * @param {Object} params - The parameters object.
5495
- * @param {Object} params.gantt - The Gantt chart instance.
5496
- * @param {Object} params.filters - Filters for tasks.
5497
- * @param {string} params.linkProperty - The property name for links.
5498
- */
5499
5750
  constructor({ gantt, linkProperty }) {
5500
5751
  this.gantt = gantt;
5501
5752
  this.linkProperty = linkProperty;
5502
5753
  this.structureOfParents = /* @__PURE__ */ new Map();
5503
5754
  this.singleParents = /* @__PURE__ */ new Map();
5504
5755
  }
5505
- /**
5506
- * Identifies third-level activities and populates the structureOfParents map.
5507
- */
5508
5756
  identifyThirdLevelActivities() {
5509
5757
  try {
5510
5758
  const parents = this.getFirstLevelParents();
@@ -5529,18 +5777,9 @@ var ThirdLevelActivityIdentifier = class {
5529
5777
  throw e;
5530
5778
  }
5531
5779
  }
5532
- /**
5533
- * Retrieves the first-level parent tasks.
5534
- * @returns {Array<Object>} Array of parent tasks.
5535
- */
5536
5780
  getFirstLevelParents() {
5537
5781
  return this.gantt.getTaskByTime().filter(filters_default.byFirstLevel).filter(filters_default.filterByParentType);
5538
5782
  }
5539
- /**
5540
- * Processes each activity under a parent task.
5541
- * @param {Object} parentActivity - The parent activity to process.
5542
- * @returns {Object} Processed data including parentsIds, allTasks, activitiesByLevel.
5543
- */
5544
5783
  processEachActivity(parentActivity) {
5545
5784
  const parentsIds = /* @__PURE__ */ new Set();
5546
5785
  const allTasks = /* @__PURE__ */ new Set();
@@ -5555,10 +5794,6 @@ var ThirdLevelActivityIdentifier = class {
5555
5794
  activitiesByLevel
5556
5795
  };
5557
5796
  }
5558
- /**
5559
- * Initializes the parent activity in singleParents map.
5560
- * @param {Object} parentActivity - The parent activity.
5561
- */
5562
5797
  initializeParent(parentActivity) {
5563
5798
  const parentId = Number(parentActivity.id);
5564
5799
  const hasLink = Boolean(parentActivity[this.linkProperty]?.length);
@@ -5569,13 +5804,6 @@ var ThirdLevelActivityIdentifier = class {
5569
5804
  childrens: []
5570
5805
  });
5571
5806
  }
5572
- /**
5573
- * Processes a single activity.
5574
- * @param {Object} activity - The activity to process.
5575
- * @param {Set<number>} parentsIds - Set of parent IDs.
5576
- * @param {Set<number>} allTasks - Set of all task IDs.
5577
- * @param {Map<number, Map<number, Array<Object>>>} activitiesByLevel - Activities grouped by level.
5578
- */
5579
5807
  processActivity(activity, parentsIds, allTasks, activitiesByLevel) {
5580
5808
  const activityId = Number(activity.id);
5581
5809
  const parentId = Number(activity.parent);
@@ -5590,27 +5818,12 @@ var ThirdLevelActivityIdentifier = class {
5590
5818
  }
5591
5819
  this.addActivityToLevel(activity, activitiesByLevel);
5592
5820
  }
5593
- /**
5594
- * Checks if an activity is a project (parent activity).
5595
- * @param {Object} activity - The activity to check.
5596
- * @returns {boolean} True if the activity is a project.
5597
- */
5598
5821
  isProjectActivity(activity) {
5599
5822
  return activity.type === "project";
5600
5823
  }
5601
- /**
5602
- * Checks if an activity has a link.
5603
- * @param {Object} activity - The activity to check.
5604
- * @returns {boolean} True if the activity has a link.
5605
- */
5606
5824
  hasLink(activity) {
5607
5825
  return Boolean(activity[this.linkProperty]?.length);
5608
5826
  }
5609
- /**
5610
- * Adds parent information to singleParents map.
5611
- * @param {Object} activity - The parent activity.
5612
- * @param {Set<number>} parentsIds - Set of parent IDs.
5613
- */
5614
5827
  addParentInfo(activity, parentsIds) {
5615
5828
  const parentId = Number(activity.id);
5616
5829
  const level = activity["$level"];
@@ -5623,27 +5836,12 @@ var ThirdLevelActivityIdentifier = class {
5623
5836
  parentsIds.add(parentId);
5624
5837
  this.singleParents.set(parentId, parentInfo);
5625
5838
  }
5626
- /**
5627
- * Checks if a parent exists in singleParents map.
5628
- * @param {number} parentId - The parent ID to check.
5629
- * @returns {boolean} True if the parent exists.
5630
- */
5631
5839
  doesParentExist(parentId) {
5632
5840
  return this.singleParents.has(parentId);
5633
5841
  }
5634
- /**
5635
- * Adds a child activity to its parent in singleParents map.
5636
- * @param {number} parentId - The parent ID.
5637
- * @param {number} activityId - The child activity ID.
5638
- */
5639
5842
  addChildToParent(parentId, activityId) {
5640
5843
  this.singleParents.get(parentId).childrens.push(activityId);
5641
5844
  }
5642
- /**
5643
- * Adds an activity to the activitiesByLevel map.
5644
- * @param {Object} activity - The activity to add.
5645
- * @param {Map<number, Map<number, Array<Object>>>} activitiesByLevel - Activities grouped by level.
5646
- */
5647
5845
  addActivityToLevel(activity, activitiesByLevel) {
5648
5846
  const levelKey = activity["$level"];
5649
5847
  const parentKey = Number(activity.parent);
@@ -5660,33 +5858,15 @@ var ThirdLevelActivityIdentifier = class {
5660
5858
  calculated: false
5661
5859
  });
5662
5860
  }
5663
- /**
5664
- * Retrieves all levels from activitiesByLevel map.
5665
- * @param {Map<number, Map<number, Array<Object>>>} activitiesByLevel - Activities grouped by level.
5666
- * @returns {Set<number>} Set of all levels.
5667
- */
5668
5861
  getAllLevels(activitiesByLevel) {
5669
5862
  return new Set(activitiesByLevel.keys());
5670
5863
  }
5671
- /**
5672
- * Determines the deepest level from a set of levels.
5673
- * @param {Set<number>} allLevels - Set of all levels.
5674
- * @returns {number} The deepest level.
5675
- */
5676
5864
  getDeepestLevel(allLevels) {
5677
5865
  if (allLevels.size === 0) {
5678
5866
  return 0;
5679
5867
  }
5680
5868
  return Math.max(...allLevels);
5681
5869
  }
5682
- /**
5683
- * Creates the result object for a parent activity.
5684
- * @param {Object} parent - The parent activity.
5685
- * @param {Object} processPayload - The processed data.
5686
- * @param {number} deepestLevel - The deepest level found.
5687
- * @param {Set<number>} allLevels - Set of all levels.
5688
- * @returns {Object} The result object.
5689
- */
5690
5870
  createResult(parent, processPayload, deepestLevel, allLevels) {
5691
5871
  const { activitiesByLevel, parentsIds, allTasks } = processPayload;
5692
5872
  return {
@@ -5852,22 +6032,6 @@ var CriticalPathHelpers = class {
5852
6032
  throw e;
5853
6033
  }
5854
6034
  }
5855
- /**
5856
- * Identifies and sets the initial activities for the chain based on the specified direction.
5857
- *
5858
- * This function determines the starting activities of a chain by filtering activities from
5859
- * the Gantt chart. The filtering is based on the specified direction (`forward` or `backward`).
5860
- * - For `forward` direction, activities with an empty `$target` property are selected.
5861
- * - For `backward` direction, activities with an empty `$source` property are selected.
5862
- *
5863
- * The function excludes activities of type `project` from the results.
5864
- * The resulting activity IDs are stored in the `chainStartActivities` property.
5865
- *
5866
- * If an error occurs during the process, `chainStartActivities` is set to an empty array,
5867
- * and the error is rethrown.
5868
- *
5869
- * @throws {Error} If an error occurs during the identification process.
5870
- */
5871
6035
  identifyInitialActivities() {
5872
6036
  try {
5873
6037
  const {
@@ -5978,27 +6142,6 @@ var CriticalPathHelpers = class {
5978
6142
  }
5979
6143
  return sorted.reverse();
5980
6144
  }
5981
- /**
5982
- * Calculates the start and finish dates for the origin of a chain activity.
5983
- *
5984
- * This function calculates the start and finish dates for an activity based on the provided direction
5985
- * (`forward` or `backward`). For forward direction, it calculates the earliest start (ES) and earliest
5986
- * finish (EF). For backward direction, it calculates the latest start (LS) and latest finish (LF),
5987
- * handling different progress states (0%, 100%, and between 0% and 100%).
5988
- *
5989
- * @param {Object} [activityFromLink=null] - The activity object to calculate dates for.
5990
- * @param {string} [customDirection=null] - The direction for the calculation (`forward` or `backward`).
5991
- * @returns {Object} An object containing the calculated dates (ES, EF, LS, LF) based on the direction and progress.
5992
- *
5993
- * @example
5994
- * // Assuming activity is an object with start_date, end_date, progress, and calendar_id properties
5995
- * // and direction is 'forward'
5996
- * const dates = calculateStartAndFinishOfChainOrigin(activity, 'forward');
5997
- * console.log()
5998
- // { es: activity.start_date, ef: activity.end_date }
5999
- *
6000
- * @throws {Error} If the activity's calendar cannot be retrieved or other errors occur during calculation.
6001
- */
6002
6145
  calculateStartAndFinishOfChainOrigin(activityFromLink = null, customDirection = null) {
6003
6146
  try {
6004
6147
  let activity = activityFromLink;
@@ -6044,25 +6187,6 @@ var CriticalPathHelpers = class {
6044
6187
  throw e;
6045
6188
  }
6046
6189
  }
6047
- /**
6048
- * Calculates the latest start (LS) and latest finish (LF) dates for an activity with zero progress.
6049
- *
6050
- * This function determines the LS and LF dates based on the activity's constraint type and duration,
6051
- * using the provided calendar. It handles different types of constraints, adjusting the start and finish
6052
- * dates accordingly.
6053
- *
6054
- * @param {Object} activity - The activity object to calculate dates for, which should include start_date, end_date, duration, and constraint_type.
6055
- * @param {Object} calendar - The calendar object used to adjust dates based on working days and hours.
6056
- * @returns {Object} An object containing the calculated latest start (LS) and latest finish (LF) dates.
6057
- *
6058
- * @example
6059
- * // Assuming activity is an object with the required properties and a calendar object is provided
6060
- * const dates = calculateBackwardWhenZeroProgress(activity, calendar);
6061
- * console.log()
6062
- // { ls: moment(...), lf: moment(...) }
6063
- *
6064
- * @throws {Error} If an error occurs during the calculation.
6065
- */
6066
6190
  calculateBackwardWhenZeroProgress(activity, calendar) {
6067
6191
  let lateStart = moment_default(activity.start_date).clone();
6068
6192
  let lateFinish = moment_default(activity.end_date).clone();
@@ -6099,23 +6223,6 @@ var CriticalPathHelpers = class {
6099
6223
  lf: lateFinish
6100
6224
  };
6101
6225
  }
6102
- /**
6103
- * Calculates the latest start (LS) and latest finish (LF) dates for an activity with progress between 0% and 100%.
6104
- *
6105
- * This function determines the LS and LF dates based on the activity's constraint type and progress,
6106
- * considering the end date of the project and various constraints.
6107
- *
6108
- * @param {Object} activity - The activity object to calculate dates for, which should include start_date, end_date, and constraint_type.
6109
- * @returns {Object} An object containing the calculated latest start (LS) and latest finish (LF) dates.
6110
- *
6111
- * @example
6112
- * // Assuming activity is an object with the required properties
6113
- * const dates = calculateWhenProgressIsBetweenZeroAndOneHundred(activity);
6114
- * console.log()
6115
- // { ls: activity.start_date, lf: calculatedLateFinish }
6116
- *
6117
- * @throws {Error} If an error occurs during the calculation.
6118
- */
6119
6226
  calculateWhenProgressIsBetweenZeroAndOneHundred(activity) {
6120
6227
  let lateStart = activity.start_date;
6121
6228
  let lateFinish = null;
@@ -6176,7 +6283,6 @@ var CriticalPathHelpers = class {
6176
6283
  throw e;
6177
6284
  }
6178
6285
  }
6179
- // Main function
6180
6286
  doCalculationForParentType(activity) {
6181
6287
  const calculationOfParent = new calculation_of_parent_default({
6182
6288
  activity,
@@ -6254,22 +6360,6 @@ var LinksRulesCalculationsMethods = class {
6254
6360
  this.parentsCalculations = calculationObject.parentsCalculations;
6255
6361
  this.gantt = calculationObject.ganttInstance;
6256
6362
  }
6257
- /**
6258
- * Retrieves the earliest start (ES) and earliest finish (EF) dates for a given activity from previously calculated activities.
6259
- *
6260
- * This function checks if the activity exists in the `alapMap`. If it does, it returns the data from `alapMap`.
6261
- * If the activity is not found in `alapMap`, it retrieves and returns the data from `calculatedActivities`.
6262
- *
6263
- * @param {string|number} activity - The ID of the activity for which to retrieve ES and EF dates.
6264
- * @returns {Object|null} The ES and EF dates for the activity, or null if not found.
6265
- *
6266
- * @example
6267
- * // Assuming alapMap and calculatedActivities are Maps with activity data
6268
- * const esEf = getEsAndEfFromPreviousCalculatedActivities(1);
6269
- // { es: ..., ef: ..., text: ... } or null
6270
- *
6271
- * @throws {Error} If an error occurs during the retrieval process.
6272
- */
6273
6363
  getEsAndEfFromPreviousCalculatedActivities(activity) {
6274
6364
  const isAlap = this.alapMap.has(activity);
6275
6365
  if (isAlap) {
@@ -6277,29 +6367,6 @@ var LinksRulesCalculationsMethods = class {
6277
6367
  }
6278
6368
  return this.calculatedActivities.get(Number(activity));
6279
6369
  }
6280
- /**
6281
- * Calculates the earliest start (ES) and earliest finish (EF) times for a successor activity.
6282
- *
6283
- * This function calculates the ES and EF times for a successor activity based on the provided predecessor time,
6284
- * data calculations for ES and EF, lag time, and the type of link restriction. It adjusts the dates according
6285
- * to the activity's calendar and the specified restrictions.
6286
- *
6287
- * @param {Date} predecessorTime - The time of the predecessor activity.
6288
- * @param {number} esDataCalculation - The amount of time to add to the predecessor time to calculate the earliest start.
6289
- * @param {number} [efDataCalculation=0] - The amount of time to add to calculate the earliest finish.
6290
- * @param {number} lag - The lag time between the predecessor and successor activities.
6291
- * @param {string} [restrictionOfLink='fs'] - The type of link restriction between the activities.
6292
- * @returns {Object} An object containing the calculated earliest start (ES) and earliest finish (EF) times.
6293
- * @property {Date} es - The earliest start time.
6294
- * @property {Date} ef - The earliest finish time.
6295
- *
6296
- * @example
6297
- * // Assuming predecessorTime is a Date object, esDataCalculation is 5, efDataCalculation is 10, lag is 2, and restrictionOfLink is 'fs'
6298
- * const result = calculateSucessorTimes(new Date(), 5, 10, 2, 'fs');
6299
- // { es: Date, ef: Date }
6300
- *
6301
- * @throws {Error} If an error occurs during the calculation process.
6302
- */
6303
6370
  calculateSucessorTimes(predecessorTime, esDataCalculation, efDataCalculation = 0, lag, restrictionOfLink = LINK_TYPES.FS) {
6304
6371
  const activityCalendar = this.gantt.getCalendar(
6305
6372
  this.referenceActivity.calendar_id
@@ -6372,27 +6439,6 @@ var LinksRulesCalculationsMethods = class {
6372
6439
  }
6373
6440
  return { es, ef };
6374
6441
  }
6375
- /**
6376
- * Calculates the earliest start (ES) and earliest finish (EF) times for a Start-to-Start (SS) relationship.
6377
- *
6378
- * This function calculates the ES and EF times for a successor activity based on a Start-to-Start (SS) relationship
6379
- * with the predecessor activity. It uses the predecessor's ES time and adjusts it based on the link's lag and the
6380
- * activity's duration.
6381
- *
6382
- * @param {Object} link - The link object representing the relationship between the predecessor and successor activities.
6383
- * @param {number} link.source - The ID of the predecessor activity.
6384
- * @param {number} [link.lag=0] - The lag time between the predecessor and successor activities.
6385
- * @returns {Object} An object containing the calculated earliest start (ES) and earliest finish (EF) times.
6386
- * @property {Date} es - The earliest start time.
6387
- * @property {Date} ef - The earliest finish time.
6388
- *
6389
- * @example
6390
- * // Assuming link is an object with a source property (predecessor ID) and an optional lag property
6391
- * const result = calculateSS({ source: 1, lag: 2 });
6392
- // { es: Date, ef: Date }
6393
- *
6394
- * @throws {Error} If an error occurs during the calculation process.
6395
- */
6396
6442
  calculateSS(link) {
6397
6443
  const predecessorCalculatedEsAndEf = this.getEsAndEfFromPreviousCalculatedActivities(Number(link.source));
6398
6444
  const esDataCalculation = link.lag || 0;
@@ -6407,27 +6453,6 @@ var LinksRulesCalculationsMethods = class {
6407
6453
  LINK_TYPES.SS
6408
6454
  );
6409
6455
  }
6410
- /**
6411
- * Calculates the earliest start (ES) and earliest finish (EF) times for a Finish-to-Finish (FF) relationship.
6412
- *
6413
- * This function calculates the ES and EF times for a successor activity based on a Finish-to-Finish (FF) relationship
6414
- * with the predecessor activity. It uses the predecessor's EF time and adjusts it based on the link's lag and the
6415
- * activity's duration.
6416
- *
6417
- * @param {Object} link - The link object representing the relationship between the predecessor and successor activities.
6418
- * @param {number} link.source - The ID of the predecessor activity.
6419
- * @param {number} [link.lag=0] - The lag time between the predecessor and successor activities.
6420
- * @returns {Object} An object containing the calculated earliest start (ES) and earliest finish (EF) times.
6421
- * @property {Date} es - The earliest start time.
6422
- * @property {Date} ef - The earliest finish time.
6423
- *
6424
- * @example
6425
- * // Assuming link is an object with a source property (predecessor ID) and an optional lag property
6426
- * const result = calculateFF({ source: 1, lag: 2 });
6427
- // { es: Date, ef: Date }
6428
- *
6429
- * @throws {Error} If an error occurs during the calculation process.
6430
- */
6431
6456
  calculateFF(link) {
6432
6457
  const predecessorCalculatedEsAndEf = this.getEsAndEfFromPreviousCalculatedActivities(Number(link.source));
6433
6458
  const duration = this.referenceActivity.duration;
@@ -6442,27 +6467,6 @@ var LinksRulesCalculationsMethods = class {
6442
6467
  LINK_TYPES.FF
6443
6468
  );
6444
6469
  }
6445
- /**
6446
- * Calculates the earliest start (ES) and earliest finish (EF) times for a Finish-to-Start (FS) relationship.
6447
- *
6448
- * This function calculates the ES and EF times for a successor activity based on a Finish-to-Start (FS) relationship
6449
- * with the predecessor activity. It uses the predecessor's EF time and adjusts it based on the link's lag and the
6450
- * activity's duration.
6451
- *
6452
- * @param {Object} link - The link object representing the relationship between the predecessor and successor activities.
6453
- * @param {number} link.source - The ID of the predecessor activity.
6454
- * @param {number} [link.lag=0] - The lag time between the predecessor and successor activities.
6455
- * @returns {Object} An object containing the calculated earliest start (ES) and earliest finish (EF) times.
6456
- * @property {Date} es - The earliest start time.
6457
- * @property {Date} ef - The earliest finish time.
6458
- *
6459
- * @example
6460
- * // Assuming link is an object with a source property (predecessor ID) and an optional lag property
6461
- * const result = calculateFS({ source: 1, lag: 2 });
6462
- // { es: Date, ef: Date }
6463
- *
6464
- * @throws {Error} If an error occurs during the calculation process.
6465
- */
6466
6470
  calculateFS(link) {
6467
6471
  const predecessorCalculatedEsAndEf = this.getEsAndEfFromPreviousCalculatedActivities(Number(link.source));
6468
6472
  const esDataCalculation = link.lag || 0;
@@ -6477,27 +6481,6 @@ var LinksRulesCalculationsMethods = class {
6477
6481
  LINK_TYPES.FS
6478
6482
  );
6479
6483
  }
6480
- /**
6481
- * Calculates the earliest start (ES) and earliest finish (EF) times for a Start-to-Finish (SF) relationship.
6482
- *
6483
- * This function calculates the ES and EF times for a successor activity based on a Start-to-Finish (SF) relationship
6484
- * with the predecessor activity. It uses the predecessor's EF time and adjusts it based on the link's lag and the
6485
- * activity's duration.
6486
- *
6487
- * @param {Object} link - The link object representing the relationship between the predecessor and successor activities.
6488
- * @param {number} link.source - The ID of the predecessor activity.
6489
- * @param {number} [link.lag=0] - The lag time between the predecessor and successor activities.
6490
- * @returns {Object} An object containing the calculated earliest start (ES) and earliest finish (EF) times.
6491
- * @property {Date} es - The earliest start time.
6492
- * @property {Date} ef - The earliest finish time.
6493
- *
6494
- * @example
6495
- * // Assuming link is an object with a source property (predecessor ID) and an optional lag property
6496
- * const result = calculateSF({ source: 1, lag: 2 });
6497
- // { es: Date, ef: Date }
6498
- *
6499
- * @throws {Error} If an error occurs during the calculation process.
6500
- */
6501
6484
  calculateSF(link) {
6502
6485
  const predecessorCalculatedEsAndEf = this.getEsAndEfFromPreviousCalculatedActivities(Number(link.source));
6503
6486
  const duration = this.referenceActivity.duration;
@@ -6512,24 +6495,6 @@ var LinksRulesCalculationsMethods = class {
6512
6495
  LINK_TYPES.SF
6513
6496
  );
6514
6497
  }
6515
- /**
6516
- * Adjusts a date to the next working hour based on the type of link restriction and the activity's calendar.
6517
- *
6518
- * This function adjusts the provided date either to a future or past working hour based on the specified link restriction.
6519
- * It uses the activity's calendar to determine the working hours and calculates the appropriate date.
6520
- *
6521
- * @param {Date} dateBaseToCalculate - The initial date that needs to be adjusted.
6522
- * @param {string} restrictionOfLink - The type of link restriction (e.g., 'fs', 'ss', 'ff').
6523
- * @param {Object} activityCalendar - The calendar associated with the activity, used to determine working hours.
6524
- * @returns {Date} The adjusted date based on the link restriction and activity calendar.
6525
- *
6526
- * @example
6527
- * // Assuming dateBaseToCalculate is a Date object, restrictionOfLink is 'fs', and activityCalendar is a valid calendar object
6528
- * const adjustedDate = mutateTheDateToFutureOrPastInBaseRestriction(new Date(), 'fs', activityCalendar);
6529
- // The date adjusted to the next working hour in the future
6530
- *
6531
- * @throws {Error} If an error occurs during the date adjustment process.
6532
- */
6533
6498
  mutateTheDateToFutureOrPastInBaseRestriction(dateBaseToCalculate, restrictionOfLink, activityCalendar) {
6534
6499
  if (![LINK_TYPES.FS, LINK_TYPES.SS, LINK_TYPES.FF].includes(restrictionOfLink)) {
6535
6500
  return dateBaseToCalculate;
@@ -6553,22 +6518,6 @@ var LinksConstraintCalculator = class extends LinksRulesCalculationsMethods_defa
6553
6518
  constructor(calculationObject) {
6554
6519
  super(calculationObject);
6555
6520
  }
6556
- /**
6557
- * Calculates the earliest start dates for all links and returns the maximum early start set.
6558
- *
6559
- * This function processes each link in the `links` array, retrieves the necessary link data, and calculates
6560
- * the earliest start dates using the `calculateLink` method. It then returns the maximum early start set
6561
- * by calling `getMaxEarlyStartSet`.
6562
- *
6563
- * @returns {Object} The maximum early start set calculated from all links.
6564
- *
6565
- * @example
6566
- * // Assuming links is an array of link IDs [1, 2, 3]
6567
- * // and gantt.getLink(id) returns link data for each ID
6568
- * const result = calculate();
6569
- *
6570
- * @throws {Error} If an error occurs during the calculation process.
6571
- */
6572
6521
  calculate() {
6573
6522
  if (this.links.length === 0) {
6574
6523
  return new generic_calculations_default(
@@ -6599,23 +6548,6 @@ var LinksConstraintCalculator = class extends LinksRulesCalculationsMethods_defa
6599
6548
  }
6600
6549
  return getMaxEarlyStartSet(allLinksCalculations);
6601
6550
  }
6602
- /**
6603
- * Calculates the link based on its type.
6604
- *
6605
- * This function determines the appropriate calculation method for the link based on its type and executes it.
6606
- * The link type is mapped to specific calculation methods: Finish-to-Start (FS), Start-to-Start (SS),
6607
- * Finish-to-Finish (FF), and Start-to-Finish (SF).
6608
- *
6609
- * @param {Object} linkData - The data of the link to be calculated. It should include a `type` property that indicates the type of link.
6610
- * @returns {*} The result of the calculation based on the link type.
6611
- *
6612
- * @example
6613
- * // Assuming linkData is an object with a type property
6614
- * const result = calculateLink({ type: 0, ...otherLinkProperties });
6615
- * // This will call the calculateFS method with the linkData and return the result
6616
- *
6617
- * @throws {Error} If the link type is not recognized.
6618
- */
6619
6551
  calculateLink(linkData) {
6620
6552
  const calculationMapping = {
6621
6553
  0: () => this.calculateFS(linkData),
@@ -6641,11 +6573,6 @@ var ActivityCalculator = class {
6641
6573
  this.linkProperty = options.linkProperty;
6642
6574
  this.linkDirection = options.linkDirection;
6643
6575
  }
6644
- /**
6645
- * Checks which activities can now be calculated based on their dependencies.
6646
- * @param {Set<number>} pendingToCalculate - Set of activity IDs pending calculation.
6647
- * @returns {Object} An object containing activities that can be calculated and remaining pending activities.
6648
- */
6649
6576
  checkActivitiesThatNowCanBeCalculated(pendingToCalculate) {
6650
6577
  const activitiesThatCanBeCalculated = /* @__PURE__ */ new Set();
6651
6578
  const pendingActivities = new Set(pendingToCalculate);
@@ -6672,9 +6599,6 @@ var ActivityCalculator = class {
6672
6599
  pendingActivities
6673
6600
  };
6674
6601
  }
6675
- /**
6676
- * Handles logic for project-type activities.
6677
- */
6678
6602
  handleProjectActivity(activityId, activityData, activitiesThatCanBeCalculated, pendingActivities) {
6679
6603
  const isPendingParentWithNoLinks = this.pendingParentsWithNoLinks.has(activityId);
6680
6604
  const isPendingParentWithLinks = this.pendingParentsWithLinks.has(activityId);
@@ -6715,9 +6639,6 @@ var ActivityCalculator = class {
6715
6639
  }
6716
6640
  }
6717
6641
  }
6718
- /**
6719
- * Determines if a parent activity can be calculated.
6720
- */
6721
6642
  canCalculateParentActivity(activityData) {
6722
6643
  const hasNoLinks = (activityData[this.linkProperty] || []).length === 0;
6723
6644
  const constraintType = activityData.constraint_type;
@@ -6732,9 +6653,6 @@ var ActivityCalculator = class {
6732
6653
  (activityId) => this.calculations.has(activityId)
6733
6654
  );
6734
6655
  }
6735
- /**
6736
- * Handles logic for non-project activities.
6737
- */
6738
6656
  handleNonProjectActivity(activityId, activityData, activitiesThatCanBeCalculated, pendingActivities) {
6739
6657
  const parentId = Number(activityData.parent);
6740
6658
  const isParentPendingWithLinks = this.pendingParentsWithLinks.has(parentId);
@@ -6772,9 +6690,6 @@ var ActivityCalculator = class {
6772
6690
  pendingActivities.delete(activityId);
6773
6691
  }
6774
6692
  }
6775
- /**
6776
- * Retrieves linked activities based on link property.
6777
- */
6778
6693
  getLinkedActivities(predecessors) {
6779
6694
  if (!Array.isArray(predecessors)) {
6780
6695
  return [];
@@ -6793,9 +6708,6 @@ var ActivityCalculator = class {
6793
6708
  }
6794
6709
  return linkedActivities;
6795
6710
  }
6796
- /**
6797
- * Retrieves an array of linked activity IDs.
6798
- */
6799
6711
  getArrayOfLinkedActivities(links) {
6800
6712
  if (!Array.isArray(links)) {
6801
6713
  return [];
@@ -6817,8 +6729,7 @@ var get_activities_to_calculate_default = ActivityCalculator;
6817
6729
  var createIsCurrent2 = (calculationId, getCurrentId) => () => getCurrentId() === calculationId;
6818
6730
 
6819
6731
  // src/critical-path/legacy/utils/validation.js
6820
- var shouldAbortCalculation = (gantt) => !gantt?.fullyParsed || // environment guard: en el core no hay `window` (el bridge en react_client sí).
6821
- typeof window !== "undefined" && window.to_use_react_gantt?.conversionMode?.isActive;
6732
+ var shouldAbortCalculation = (gantt) => !gantt?.fullyParsed || typeof window !== "undefined" && window.to_use_react_gantt?.conversionMode?.isActive;
6822
6733
 
6823
6734
  // src/critical-path/legacy/utils/timing.js
6824
6735
  var TIME_BUDGET_MS = 16;
@@ -6930,24 +6841,6 @@ var ForwardPath = class extends generic_calculations_default {
6930
6841
  isCurrent
6931
6842
  });
6932
6843
  }
6933
- /**
6934
- * Calculates the earliest start (ES) and earliest finish (EF) dates for a list of activities.
6935
- *
6936
- * This function processes each activity in the `activitiesToCalculate` list, retrieves the necessary
6937
- * information, and calculates the ES and EF dates based on the activity's progress and constraint type.
6938
- * It handles various constraints and updates the calculations accordingly.
6939
- * It also do calculation according to the activities links
6940
- *
6941
- * @param {Array<string|number>} activitiesToCalculate - A list of activity IDs for which to calculate ES and EF dates.
6942
- * @returns {void} This function does not return a value.
6943
- *
6944
- * @example
6945
- * // Assuming activitiesToCalculate is an array containing activity IDs [1, 2, 3]
6946
- * calculateStartAndFinishTimes([1, 2, 3]);
6947
- * // This will calculate the ES and EF dates for the activities and update the internal calculations map.
6948
- *
6949
- * @throws {Error} If an error occurs during the process.
6950
- */
6951
6844
  calculateStartAndFinishTimes(activitiesToCalculate) {
6952
6845
  activitiesToCalculate.forEach((activity) => {
6953
6846
  const activityReference = this.gantt.getTask(activity);
@@ -7068,13 +6961,6 @@ var ForwardPath = class extends generic_calculations_default {
7068
6961
  this.activitiesWaitingForCalculation.delete(activity);
7069
6962
  });
7070
6963
  }
7071
- /**
7072
- * Gets the greatest date between a restriction and a link calculation.
7073
- * @param {Object} restriction - The restriction object.
7074
- * @param {Object} linkCalculation - The link calculation object.
7075
- * @param {string} [comparisonType='greater'] - The type of comparison ('greater' or 'less').
7076
- * @returns {Object} - The object with the greatest date.
7077
- */
7078
6964
  getTheGreatesDateBetweenRestrictionAndEsEf(restriction, linkCalculation, comparisonType = "greater") {
7079
6965
  if (comparisonType === "greater") {
7080
6966
  return linkCalculation.ef > restriction.ef ? linkCalculation : restriction;
@@ -7083,34 +6969,18 @@ var ForwardPath = class extends generic_calculations_default {
7083
6969
  return linkCalculation.ef < restriction.ef ? linkCalculation : restriction;
7084
6970
  }
7085
6971
  }
7086
- /**
7087
- * Set ES and EF dates for an activity with full progress.
7088
- * @param {Object} activity - The activity object.
7089
- */
7090
6972
  setDatesForActivityWithFullProgress(activity) {
7091
6973
  this.calculations.set(activity.id, {
7092
6974
  es: activity.start_date,
7093
6975
  ef: activity.end_date
7094
6976
  });
7095
6977
  }
7096
- /**
7097
- * Calculates ES and EF dates for an activity with progress greater than zero.
7098
- * @param {Object} activity - The activity object.
7099
- * @returns {Object} - The calculated ES and EF dates.
7100
- */
7101
6978
  getDatesForActivityWithZeroProgress(activity) {
7102
6979
  return {
7103
6980
  es: activity.start_date,
7104
6981
  ef: activity.end_date
7105
6982
  };
7106
6983
  }
7107
- /**
7108
- * Recalculates ES and EF dates based on a constraint.
7109
- * @param {string} constraintType - The type of constraint.
7110
- * @param {Object} calculatedRestriction - The calculated restriction object.
7111
- * @param {Object} calculatedEsEf - The calculated ES and EF object.
7112
- * @returns {Object} - The recalculated ES and EF dates.
7113
- */
7114
6984
  recalculateInBaseConstraint(constraintType, calculatedRestriction, calculatedEsEf) {
7115
6985
  const comparisontype = [
7116
6986
  CONSTRAINT_TYPES.SNET,
@@ -7150,30 +7020,12 @@ var CalculationsGenericMethods = class {
7150
7020
  this.forwardPathCalculations = calculationObject.calculatedForwardActivitiesMap;
7151
7021
  this.gantt = calculationObject.ganttInstance;
7152
7022
  }
7153
- /**
7154
- * Retrieves the late start (LS) and late finish (lf) dates for a given activity from previously calculated activities.
7155
- *
7156
- * @param {string|number} activity - The ID of the activity for which to retrieve LS and lf dates.
7157
- * @param {string} [constraint=null] - The constraint type to use for the calculation (e.g., 'alap').
7158
- * @returns {Object|null} The LS and lf dates for the activity, or null if not found.
7159
- * @throws {Error} If an error occurs during the retrieval process.
7160
- */
7161
7023
  getForwardOrBackwardCalculations(activity, constraint = null) {
7162
7024
  if (constraint === CONSTRAINT_TYPES.ALAP) {
7163
7025
  return this.forwardPathCalculations.get(activity);
7164
7026
  }
7165
7027
  return this.calculatedActivities.get(activity);
7166
7028
  }
7167
- /**
7168
- * Calculates the LS (Latest Start) and LF (Latest Finish) times for the successor activity.
7169
- * @param {Date} successorTime - The time of the successor activity.
7170
- * @param {number} lsDataCalculation - The duration for LS calculation.
7171
- * @param {number} [lfDataCalculation=0] - The duration for LF calculation, default is 0.
7172
- * @param {number} lag - The lag time.
7173
- * @param {string} [type='FS'] - The type of link ('FS', 'FF', 'SS', 'SF'), default is 'FS'.
7174
- * @returns {Object} Returns an object containing the LS and LF times for the successor activity.
7175
- * @throws Will throw an error if there's an issue with the calculation.
7176
- */
7177
7029
  calculateSuccessorTimes(sucessorTime, lsDataCalculation, lfDataCalculation = 0, lag, type = LINK_TYPES.FS) {
7178
7030
  let activityCalendar = this.gantt.getCalendar(this.activity.calendar_id);
7179
7031
  if (!activityCalendar) {
@@ -7223,13 +7075,6 @@ var CalculationsGenericMethods = class {
7223
7075
  return { ls, lf };
7224
7076
  }
7225
7077
  }
7226
- /**
7227
- * Calculates the LS (Latest Start) and LF (Latest Finish) times for the successor activity in a SS (Start-to-Start) link.
7228
- * @param {Object} link - The link object containing information about the relationship.
7229
- * @param {boolean} [alap=false] - Indicates whether to calculate based on ALAP (As Late As Possible) constraint, default is false.
7230
- * @returns {Object} Returns an object containing the calculated LS and LF times for the successor activity.
7231
- * @throws Will throw an error if there's an issue with the calculation.
7232
- */
7233
7078
  calculateSS(link, alap = false) {
7234
7079
  let lsSuc = this.getValueForSS(link, alap);
7235
7080
  let lsDataForCalculation = -link.lag || 0;
@@ -7243,12 +7088,6 @@ var CalculationsGenericMethods = class {
7243
7088
  LINK_TYPES.SS
7244
7089
  );
7245
7090
  }
7246
- /**
7247
- * Calculates the LS (Latest Start) and LF (Latest Finish) times for the successor activity in a FF (Finish-to-Finish) link.
7248
- * @param {Object} link - The link object containing information about the relationship.
7249
- * @returns {Object} Returns an object containing the calculated LS and LF times for the successor activity.
7250
- * @throws Will throw an error if there's an issue with the calculation.
7251
- */
7252
7091
  calculateFF(link, constraint) {
7253
7092
  const succesorDate = this.getForwardOrBackwardCalculations(
7254
7093
  Number(link.target)
@@ -7266,13 +7105,6 @@ var CalculationsGenericMethods = class {
7266
7105
  LINK_TYPES.FF
7267
7106
  );
7268
7107
  }
7269
- /**
7270
- * Calculates the LS (Latest Start) and LF (Latest Finish) times for the successor activity in a FS (Finish-to-Start) link.
7271
- * @param {Object} link - The link object containing information about the relationship.
7272
- * @param {string} constraint - The constraint type.
7273
- * @returns {Object} Returns an object containing the calculated LS and LF times for the successor activity.
7274
- * @throws Will throw an error if there's an issue with the calculation.
7275
- */
7276
7108
  calculateFS(link, constraint) {
7277
7109
  let propertyToCalculate = "ls";
7278
7110
  propertyToCalculate = constraint === CONSTRAINT_TYPES.ALAP ? "es" : "ls";
@@ -7291,13 +7123,6 @@ var CalculationsGenericMethods = class {
7291
7123
  LINK_TYPES.FS
7292
7124
  );
7293
7125
  }
7294
- /**
7295
- * Calculates the LS (Latest Start) and LF (Latest Finish) times for the successor activity in a SF (Start-to-Finish) link.
7296
- * @param {Object} link - The link object containing information about the relationship.
7297
- * @param {boolean} getFromForward - Whether to calculate LS using the early start from the forward path.
7298
- * @returns {Object} Returns an object containing the calculated LS and LF times for the successor activity.
7299
- * @throws Will throw an error if there's an issue with the calculation.
7300
- */
7301
7126
  calculateSF(link, getFromForward = false) {
7302
7127
  let lateFinishSucessor = getFromForward ? this.getEarlyStartFromForwardPath(Number(link.target)).ef : this.getForwardOrBackwardCalculations(Number(link.target)).lf;
7303
7128
  let lsDataForCalculation = -link.lag || 0;
@@ -7311,19 +7136,9 @@ var CalculationsGenericMethods = class {
7311
7136
  LINK_TYPES.SF
7312
7137
  );
7313
7138
  }
7314
- /**
7315
- * Retrieves the early start time from the forward path calculations for the current activity.
7316
- * @returns {number} The early start time for the activity.
7317
- */
7318
7139
  getEarlyStartFromForwardPath(link) {
7319
7140
  return this.forwardPathCalculations.get(link);
7320
7141
  }
7321
- /**
7322
- * Retrieves the value for the specified scheduling state (SS).
7323
- * @param {object} link - The link object representing the dependency.
7324
- * @param {boolean} alap - Flag indicating if the scheduling state is As Late As Possible (ALAP).
7325
- * @returns {number} The value representing the specified scheduling state.
7326
- */
7327
7142
  getValueForSS(link, alap) {
7328
7143
  if (alap) {
7329
7144
  return this.getEarlyStartFromForwardPath(Number(link.target)).es;
@@ -7332,13 +7147,6 @@ var CalculationsGenericMethods = class {
7332
7147
  let sucessor = this.getForwardOrBackwardCalculations(Number(link.target));
7333
7148
  return sucessor[propertyToCalculate];
7334
7149
  }
7335
- /**
7336
- * Calculates the end date based on the provided activity calendar, starting date, and duration.
7337
- * @param {object} activityCalendar - The calendar object containing activity scheduling information.
7338
- * @param {Date} date - The starting date for the activity.
7339
- * @param {number} duration - The duration of the activity in days.
7340
- * @returns {Date} The end date of the activity.
7341
- */
7342
7150
  calculateDate(activityCalendar, date2, duration) {
7343
7151
  let resetedDate = moment_default(date2).clone();
7344
7152
  return addDurationToDate(
@@ -7348,14 +7156,6 @@ var CalculationsGenericMethods = class {
7348
7156
  this.activity
7349
7157
  );
7350
7158
  }
7351
- /**
7352
- * Retrieves the last working hour based on the provided date and activity calendar.
7353
- * @param {Date} date - The date for which to find the last working hour.
7354
- * @param {object} activityCalendar - The calendar object containing activity scheduling information.
7355
- * @param {string} [dir='past'] - The direction in which to search for the last working hour. Default is 'past'.
7356
- * @throws {Error} Throws an error if the provided date is not valid.
7357
- * @returns {Date} The last working hour relative to the provided date.
7358
- */
7359
7159
  getLastWorkingHour(date2, activityCalendar, dir = "past") {
7360
7160
  const normalizedDate = date2 instanceof Date ? date2 : new Date(date2);
7361
7161
  let resetedDate = moment_default(normalizedDate).clone();
@@ -7370,14 +7170,6 @@ var CalculationsGenericMethods = class {
7370
7170
  });
7371
7171
  return newDate;
7372
7172
  }
7373
- /**
7374
- * Determines if a given date corresponds to the initial work hour of an activity as defined in the activity calendar.
7375
- * This function retrieves the first work interval from the activity calendar and compares the hour portion
7376
- * of the input date to the start hour of the work interval.
7377
- * @param {object} activityCalendar - The calendar object containing work hours and scheduling information for the activity.
7378
- * @param {Date} date - The date to check against the activity's start hour.
7379
- * @returns {boolean} True if the hour of the input date matches the initial work hour of the activity; otherwise, false.
7380
- */
7381
7173
  isActivityInInitHour(activityCalendar, date2) {
7382
7174
  const normalizedDate = date2 instanceof Date ? date2 : new Date(date2);
7383
7175
  const shifts = activityCalendar.getWorkHours(normalizedDate);
@@ -7396,17 +7188,6 @@ var CalculationsGenericMethods = class {
7396
7188
  }
7397
7189
  return normalizedDate.getUTCHours() === workStartHour;
7398
7190
  }
7399
- /**
7400
- * Calculates the forward start (FS) and forward finish (FF) dates based on the provided parameters.
7401
- * @param {object} options - An object containing the necessary parameters for the calculation.
7402
- * @param {number} options.lag - The lag duration for the calculation.
7403
- * @param {Date} options.workTime - The starting work time for the calculation.
7404
- * @param {object} options.activityCalendar - The calendar object containing activity scheduling information.
7405
- * @param {number} options.lsDataCalculation - The duration for calculating the forward start date.
7406
- * @param {number} options.lfDataCalculation - The duration for calculating the forward finish date.
7407
- * @param {boolean} [options.isMilestone=false] - Flag indicating if the activity is a milestone. Default is false.
7408
- * @returns {object} An object containing the forward start (FS) and forward finish (FF) dates.
7409
- */
7410
7191
  calculateFsLink({
7411
7192
  lag,
7412
7193
  workTime,
@@ -7459,16 +7240,6 @@ var CalculationsGenericMethods = class {
7459
7240
  }
7460
7241
  return { ls: lsPred, lf: lfPred };
7461
7242
  }
7462
- /**
7463
- * Calculates the forward finish (FF) dates based on the provided parameters.
7464
- * @param {object} options - An object containing the necessary parameters for the calculation.
7465
- * @param {number} options.lag - The lag duration for the calculation.
7466
- * @param {Date} options.workTime - The starting work time for the calculation.
7467
- * @param {object} options.activityCalendar - The calendar object containing activity scheduling information.
7468
- * @param {number} options.lsDataCalculation - The duration for calculating the forward start date.
7469
- * @param {number} options.lfDataCalculation - The duration for calculating the forward finish date.
7470
- * @returns {object} An object containing the forward start (FS) and forward finish (FF) dates.
7471
- */
7472
7243
  calculateFFLink({
7473
7244
  lag,
7474
7245
  workTime,
@@ -7515,19 +7286,6 @@ var CalculationsGenericMethods = class {
7515
7286
  );
7516
7287
  return { ls: lsPred, lf: lfPred };
7517
7288
  }
7518
- /**
7519
- * Calculates the start and finish times for an activity based on the specified lag and work time.
7520
- * If the lag is zero, the function directly calculates the times using the provided work time.
7521
- * If the lag is negative and the activity is not a milestone, it adjusts the work time based on future working hours.
7522
- * @param {object} options - Configuration object containing parameters needed for the calculation.
7523
- * @param {number} options.lay - The lag time affecting the start and finish calculations.
7524
- * @param {Date} options.workTime - The reference time from which calculations begin.
7525
- * @param {object} options.activityCalendar - The calendar used to check work hours and holidays.
7526
- * @param {number} options.lsDataCalculation - Duration to calculate the start time from the reference point.
7527
- * @param {number} options.lfDataCalculation - Duration to calculate the finish time from the calculated start time.
7528
- * @param {boolean} [options.isMilestone=false] - Indicates whether the current activity is a milestone.
7529
- * @returns {object} An object with properties `ls` (start time) and `lf` (finish time).
7530
- */
7531
7289
  calculateSSlink({
7532
7290
  lag,
7533
7291
  workTime,
@@ -7575,17 +7333,6 @@ var CalculationsGenericMethods = class {
7575
7333
  );
7576
7334
  return { ls: lsPred, lf: lfPred };
7577
7335
  }
7578
- /**
7579
- * Calculates the start (SF) and finish (LF) times for an activity based on the specified lag and work time.
7580
- * This function handles both cases where lag is zero and when it's not, calculating times based on the given work time.
7581
- * @param {object} options - Configuration object containing the necessary parameters for the calculation.
7582
- * @param {number} options.lag - The lag time that influences the scheduling.
7583
- * @param {Date} options.workBlock - The reference time from which scheduling starts.
7584
- * @param {object} options.activityCalendar - The calendar object containing activity scheduling information.
7585
- * @param {number} options.lsDataCalculation - The duration to calculate the start time.
7586
- * @param {number} options.lfDataCalculation - The duration to calculate the finish time.
7587
- * @returns {object} An object containing the start (ls) and finish (lf) times of the activity.
7588
- */
7589
7336
  calculateSFLink({
7590
7337
  lag,
7591
7338
  workTime,
@@ -7632,23 +7379,6 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
7632
7379
  this.parentsThatImpactChildrens = calculationObject.parentsThatImpactChildrens;
7633
7380
  this.projectDates = this.gantt.getSubtaskDates();
7634
7381
  }
7635
- /**
7636
- * Calculates the latest start (LS) and latest finish (LF) times for an activity.
7637
- *
7638
- * This function calculates the LS and LF times for an activity based on its progress and the links associated with it.
7639
- * It takes into account various conditions and constraints to determine the final LS and LF times.
7640
- *
7641
- * @returns {Object} An object containing the calculated latest start (LS) and latest finish (LF) times.
7642
- * @property {Date} ls - The calculated latest start time.
7643
- * @property {Date} lf - The calculated latest finish time.
7644
- *
7645
- * @example
7646
- * // Assuming this function is part of a class with access to the required properties and methods
7647
- * const result = calculate();
7648
- // { ls: Date, lf: Date }
7649
- *
7650
- * @throws {Error} If an error occurs during the calculation process.
7651
- */
7652
7382
  calculate() {
7653
7383
  if (this.links.length === 0) {
7654
7384
  return new generic_calculations_default(
@@ -7725,11 +7455,6 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
7725
7455
  minFromLinks: calculation
7726
7456
  };
7727
7457
  }
7728
- /**
7729
- * Calculates the Late Start (LS) and Late Finish (LF) for the current activity.
7730
- * @returns {Object} An object containing the Late Start (LS) and Late Finish (LF) dates.
7731
- * @throws {Error} If there's an issue with retrieving the calendar or calculating the dates.
7732
- */
7733
7458
  calculateTheLsAndLfForTheActivity(parentDates = null) {
7734
7459
  try {
7735
7460
  const duration = this.activity.duration;
@@ -7756,12 +7481,6 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
7756
7481
  throw Error(error.message);
7757
7482
  }
7758
7483
  }
7759
- /**
7760
- * Calculates the minimum between the minimum date from links and the end date of the project
7761
- * or the end date of the activity, depending on the constraint type.
7762
- * @param {Object} minCalculatedDateFromLinks - The minimum calculated date from links.
7763
- * @returns {Date} The minimum date between the calculated date from links and the end date.
7764
- */
7765
7484
  SnetSnltMsoMinDate(minCalculatedDateFromLinks) {
7766
7485
  const minDateOfEndOfProjectAndLinks = Math.min(
7767
7486
  minCalculatedDateFromLinks.lf,
@@ -7771,12 +7490,6 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
7771
7490
  Math.max(minDateOfEndOfProjectAndLinks, this.activity.end_date)
7772
7491
  );
7773
7492
  }
7774
- /**
7775
- * Calculates the successor and/or predecessor times based on the link type and constraints.
7776
- * @param {Object} linkData - The link data object containing information about the link.
7777
- * @returns {void} Returns nothing if the calculation is avoided based on the progress of the target activity.
7778
- * @throws {Error} Throws an error if activity data is not found or if an error occurs during calculation.
7779
- */
7780
7493
  calculateLink(linkData) {
7781
7494
  const activityFromLink = this.gantt.getTask(linkData.target);
7782
7495
  if (!activityFromLink) {
@@ -7796,29 +7509,17 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
7796
7509
  };
7797
7510
  return calculationMapping[linkData.type]();
7798
7511
  }
7799
- /**
7800
- * Determines the special calculation parameter based on the constraint type.
7801
- * @returns {string|undefined} Returns a special parameter for specific constraint types, or undefined if no special parameter is needed.
7802
- */
7803
7512
  getSpecialCalculationParamForConstraintLink() {
7804
7513
  if (this.constraint === CONSTRAINT_TYPES.ALAP) return CONSTRAINT_TYPES.ALAP;
7805
7514
  if (this.constraint === CONSTRAINT_TYPES.FNET || this.constraint === CONSTRAINT_TYPES.SNET)
7806
7515
  return "snet-fnet";
7807
7516
  if (this.constraint === CONSTRAINT_TYPES.FNLT) return CONSTRAINT_TYPES.FNLT;
7808
7517
  }
7809
- /**
7810
- * Determines the special calculation parameter based on the constraint type.
7811
- * @returns {string|undefined} Returns a special parameter for specific constraint types, or undefined if no special parameter is needed.
7812
- */
7813
7518
  getSpecialParamForSf() {
7814
7519
  const constriantThatNeedSpecialParam = [CONSTRAINT_TYPES.ALAP];
7815
7520
  if (constriantThatNeedSpecialParam.includes(this.constraint)) return true;
7816
7521
  return false;
7817
7522
  }
7818
- /**
7819
- * Determines the special calculation parameter based on the constraint type.
7820
- * @returns {string|undefined} Returns a special parameter for specific constraint types, or undefined if no special parameter is needed.
7821
- */
7822
7523
  getSpecialParamForFF() {
7823
7524
  const constraintsThatNeedSpecialFFParam = [
7824
7525
  CONSTRAINT_TYPES.MFO,
@@ -7828,11 +7529,6 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
7828
7529
  return true;
7829
7530
  return false;
7830
7531
  }
7831
- /**
7832
- * Determines the minimum calculation logic based on the constraint type.
7833
- * @param {Object} minCalculateFromLinks - The minimum calculation data from links.
7834
- * @returns {Date} Returns the minimum calculation date based on the constraint type.
7835
- */
7836
7532
  getMinCalculationLogic(minCalculateFromLinks) {
7837
7533
  if (this.constraint === CONSTRAINT_TYPES.ALAP) {
7838
7534
  return this.getMinDateBasedOnConstraint(minCalculateFromLinks);
@@ -7853,11 +7549,6 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
7853
7549
  return this.getMinDateBasedOnConstraint(minCalculateFromLinks);
7854
7550
  }
7855
7551
  }
7856
- /**
7857
- * Calculates the minimum date from the list of link calculations based on the constraint type.
7858
- * @param {Array} allLinksCalculations - The list of all link calculations.
7859
- * @returns {Object} Returns the minimum date from the link calculations.
7860
- */
7861
7552
  getMinDateFromLinks(allLinksCalculations) {
7862
7553
  try {
7863
7554
  if (this.constraint === CONSTRAINT_TYPES.ALAP || this.constraint === CONSTRAINT_TYPES.ASAP) {
@@ -7880,16 +7571,6 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
7880
7571
  (min, activity) => activity.lf < min.lf ? activity : min
7881
7572
  );
7882
7573
  }
7883
- /**
7884
- * Gets the minimum date between the links' minimum date and the end of the project based on the constraint type.
7885
- *
7886
- * @param {Object} minCalculatedDateFromLinks - The minimum calculated date from links.
7887
- * @param {Date} minCalculatedDateFromLinks.lf - The latest finish date from links.
7888
- * @param {string} constraintType - The constraint type of the activity.
7889
- * @returns {Date} The calculated minimum date based on the constraint type.
7890
- *
7891
- * @throws {Error} If an error occurs during the calculation process.
7892
- */
7893
7574
  getMinDateBasedOnConstraint(minCalculatedDateFromLinks, constraintType = this.constraint) {
7894
7575
  const minDateOfEndOfProjectAndLinks = Math.min(
7895
7576
  minCalculatedDateFromLinks.lf,
@@ -8040,23 +7721,6 @@ var BackwardPath = class extends generic_calculations_default {
8040
7721
  lf: maxLf
8041
7722
  });
8042
7723
  }
8043
- /**
8044
- * Calculates the latest start (LS) and latest finish (LF) times for a list of activities.
8045
- *
8046
- * This function processes each activity in the `activitiesToCalculate` list, retrieves the necessary
8047
- * information, and calculates the LS and LF times based on the activity's progress and constraint type.
8048
- * It handles various constraints and updates the calculations accordingly.
8049
- *
8050
- * @param {Array<string|number>} activitiesToCalculate - A list of activity IDs for which to calculate LS and LF times.
8051
- * @returns {void} This function does not return a value.
8052
- *
8053
- * @example
8054
- * // Assuming activitiesToCalculate is an array containing activity IDs [1, 2, 3]
8055
- * calculateStartAndFinishTimes([1, 2, 3]);
8056
- * // This will calculate the LS and LF times for the activities and update the internal calculations map.
8057
- *
8058
- * @throws {Error} If an error occurs during the process.
8059
- */
8060
7724
  calculateStartAndFinishTimes(activitiesToCalculate) {
8061
7725
  activitiesToCalculate.forEach((activityId) => {
8062
7726
  let activityReference = this.gantt.getTask(activityId);
@@ -8134,29 +7798,6 @@ var BackwardPath = class extends generic_calculations_default {
8134
7798
  });
8135
7799
  });
8136
7800
  }
8137
- /**
8138
- * Determines the least late time for an activity based on ES and EF constraints.
8139
- *
8140
- * This function compares the latest finish (LF) time from links with the earliest finish (EF) constraint
8141
- * for the activity. If the LF from links is less than the EF constraint, it returns the LF from links.
8142
- * Otherwise, it returns the ES and EF constraints.
8143
- *
8144
- * @param {string|number} activity - The ID of the activity.
8145
- * @param {Object} lfFromLinks - An object containing LS (latest start) and LF (latest finish) times from links.
8146
- * @param {Date} lfFromLinks.ls - The latest start time from links.
8147
- * @param {Date} lfFromLinks.lf - The latest finish time from links.
8148
- * @returns {Object} An object containing the least late LS and LF times.
8149
- * @property {Date} ls - The least late latest start time.
8150
- * @property {Date} lf - The least late latest finish time.
8151
- *
8152
- * @example
8153
- * // Assuming forwardConstraintsMap contains the ES and EF constraints for the activity
8154
- * const result = getTheLessLateInBasEsEfConstraint(1, { ls: new Date(), lf: new Date() });
8155
- * console.log()
8156
- // { ls: Date, lf: Date }
8157
- *
8158
- * @throws {Error} If an error occurs during the process.
8159
- */
8160
7801
  getTheLessLateInBasEsEfConstraint(activity, lfFromLinks, constraintType) {
8161
7802
  let esEfFromConstraint = this.forwardConstraintsMap.get(activity);
8162
7803
  if (!esEfFromConstraint) {
@@ -8175,23 +7816,6 @@ var BackwardPath = class extends generic_calculations_default {
8175
7816
  }
8176
7817
  return { ls: esEfFromConstraint.es, lf: esEfFromConstraint.ef };
8177
7818
  }
8178
- /**
8179
- * Checks whether all activities linked to the given set of activities have progress greater than 0.
8180
- *
8181
- * This function iterates over the linked activities, retrieves their data, and checks if all of them have progress greater than 0.
8182
- * If any linked activity has 0 progress, the function returns false. If all linked activities have progress, it returns true.
8183
- *
8184
- * @param {Array<string|number>} linkedActivities - An array of linked activity IDs.
8185
- * @returns {boolean} True if all linked activities have progress greater than 0, otherwise false.
8186
- *
8187
- * @example
8188
- * // Assuming linkedActivities is an array containing linked activity IDs [1, 2, 3]
8189
- * const allHaveProgress = allLinkedActivitiesHasProgress([1, 2, 3]);
8190
- * console.log()
8191
- // true or false based on the progress of the linked activities
8192
- *
8193
- * @throws {Error} If an error occurs during the process, such as missing link data or activity data.
8194
- */
8195
7819
  allLinkedActivitiesHasProgress(linkedActivities) {
8196
7820
  try {
8197
7821
  let allLinkedHasProgress = true;
@@ -8216,46 +7840,9 @@ var BackwardPath = class extends generic_calculations_default {
8216
7840
  throw new Error(error.message);
8217
7841
  }
8218
7842
  }
8219
- /**
8220
- * Sets the calculations for an activity that has 100% progress.
8221
- *
8222
- * This function uses the activity's start and end dates to set the calculations for the activity.
8223
- * It is assumed that the activity has 100% progress.
8224
- *
8225
- * @param {Object} activity - The activity object containing the details of the activity.
8226
- * @param {Date} activity.start_date - The start date of the activity.
8227
- * @param {Date} activity.end_date - The end date of the activity.
8228
- * @returns {void} This function does not return a value.
8229
- *
8230
- * @example
8231
- * // Assuming activity is an object with start_date and end_date properties
8232
- * setDatesForActivityWithFullProgress({
8233
- * start_date: new Date('2023-01-01'),
8234
- * end_date: new Date('2023-01-10')
8235
- * });
8236
- * // This will set the calculations for the activity using its start and end dates.
8237
- *
8238
- * @throws {Error} If an error occurs during the calculation process.
8239
- */
8240
7843
  setDatesForActivityWithFullProgress(activity) {
8241
7844
  this.setCalculations(activity, activity.start_date, activity.end_date);
8242
7845
  }
8243
- /**
8244
- * Sets the calculations for an activity when all its linked activities have progress.
8245
- *
8246
- * This function calculates the latest start (LS) and latest finish (LF) times for the activity using a backward direction,
8247
- * and sets these values in the internal calculations.
8248
- *
8249
- * @param {Object} activity - The activity object containing the details of the activity.
8250
- * @returns {void} This function does not return a value.
8251
- *
8252
- * @example
8253
- * // Assuming activity is an object with necessary properties for calculation
8254
- * setWhenAllLinkedActivitiesHasProgress(activity);
8255
- * // This will calculate LS and LF for the activity and set these values in the internal calculations.
8256
- *
8257
- * @throws {Error} If an error occurs during the calculation process.
8258
- */
8259
7846
  setWhenAllLinkedActivitiesHasProgress(activity) {
8260
7847
  const parent = Number(activity.parent);
8261
7848
  let { ls, lf } = this.calculateStartAndFinishOfChainOrigin(
@@ -8272,23 +7859,6 @@ var BackwardPath = class extends generic_calculations_default {
8272
7859
  this.setCalculations(activity, ls, lf);
8273
7860
  return;
8274
7861
  }
8275
- /**
8276
- * Sets the calculations for an activity with progress greater than 0% but less than 100%.
8277
- *
8278
- * This function handles activities based on their constraint type when the progress is between 0% and 100%.
8279
- * It sets the calculations accordingly using the activity's start and end dates, or the constraint dates.
8280
- *
8281
- * @param {Object} activity - The activity object containing the details of the activity.
8282
- * @param {string} constraintType - The constraint type of the activity, such as 'mso' or 'mfo'.
8283
- * @returns {void} This function does not return a value.
8284
- *
8285
- * @example
8286
- * // Assuming activity is an object with start_date, end_date, and constraint_date properties, and constraintType is 'mso'
8287
- * setWhenActivitiesHasProgressButLessThanOneHundred(activity, 'mso');
8288
- * // This will set the calculations for the activity using its start and end dates.
8289
- *
8290
- * @throws {Error} If an error occurs during the calculation process.
8291
- */
8292
7862
  setWhenActivitiesHasProgressButLessThanOneHundred(activity, constraintType) {
8293
7863
  if (constraintType === CONSTRAINT_TYPES.MSO) {
8294
7864
  this.setCalculations(activity, activity.start_date, activity.end_date);
@@ -8304,24 +7874,6 @@ var BackwardPath = class extends generic_calculations_default {
8304
7874
  return;
8305
7875
  }
8306
7876
  }
8307
- /**
8308
- * Sets the latest start (LS) and latest finish (LF) times for a given activity in the internal calculations map.
8309
- *
8310
- * This function stores the LS and LF times, along with the activity's text, in the internal `calculations` map
8311
- * using the activity's ID as the key.
8312
- *
8313
- * @param {Object} activity - The activity object containing the details of the activity.
8314
- * @param {Date} ls - The latest start time for the activity.
8315
- * @param {Date} lf - The latest finish time for the activity.
8316
- * @returns {void} This function does not return a value.
8317
- *
8318
- * @example
8319
- * // Assuming activity is an object with id and text properties, and ls and lf are Date objects
8320
- * setCalculations(activity, new Date('2023-01-01'), new Date('2023-01-10'));
8321
- * // This will store the LS and LF times in the calculations map for the given activity.
8322
- *
8323
- * @throws {Error} If an error occurs during the calculation process.
8324
- */
8325
7877
  setCalculations(activity, ls, lf) {
8326
7878
  this.calculations.set(activity.id, {
8327
7879
  ls,
@@ -8329,28 +7881,6 @@ var BackwardPath = class extends generic_calculations_default {
8329
7881
  text: activity.text
8330
7882
  });
8331
7883
  }
8332
- /**
8333
- * Calculates the latest start (LS) and latest finish (LF) times for an activity based on its links with successors and the given constraint type.
8334
- *
8335
- * This function creates a new instance of the `LinksConstraintCalculator` class with the provided parameters and calls its `calculate` method
8336
- * to determine the LS and LF times for the activity.
8337
- *
8338
- * @param {Array<string|number>} linksWithSucessors - An array of links to successor activities.
8339
- * @param {Object} activityReference - The activity object for which to calculate LS and LF times.
8340
- * @param {string} constraintType - The constraint type of the activity.
8341
- * @returns {Object} An object containing the calculated latest start (LS) and latest finish (LF) times.
8342
- * @property {Date} ls - The calculated latest start time.
8343
- * @property {Date} lf - The calculated latest finish time.
8344
- *
8345
- * @example
8346
- * // Assuming linksWithSucessors is an array of link IDs, activityReference is an activity object,
8347
- * // and constraintType is a string representing the constraint type
8348
- * const result = calculateLfandLsFromLinks([1, 2, 3], activityReference, 'mso');
8349
- * console.log()
8350
- // { ls: Date, lf: Date }
8351
- *
8352
- * @throws {Error} If an error occurs during the calculation process.
8353
- */
8354
7884
  calculateLfandLsFromLinks(linksWithSucessors, activityReference, constraintType, parentsWithFullProgress, parentsThatImpactChildrens) {
8355
7885
  return new LinksConstraintCalculator_default({
8356
7886
  links: linksWithSucessors,
@@ -8363,23 +7893,6 @@ var BackwardPath = class extends generic_calculations_default {
8363
7893
  ganttInstance: this.gantt
8364
7894
  }).calculate();
8365
7895
  }
8366
- /**
8367
- * Recalculates the latest start (LS) and latest finish (LF) times for an activity based on its constraint type.
8368
- *
8369
- * This function fetches the activity's calendar, calculates the restriction based on the constraint type,
8370
- * updates the constraint map, and sets the new calculations for the activity.
8371
- *
8372
- * @param {Object} activity - The activity object containing the details of the activity.
8373
- * @param {string} constraintType - The constraint type of the activity.
8374
- * @returns {void} This function does not return a value.
8375
- *
8376
- * @example
8377
- * // Assuming activity is an object with calendar_id property, and constraintType is 'mso'
8378
- * recalculateInBaseRestriction(activity, 'mso');
8379
- * // This will recalculate the LS and LF times for the activity based on the constraint type and update the internal calculations.
8380
- *
8381
- * @throws {Error} If an error occurs during the calculation process, such as missing calendar data.
8382
- */
8383
7896
  recalculateInBaseRestriction(activity, constraintType) {
8384
7897
  try {
8385
7898
  const activityCalendar = this.gantt.getCalendar(activity.calendar_id);
@@ -9427,6 +8940,7 @@ var NON_SCHEDULING_KINDS = /* @__PURE__ */ new Set([
9427
8940
  "selection-toggle",
9428
8941
  "selection-replace",
9429
8942
  "visibility-set",
8943
+ "filter-set",
9430
8944
  "sir-sync",
9431
8945
  "activity-lookahead-sync",
9432
8946
  "persistence-acknowledge",
@@ -9434,6 +8948,15 @@ var NON_SCHEDULING_KINDS = /* @__PURE__ */ new Set([
9434
8948
  "ponderator-criterion-set",
9435
8949
  "status-criteria-set"
9436
8950
  ]);
8951
+ var PURE_VIEW_STATE_KINDS = /* @__PURE__ */ new Set([
8952
+ "selection-toggle",
8953
+ "selection-replace",
8954
+ "visibility-set",
8955
+ "filter-set"
8956
+ ]);
8957
+ function reappliesActiveFilter(action) {
8958
+ return !PURE_VIEW_STATE_KINDS.has(action.kind);
8959
+ }
9437
8960
  var NO_STRUCTURAL_EXEMPTIONS = /* @__PURE__ */ new Set();
9438
8961
  function editsOnlyNonSchedulingColumns(action) {
9439
8962
  if (action.kind === "inline-edit") {
@@ -9742,7 +9265,7 @@ function detectSirAutoReject(beforeSnap, adapter, touchedIds) {
9742
9265
  }
9743
9266
 
9744
9267
  // src/dispatch/shared/change-set.ts
9745
- function assembleChangeSet(adapter, args) {
9268
+ async function assembleChangeSet(adapter, args) {
9746
9269
  const allTouched = collectChangeSetIds(adapter, args);
9747
9270
  const before = new Map(args.beforeSnap);
9748
9271
  const captured = adapter.peekWriteCapture();
@@ -9751,7 +9274,16 @@ function assembleChangeSet(adapter, args) {
9751
9274
  mergeDirtyBeforeImages(adapter, captured, insertedIds, before, allTouched);
9752
9275
  }
9753
9276
  const beforeDiffEffects = args.sirDetection === "before-diff" ? detectSirAutoReject(before, adapter, allTouched) : [];
9754
- const activityChanges = buildActivityChanges(adapter, before, allTouched);
9277
+ const correlativeBefore = buildCorrelativeBeforeMap(
9278
+ args.correlativeShifts,
9279
+ allTouched
9280
+ );
9281
+ const activityChanges = await buildActivityChanges(
9282
+ adapter,
9283
+ before,
9284
+ allTouched,
9285
+ correlativeBefore
9286
+ );
9755
9287
  const effects = args.sirDetection === "after-diff" ? detectSirAutoReject(before, adapter, allTouched) : beforeDiffEffects;
9756
9288
  const warnings = args.warnings ?? [];
9757
9289
  return {
@@ -9759,12 +9291,20 @@ function assembleChangeSet(adapter, args) {
9759
9291
  activities: activityChanges,
9760
9292
  links: args.links ?? [],
9761
9293
  calendars: [],
9762
- // dispatch never mutates calendars
9763
9294
  trackingEvents: args.trackingEvents ?? [],
9764
9295
  ...effects.length > 0 ? { effects } : {},
9765
9296
  ...warnings.length > 0 ? { warnings } : {}
9766
9297
  };
9767
9298
  }
9299
+ function buildCorrelativeBeforeMap(shifts, touched) {
9300
+ if (!shifts || shifts.length === 0) return void 0;
9301
+ const correlativeBefore = /* @__PURE__ */ new Map();
9302
+ for (const shift of shifts) {
9303
+ correlativeBefore.set(shift.activityId, shift.before);
9304
+ touched.add(shift.activityId);
9305
+ }
9306
+ return correlativeBefore;
9307
+ }
9768
9308
  function collectChangeSetIds(adapter, args) {
9769
9309
  const ids = /* @__PURE__ */ new Set();
9770
9310
  for (const id of args.touchedIds) ids.add(id);
@@ -9962,7 +9502,7 @@ async function dispatchInlineEdit(action, options, deps) {
9962
9502
  parsed2.raw
9963
9503
  );
9964
9504
  const touchedIds = collectTouchedIds(action.activityId, changes);
9965
- const beforeSnap = snapshotActivities(adapter, touchedIds);
9505
+ const beforeSnap = await snapshotActivities(adapter, touchedIds);
9966
9506
  const beforeLinkLags = snapshotIncomingLinkLags(
9967
9507
  adapter,
9968
9508
  String(action.activityId)
@@ -10034,7 +9574,7 @@ async function dispatchInlineEdit(action, options, deps) {
10034
9574
  );
10035
9575
  return {
10036
9576
  ok: true,
10037
- changes: assembleChangeSet(adapter, {
9577
+ changes: await assembleChangeSet(adapter, {
10038
9578
  source: action,
10039
9579
  beforeSnap,
10040
9580
  touchedIds,
@@ -10144,7 +9684,10 @@ async function dispatchLinkBatch(operations, source, options, deps, deterministi
10144
9684
  const { adapter, scheduler, sector, linkIdGen } = deps;
10145
9685
  scheduler.invalidateAllCaches();
10146
9686
  const { activityIds: affectedActivityIds, links: beforeLinks } = collectBatchContext(operations, adapter);
10147
- const beforeActivities = snapshotActivities(adapter, affectedActivityIds);
9687
+ const beforeActivities = await snapshotActivities(
9688
+ adapter,
9689
+ affectedActivityIds
9690
+ );
10148
9691
  const applied = applyBatchOperations(
10149
9692
  operations,
10150
9693
  adapter,
@@ -10187,7 +9730,7 @@ async function dispatchLinkBatch(operations, source, options, deps, deterministi
10187
9730
  }
10188
9731
  ),
10189
9732
  __beforeLinks: stringKeyedLinkSnapshots(beforeLinks),
10190
- changes: assembleChangeSet(adapter, {
9733
+ changes: await assembleChangeSet(adapter, {
10191
9734
  source,
10192
9735
  beforeSnap: beforeActivities,
10193
9736
  touchedIds: affectedActivityIds,
@@ -10794,7 +10337,7 @@ function computeFractionalCidAtIndex(adapter, parentKey, targetIndex, excludeId)
10794
10337
  }
10795
10338
 
10796
10339
  // src/dispatch/handlers/activity-create.ts
10797
- function createActivityCore(action, deps, opts = {}) {
10340
+ async function createActivityCore(action, deps, opts = {}) {
10798
10341
  const { adapter, scheduler, sector, calendars, activityIdGen, uidGen } = deps;
10799
10342
  scheduler.invalidateAllCaches();
10800
10343
  const target = validateCreateTarget(action, adapter);
@@ -10835,7 +10378,7 @@ function createActivityCore(action, deps, opts = {}) {
10835
10378
  const initialTouched = /* @__PURE__ */ new Set([newId]);
10836
10379
  if (parent) initialTouched.add(parent.id);
10837
10380
  const parentWasLeaf = parent !== null && adapter.getChildren(parent.id).length === 0;
10838
- const beforeSnap = opts.skipBeforeSnap ? /* @__PURE__ */ new Map() : snapshotActivities(adapter, initialTouched);
10381
+ const beforeSnap = opts.skipBeforeSnap ? /* @__PURE__ */ new Map() : await snapshotActivities(adapter, initialTouched);
10839
10382
  adapter.addActivity(newActivity);
10840
10383
  applyParentMutations(
10841
10384
  action,
@@ -10955,7 +10498,7 @@ function recomputeAndFoldCorrelatives(adapter, newId, beforeSnap, initialTouched
10955
10498
  initialTouched
10956
10499
  );
10957
10500
  }
10958
- function buildCreateChangeSet(adapter, action, coreResult, scheduledIds, hoursPerDay) {
10501
+ async function buildCreateChangeSet(adapter, action, coreResult, scheduledIds, hoursPerDay) {
10959
10502
  const { newId, newActivity, beforeSnap, initialTouched } = coreResult;
10960
10503
  const trackingEvent = {
10961
10504
  name: DISPATCH_TRACK_EVENT.ACTIVITY_CREATION,
@@ -10977,7 +10520,7 @@ function buildCreateChangeSet(adapter, action, coreResult, scheduledIds, hoursPe
10977
10520
  }
10978
10521
  async function dispatchActivityCreate(action, options, deps) {
10979
10522
  const { adapter, scheduler, sector } = deps;
10980
- const core = createActivityCore(action, deps);
10523
+ const core = await createActivityCore(action, deps);
10981
10524
  if (!core.ok) return core;
10982
10525
  const { newId } = core;
10983
10526
  const createdAutoScheduling = core.newActivity.autoScheduling;
@@ -11003,7 +10546,7 @@ async function dispatchActivityCreate(action, options, deps) {
11003
10546
  adapter.setActivityField(newId, "autoScheduling", createdAutoScheduling);
11004
10547
  }
11005
10548
  const { scheduledIds } = scheduleOutcome;
11006
- const changeset = buildCreateChangeSet(
10549
+ const changeset = await buildCreateChangeSet(
11007
10550
  adapter,
11008
10551
  action,
11009
10552
  core,
@@ -11053,7 +10596,7 @@ async function dispatchActivityPaste(action, options, deps) {
11053
10596
  const { adapter, scheduler, sector } = deps;
11054
10597
  const rootDest = resolvePasteRootDestination(action.destination, adapter);
11055
10598
  if (!rootDest.ok) return rootDest;
11056
- const beforeSnap = snapshotActivities(adapter, /* @__PURE__ */ new Set());
10599
+ const beforeSnap = await snapshotActivities(adapter, /* @__PURE__ */ new Set());
11057
10600
  const touched = /* @__PURE__ */ new Set();
11058
10601
  const originalToNew = /* @__PURE__ */ new Map();
11059
10602
  const createdIds = [];
@@ -11074,7 +10617,7 @@ async function dispatchActivityPaste(action, options, deps) {
11074
10617
  afterSiblingId = prevRootId;
11075
10618
  }
11076
10619
  }
11077
- const core = createActivityCore(
10620
+ const core = await createActivityCore(
11078
10621
  {
11079
10622
  parentId,
11080
10623
  afterSiblingId,
@@ -11085,16 +10628,8 @@ async function dispatchActivityPaste(action, options, deps) {
11085
10628
  },
11086
10629
  deps,
11087
10630
  {
11088
- // Saltamos el recompute por-create: corre UNA vez tras el loop (abajo).
11089
10631
  skipCorrelativeRecompute: true,
11090
- // Saltamos el snapshot per-create: el paste ya capturó `beforeSnap` del
11091
- // árbol completo antes del loop (O(N²) de clones puros si no).
11092
10632
  skipBeforeSnap: true,
11093
- // custom_id (paridad legacy): TODAS las pegadas derivan del ancla de
11094
- // pegado. Los roots ya lo logran vía `afterSiblingId`; los HIJOS
11095
- // (mappedParent) no tienen sibling anchor → les pasamos el ancla como
11096
- // `customIdReferenceId`, y preservamos el custom_id de su parent pegado
11097
- // (que si no, `buildParentMutations` limpiaría al adjuntar el hijo).
11098
10633
  ...mappedParent !== void 0 ? {
11099
10634
  customIdReferenceId: action.referenceActivityId,
11100
10635
  preserveParentCustomId: true
@@ -11138,9 +10673,6 @@ async function dispatchActivityPaste(action, options, deps) {
11138
10673
  source: newSource,
11139
10674
  target: newTarget,
11140
10675
  type: link.type,
11141
- // El clipboard trae `lag` en DÍAS (getLink/getAllLinks → lagHoursToDays);
11142
- // el motor lo almacena en HORAS LABORALES. Convertir acá, igual que
11143
- // `duration` arriba y que `link-create`/`link-update` — el borde de entrada.
11144
10676
  lag: lagDaysToHours(link.lag, sector.hoursPerDay)
11145
10677
  };
11146
10678
  const res = applyLinkOperation(op, {
@@ -11175,7 +10707,7 @@ async function dispatchActivityPaste(action, options, deps) {
11175
10707
  );
11176
10708
  return {
11177
10709
  ok: true,
11178
- changes: assembleChangeSet(adapter, {
10710
+ changes: await assembleChangeSet(adapter, {
11179
10711
  source: action,
11180
10712
  beforeSnap,
11181
10713
  touchedIds: touched,
@@ -11387,6 +10919,7 @@ function buildParentNewActivitiesCleanup(input) {
11387
10919
  }
11388
10920
 
11389
10921
  // src/dispatch/handlers/activity-delete.ts
10922
+ var DELETE_YIELD_EVERY_N = 200;
11390
10923
  async function dispatchActivityDelete(action, options, deps) {
11391
10924
  const { adapter, scheduler, customIdTracker, sector } = deps;
11392
10925
  scheduler.invalidateAllCaches();
@@ -11410,14 +10943,17 @@ async function dispatchActivityDelete(action, options, deps) {
11410
10943
  if (!toDelete.has(parentKey)) parentsToCheck.add(parentKey);
11411
10944
  }
11412
10945
  const touchedIds = /* @__PURE__ */ new Set([...toDelete, ...parentsToCheck]);
11413
- const beforeSnap = snapshotActivities(adapter, touchedIds);
10946
+ const beforeSnap = await snapshotActivities(adapter, touchedIds);
11414
10947
  const beforeLinks = /* @__PURE__ */ new Map();
11415
10948
  for (const linkId of incidentLinkIds) {
11416
10949
  const l = adapter.getLink(linkId);
11417
10950
  if (l) beforeLinks.set(linkId, { ...l });
11418
10951
  }
11419
10952
  const newActivitiesToDelete = /* @__PURE__ */ new Set();
10953
+ let inspected = 0;
11420
10954
  for (const id of toDelete) {
10955
+ inspected += 1;
10956
+ if (inspected % DELETE_YIELD_EVERY_N === 0) await yieldToBrowser();
11421
10957
  const a = adapter.getActivity(id);
11422
10958
  if (!a) continue;
11423
10959
  const parent = isRootParent(a.parentId) ? null : adapter.getActivity(String(a.parentId));
@@ -11434,7 +10970,10 @@ async function dispatchActivityDelete(action, options, deps) {
11434
10970
  adapter.removeLink(linkId);
11435
10971
  }
11436
10972
  const viewStateChanges = captureDeletedViewState(adapter, toDelete);
10973
+ let removed = 0;
11437
10974
  for (const id of toDelete) {
10975
+ removed += 1;
10976
+ if (removed % DELETE_YIELD_EVERY_N === 0) await yieldToBrowser();
11438
10977
  adapter.removeActivity(id);
11439
10978
  }
11440
10979
  for (const parentId of parentsToCheck) {
@@ -11474,15 +11013,6 @@ async function dispatchActivityDelete(action, options, deps) {
11474
11013
  recomputeRollupCascadesForParent(parentId, adapter);
11475
11014
  }
11476
11015
  const correlativeShifts = recomputeCorrelativeIds(adapter);
11477
- for (const shift of correlativeShifts) {
11478
- touchedIds.add(shift.activityId);
11479
- if (beforeSnap.has(shift.activityId)) continue;
11480
- const liveActivity = adapter.getActivity(shift.activityId);
11481
- if (!liveActivity) continue;
11482
- const beforeImage = structuredCloneActivity(liveActivity);
11483
- if (shift.before !== void 0) beforeImage.correlativeId = shift.before;
11484
- beforeSnap.set(shift.activityId, beforeImage);
11485
- }
11486
11016
  const { scheduledIds } = await runPostMutation(
11487
11017
  {
11488
11018
  adapter,
@@ -11515,7 +11045,7 @@ async function dispatchActivityDelete(action, options, deps) {
11515
11045
  const snap = beforeSnap.get(String(id));
11516
11046
  if (snap) deletedRowsSnap.set(String(id), snap);
11517
11047
  }
11518
- const changes = assembleChangeSet(adapter, {
11048
+ const changes = await assembleChangeSet(adapter, {
11519
11049
  source: action,
11520
11050
  beforeSnap,
11521
11051
  touchedIds,
@@ -11523,7 +11053,8 @@ async function dispatchActivityDelete(action, options, deps) {
11523
11053
  sirDetection: "after-diff",
11524
11054
  links: buildLinkDeletions(beforeLinks),
11525
11055
  trackingEvents: [trackingEvent],
11526
- hoursPerDay: sector.hoursPerDay
11056
+ hoursPerDay: sector.hoursPerDay,
11057
+ correlativeShifts
11527
11058
  });
11528
11059
  return {
11529
11060
  ok: true,
@@ -11563,8 +11094,6 @@ function buildLinkDeletions(beforeLinks) {
11563
11094
  source: { before: String(before.source), after: void 0 },
11564
11095
  target: { before: String(before.target), after: void 0 },
11565
11096
  type: { before: before.type, after: void 0 },
11566
- // Engine stores lag in WORKING HOURS — ChangeSet now emits HOURS too.
11567
- // `toPublicChangeSet` at the facade boundary converts to days (default).
11568
11097
  lag: { before: Number(before.lag), after: void 0 }
11569
11098
  },
11570
11099
  after: null
@@ -11653,7 +11182,7 @@ async function dispatchActivityMove(action, options, deps) {
11653
11182
  } else {
11654
11183
  if (oldParentKey !== ROOT_PARENT_ID) touched.add(oldParentKey);
11655
11184
  }
11656
- const beforeSnap = snapshotActivities(adapter, touched);
11185
+ const beforeSnap = await snapshotActivities(adapter, touched);
11657
11186
  if (parentChanged) {
11658
11187
  adapter.setActivityField(
11659
11188
  action.activityId,
@@ -11683,8 +11212,6 @@ async function dispatchActivityMove(action, options, deps) {
11683
11212
  newChildId: action.activityId,
11684
11213
  getParent: (id) => adapter.getActivity(id) ?? null,
11685
11214
  isCurrentlyLeaf: wasLeaf,
11686
- // Move reparents an EXISTING child — legacy never re-stamps the new
11687
- // parent's progress (it keeps its pre-move leaf value). See JUN-23.
11688
11215
  promotionSource: "reparent"
11689
11216
  });
11690
11217
  if (promotion) {
@@ -11793,7 +11320,7 @@ async function dispatchActivityMove(action, options, deps) {
11793
11320
  }
11794
11321
  return {
11795
11322
  ok: true,
11796
- changes: assembleChangeSet(adapter, {
11323
+ changes: await assembleChangeSet(adapter, {
11797
11324
  source: action,
11798
11325
  beforeSnap,
11799
11326
  touchedIds: touched,
@@ -11855,7 +11382,7 @@ async function dispatchActivityIndent(action, options, deps) {
11855
11382
  touched.add(targetParentId);
11856
11383
  if (oldParentId !== ROOT_PARENT_ID) touched.add(oldParentId);
11857
11384
  }
11858
- const beforeSnap = snapshotActivities(adapter, touched);
11385
+ const beforeSnap = await snapshotActivities(adapter, touched);
11859
11386
  for (const { activityId, newParentId } of moves) {
11860
11387
  adapter.setActivityField(activityId, ACTIVITY_PROPERTY.PARENT, newParentId);
11861
11388
  adapter.setActivityField(
@@ -11879,8 +11406,6 @@ async function dispatchActivityIndent(action, options, deps) {
11879
11406
  newChildId: activityId,
11880
11407
  getParent: (id) => adapter.getActivity(id) ?? null,
11881
11408
  isCurrentlyLeaf: wasLeaf,
11882
- // Indent reparents an EXISTING child — legacy never re-stamps the new
11883
- // parent's progress (it keeps its pre-indent leaf value). See JUN-23.
11884
11409
  promotionSource: "reparent"
11885
11410
  });
11886
11411
  if (promotion) {
@@ -11947,33 +11472,8 @@ async function dispatchActivityIndent(action, options, deps) {
11947
11472
  },
11948
11473
  {
11949
11474
  action,
11950
- // A pure indent (reparent) does NOT auto-reschedule dates in legacy:
11951
- // `actions.indent` runs purely through `gantt.moveTask`, firing only
11952
- // `onBeforeTaskMove`/`onAfterTaskMove` — never `autoSchedule()` /
11953
- // `onAfterAutoSchedule`. So the moved child + its downstream chain KEEP
11954
- // their pre-indent dates; only the new parent's bounds re-roll (via
11955
- // DHTMLX `_update_parents` in the move's batchUpdate — done unconditionally
11956
- // by `updateParentBoundsFromChildren` below). The core previously passed
11957
- // `{}` here, running a full ASAP/ALAP reflow that pulled the moved child +
11958
- // chain as-early-as-possible — diverging from the oracle (MORNING_QUEUE.md
11959
- // — JUN-11 corr20 stays 2024-05-07 stale, core moved it to 04-30; JUN-16(B)
11960
- // corr33 stays 2026-10-21 stale, core pulled it to 09-16). `null` suppresses
11961
- // the date cascade entirely, completing the outdent mirror (outdent's `{}`
11962
- // was always a no-op because its moved child keeps its links/position; a
11963
- // childless leaf + reparent of an EXISTING activity is never the trigger
11964
- // of an autoSchedule). A SUBSEQUENT date/constraint/link edit still
11965
- // cascades normally (its own handler passes a non-null trigger).
11966
11475
  autoscheduleFrom: null,
11967
11476
  recomputeParentsFrom: succeededIds,
11968
- // A pure indent re-rolls the new parent's start/end/duration but legacy
11969
- // leaves `for_disable_milestone_duration` STALE at the pre-indent value —
11970
- // the milestone-promotion branch (`adjustParentMilestone`) only fires for a
11971
- // 0-duration milestone, never a task → project promotion (MORNING_QUEUE.md
11972
- // — JUN-18 / JUN-11). A later scheduling recalc that re-rolls these parents
11973
- // re-derives the mirror = duration — that is how the oracle's mirror is
11974
- // FRESH whenever an edit follows the indent (MORNING_QUEUE.md — JUN-19).
11975
- // `resolveDerivedPasses` skips the ancestor stamp for activity-indent.
11976
- // activity-indent is a structural reparent: leaves EP and CP stale.
11977
11477
  now: deps.now,
11978
11478
  options
11979
11479
  }
@@ -12005,7 +11505,7 @@ async function dispatchActivityIndent(action, options, deps) {
12005
11505
  reason: failure.reason
12006
11506
  } : { activityId: String(activityId), ok: true };
12007
11507
  }),
12008
- changes: assembleChangeSet(adapter, {
11508
+ changes: await assembleChangeSet(adapter, {
12009
11509
  source: action,
12010
11510
  beforeSnap,
12011
11511
  touchedIds: touched,
@@ -12103,7 +11603,7 @@ async function dispatchActivityOutdent(action, options, deps) {
12103
11603
  if (grandparentKey !== ROOT_PARENT_ID) touched.add(String(grandparentKey));
12104
11604
  oldParents.add(oldParentKey);
12105
11605
  }
12106
- const beforeSnap = snapshotActivities(adapter, touched);
11606
+ const beforeSnap = await snapshotActivities(adapter, touched);
12107
11607
  for (const plan of planned) {
12108
11608
  adapter.setActivityField(
12109
11609
  plan.activityId,
@@ -12190,12 +11690,9 @@ async function dispatchActivityOutdent(action, options, deps) {
12190
11690
  defaultBaseCalendarId: deps.defaultBaseCalendarId
12191
11691
  },
12192
11692
  {
12193
- // Empty-batch gate: nothing moved → no autoscheduler pass (the
12194
- // unconditional parent-bounds rollup still runs).
12195
11693
  action,
12196
11694
  autoscheduleFrom: succeededIds.length > 0 ? "roots" : null,
12197
11695
  recomputeParentsFrom: succeededIds,
12198
- // activity-outdent is a structural reparent: leaves EP and CP stale.
12199
11696
  now: deps.now,
12200
11697
  options
12201
11698
  }
@@ -12225,7 +11722,7 @@ async function dispatchActivityOutdent(action, options, deps) {
12225
11722
  reason: failure.reason
12226
11723
  } : { activityId: String(activityId), ok: true };
12227
11724
  }),
12228
- changes: assembleChangeSet(adapter, {
11725
+ changes: await assembleChangeSet(adapter, {
12229
11726
  source: action,
12230
11727
  beforeSnap,
12231
11728
  touchedIds: touched,
@@ -12262,7 +11759,7 @@ async function dispatchActivitySetProgress(action, options, deps) {
12262
11759
  action.newValue
12263
11760
  );
12264
11761
  const touchedIds = collectTouchedIds(action.activityId, changes);
12265
- const beforeSnap = snapshotActivities(adapter, touchedIds);
11762
+ const beforeSnap = await snapshotActivities(adapter, touchedIds);
12266
11763
  applyFieldChanges(adapter, action.activityId, changes);
12267
11764
  runPostProcessorsOnAdapter(
12268
11765
  action.activityId,
@@ -12278,7 +11775,6 @@ async function dispatchActivitySetProgress(action, options, deps) {
12278
11775
  },
12279
11776
  {
12280
11777
  action,
12281
- // Pipeline gate: only schedule when the transform asked for it.
12282
11778
  autoscheduleFrom: changes.needsAutoSchedule ? action.activityId : null,
12283
11779
  recomputeParentsFrom: [],
12284
11780
  collectDirty: (sids) => collectDirtyForInlineEdit(action.activityId, touchedIds, sids),
@@ -12292,7 +11788,7 @@ async function dispatchActivitySetProgress(action, options, deps) {
12292
11788
  }));
12293
11789
  return {
12294
11790
  ok: true,
12295
- changes: assembleChangeSet(adapter, {
11791
+ changes: await assembleChangeSet(adapter, {
12296
11792
  source: action,
12297
11793
  beforeSnap,
12298
11794
  touchedIds,
@@ -12321,9 +11817,10 @@ async function dispatchDatesBatch(action, options, deps) {
12321
11817
  mergeBeforeSnapshots(beforeSnap, editTouched, deps);
12322
11818
  for (const id of editTouched) touchedIds.add(id);
12323
11819
  const beforeLinkLags = snapshotIncomingLinkLags(adapter, edit.activityId);
12324
- const preEditSnapshot = snapshotActivities(adapter, /* @__PURE__ */ new Set([String(edit.activityId)])).get(
11820
+ const preEditSnapshot = snapshotSingleActivity(
11821
+ adapter,
12325
11822
  String(edit.activityId)
12326
- ) ?? null;
11823
+ );
12327
11824
  applyFieldChanges(adapter, edit.activityId, outcome.changes);
12328
11825
  runPostProcessorsOnAdapter(
12329
11826
  edit.activityId,
@@ -12365,7 +11862,7 @@ async function dispatchDatesBatch(action, options, deps) {
12365
11862
  return {
12366
11863
  ok: true,
12367
11864
  verdicts,
12368
- changes: assembleChangeSet(adapter, {
11865
+ changes: await assembleChangeSet(adapter, {
12369
11866
  source: action,
12370
11867
  beforeSnap,
12371
11868
  touchedIds,
@@ -12446,8 +11943,11 @@ function mergeBeforeSnapshots(beforeSnap, ids, deps) {
12446
11943
  if (!beforeSnap.has(id)) missing.add(id);
12447
11944
  }
12448
11945
  if (missing.size === 0) return;
12449
- for (const [id, snap] of snapshotActivities(deps.adapter, missing)) {
12450
- beforeSnap.set(id, snap);
11946
+ for (const missingId of missing) {
11947
+ const liveActivity = deps.adapter.getActivity(missingId);
11948
+ if (liveActivity) {
11949
+ beforeSnap.set(missingId, structuredCloneActivity(liveActivity));
11950
+ }
12451
11951
  }
12452
11952
  }
12453
11953
 
@@ -12487,9 +11987,10 @@ async function dispatchBulkEdit(action, options, deps) {
12487
11987
  explicitDateEditActivities.add(String(edit.activityId));
12488
11988
  }
12489
11989
  const beforeLinkLags = snapshotIncomingLinkLags(adapter, edit.activityId);
12490
- const preEditSnapshot = snapshotActivities(adapter, /* @__PURE__ */ new Set([String(edit.activityId)])).get(
11990
+ const preEditSnapshot = snapshotSingleActivity(
11991
+ adapter,
12491
11992
  String(edit.activityId)
12492
- ) ?? null;
11993
+ );
12493
11994
  const customIdBeforeApply = readLiveCustomId(edit, deps);
12494
11995
  const changes = outcome.changes;
12495
11996
  applyFieldChanges(adapter, edit.activityId, changes);
@@ -12553,14 +12054,11 @@ async function dispatchBulkEdit(action, options, deps) {
12553
12054
  return {
12554
12055
  ok: true,
12555
12056
  verdicts,
12556
- changes: assembleChangeSet(adapter, {
12057
+ changes: await assembleChangeSet(adapter, {
12557
12058
  source: action,
12558
12059
  beforeSnap,
12559
12060
  touchedIds,
12560
12061
  scheduledIds,
12561
- // Los dependientes que mueve el autoscheduler no están en beforeSnap;
12562
- // sin su before-image el diff los marca FALSE-CREATED y el undo los
12563
- // borra (fix 4bbccbc de inline-edit).
12564
12062
  sirDetection: "before-diff",
12565
12063
  links: linkChanges,
12566
12064
  trackingEvents,
@@ -12687,11 +12185,11 @@ function mergeBeforeSnapshots2(beforeSnap, ids, deps) {
12687
12185
  if (!beforeSnap.has(candidateId)) missing.add(candidateId);
12688
12186
  }
12689
12187
  if (missing.size === 0) return;
12690
- for (const [snappedId, snapshot] of snapshotActivities(
12691
- deps.adapter,
12692
- missing
12693
- )) {
12694
- beforeSnap.set(snappedId, snapshot);
12188
+ for (const missingId of missing) {
12189
+ const liveActivity = deps.adapter.getActivity(missingId);
12190
+ if (liveActivity) {
12191
+ beforeSnap.set(missingId, structuredCloneActivity(liveActivity));
12192
+ }
12695
12193
  }
12696
12194
  }
12697
12195
 
@@ -13115,8 +12613,8 @@ function activeBaselineSignature(deps) {
13115
12613
  })
13116
12614
  );
13117
12615
  }
13118
- function dispatchBaselineApply(action, deps) {
13119
- const beforeSnap = snapshotActivities(
12616
+ async function dispatchBaselineApply(action, deps) {
12617
+ const beforeSnap = await snapshotActivities(
13120
12618
  deps.adapter,
13121
12619
  new Set(deps.adapter.getAllIds())
13122
12620
  );
@@ -13136,7 +12634,7 @@ function dispatchBaselineApply(action, deps) {
13136
12634
  }
13137
12635
  return {
13138
12636
  ok: true,
13139
- changes: assembleChangeSet(deps.adapter, {
12637
+ changes: await assembleChangeSet(deps.adapter, {
13140
12638
  source: action,
13141
12639
  beforeSnap,
13142
12640
  touchedIds: changedIds,
@@ -13153,15 +12651,15 @@ function assertValidCriterion(value) {
13153
12651
  `ponderator-criterion-set: invalid criterion "${String(value)}"`
13154
12652
  );
13155
12653
  }
13156
- function dispatchPonderatorCriterionSet(action, deps) {
12654
+ async function dispatchPonderatorCriterionSet(action, deps) {
13157
12655
  assertValidCriterion(action.criterion);
13158
12656
  const allIds = new Set(deps.adapter.getAllIds());
13159
- const beforeSnap = snapshotActivities(deps.adapter, allIds);
12657
+ const beforeSnap = await snapshotActivities(deps.adapter, allIds);
13160
12658
  recomputeBaselineWeightedFields(deps, action.criterion);
13161
12659
  deps.sector.activityCreter = action.criterion;
13162
12660
  return {
13163
12661
  ok: true,
13164
- changes: assembleChangeSet(deps.adapter, {
12662
+ changes: await assembleChangeSet(deps.adapter, {
13165
12663
  source: action,
13166
12664
  beforeSnap,
13167
12665
  touchedIds: allIds,
@@ -13172,15 +12670,15 @@ function dispatchPonderatorCriterionSet(action, deps) {
13172
12670
  }
13173
12671
 
13174
12672
  // src/dispatch/handlers/status-criteria-set.ts
13175
- function dispatchStatusCriteriaSet(action, deps) {
12673
+ async function dispatchStatusCriteriaSet(action, deps) {
13176
12674
  const resolved = resolveStatusCriteria(action.criteria);
13177
12675
  const allIds = new Set(deps.adapter.getAllIds());
13178
- const beforeSnap = snapshotActivities(deps.adapter, allIds);
12676
+ const beforeSnap = await snapshotActivities(deps.adapter, allIds);
13179
12677
  const changedIds = applyStatusPass(deps.adapter, resolved);
13180
12678
  deps.sector.statusCriteria = resolved;
13181
12679
  return {
13182
12680
  ok: true,
13183
- changes: assembleChangeSet(deps.adapter, {
12681
+ changes: await assembleChangeSet(deps.adapter, {
13184
12682
  source: action,
13185
12683
  beforeSnap,
13186
12684
  touchedIds: changedIds,
@@ -13246,6 +12744,12 @@ async function dispatch(action, options, deps) {
13246
12744
  if (action.kind === "visibility-set") {
13247
12745
  return dispatchVisibilitySet(action, selectionDeps(deps));
13248
12746
  }
12747
+ if (action.kind === "filter-set") {
12748
+ return dispatchFilterSet(action, {
12749
+ adapter: deps.adapter,
12750
+ hoursPerDay: deps.sector.hoursPerDay
12751
+ });
12752
+ }
13249
12753
  if (action.kind === "sir-sync") {
13250
12754
  return dispatchSirSync(action, deps);
13251
12755
  }
@@ -15768,9 +15272,7 @@ var defaultLocale = {
15768
15272
  function createGanttShim(options = {}) {
15769
15273
  const userConfig = options.config || {};
15770
15274
  const shim = {
15771
- // ------ Config ------
15772
15275
  config: Object.assign({
15773
- // Defaults críticos para calendar
15774
15276
  duration_unit: "hour",
15775
15277
  duration_step: 1,
15776
15278
  work_time: false,
@@ -15781,16 +15283,13 @@ function createGanttShim(options = {}) {
15781
15283
  resource_property: "resource_id",
15782
15284
  resource_calendars: {},
15783
15285
  dynamic_resource_calendars: false,
15784
- // Config date module
15785
15286
  start_on_monday: true,
15786
15287
  server_utc: true,
15787
15288
  csp: "auto",
15788
15289
  show_errors: false
15789
15290
  }, userConfig),
15790
- // ------ Locale + templates ------
15791
15291
  locale: options.locale || defaultLocale,
15792
15292
  templates: options.templates || {},
15793
- // ------ Task resolver (opcional) ------
15794
15293
  getTask: options.getTask || function(id) {
15795
15294
  return null;
15796
15295
  },
@@ -15800,11 +15299,9 @@ function createGanttShim(options = {}) {
15800
15299
  isSummaryTask: options.isSummaryTask || function(task) {
15801
15300
  return false;
15802
15301
  },
15803
- // ------ State (mínimo) ------
15804
15302
  getState: function() {
15805
15303
  return { group_mode: false };
15806
15304
  },
15807
- // ------ Eventable (no-ops por defecto) ------
15808
15305
  callEvent: function(name, args) {
15809
15306
  const handler = options.onEvent;
15810
15307
  if (handler) handler(name, args);
@@ -15818,7 +15315,6 @@ function createGanttShim(options = {}) {
15818
15315
  },
15819
15316
  detachEvent: function() {
15820
15317
  },
15821
- // ------ Utils expuestas en gantt2 ------
15822
15318
  defined,
15823
15319
  mixin,
15824
15320
  copy,
@@ -15828,7 +15324,6 @@ function createGanttShim(options = {}) {
15828
15324
  else if (options.silent !== true) console.error("[calendar]", msg);
15829
15325
  }
15830
15326
  },
15831
- // ------ $services / $ui — stubs minimales para evitar cracks ------
15832
15327
  $services: { getService: function() {
15833
15328
  return null;
15834
15329
  } },
@@ -15849,7 +15344,6 @@ function createGanttShim(options = {}) {
15849
15344
  function createCalendar(options = {}) {
15850
15345
  const shim = createGanttShim(options);
15851
15346
  return {
15852
- // ------ Gestión de calendarios ------
15853
15347
  addCalendar: function(c) {
15854
15348
  return shim.addCalendar(c);
15855
15349
  },
@@ -15871,7 +15365,6 @@ function createCalendar(options = {}) {
15871
15365
  getResourceCalendar: function(r) {
15872
15366
  return shim.getResourceCalendar(r);
15873
15367
  },
15874
- // ------ Cálculo (también disponible en cada Calendar instance) ------
15875
15368
  setWorkTime: function(c) {
15876
15369
  return shim.setWorkTime(c);
15877
15370
  },
@@ -15893,7 +15386,6 @@ function createCalendar(options = {}) {
15893
15386
  calculateEndDate: function() {
15894
15387
  return shim.calculateEndDate.apply(shim, arguments);
15895
15388
  },
15896
- // ------ Para inspección/debug ------
15897
15389
  _internals: shim
15898
15390
  };
15899
15391
  }
@@ -15921,16 +15413,11 @@ function normalizeWorktimeHours(hours) {
15921
15413
  return [`${first}:00-${last + 1}:00`];
15922
15414
  }
15923
15415
  var DEFAULT_WORKTIME = {
15924
- // 08:00..16:00 UTC, Mon..Fri. Matches the prior generic fallback used by
15925
- // synthetic fixtures and CPM nodes whose calendar id is genuinely unknown.
15926
15416
  hours: ["8:00-16:00"],
15927
15417
  days: [false, true, true, true, true, true, false]
15928
15418
  };
15929
15419
  var CATALOG_ONLY_CALENDAR_ID = "__main_global__";
15930
15420
  var CATALOG_ONLY_WORKTIME = {
15931
- // Native MAIN/DHTMLX global calendar. A calendar present in the selector but
15932
- // lacking usable shifts is not registered by MAIN, so its date arithmetic
15933
- // falls through to this split-day global calendar.
15934
15421
  hours: ["8:00-12:00", "13:00-17:00"],
15935
15422
  days: [false, true, true, true, true, true, false]
15936
15423
  };
@@ -16122,7 +15609,6 @@ var WriteCapture = class {
16122
15609
  end() {
16123
15610
  this._journal = null;
16124
15611
  }
16125
- /** Field write on an activity — pre-mutation clone on first write per id. */
16126
15612
  note(key, current) {
16127
15613
  const journal = this._journal;
16128
15614
  if (!journal) return;
@@ -16150,13 +15636,11 @@ var WriteCapture = class {
16150
15636
  before: cloneLink(current)
16151
15637
  });
16152
15638
  }
16153
- /** Pre-sweep correlative_id of an activity the renumbering shifted (first-wins). */
16154
15639
  noteCorrelativeBefore(activityId, before) {
16155
15640
  const journal = this._journal;
16156
15641
  if (!journal || journal.correlativeBefore.has(activityId)) return;
16157
15642
  journal.correlativeBefore.set(activityId, before);
16158
15643
  }
16159
- /** Pre-applyResults clone of an activity the autoscheduler will move (first-wins). */
16160
15644
  noteScheduledBefore(activityId, current) {
16161
15645
  const journal = this._journal;
16162
15646
  if (!journal) return;
@@ -16169,7 +15653,6 @@ var WriteCapture = class {
16169
15653
  }
16170
15654
  journal.dirty.add(activityId);
16171
15655
  }
16172
- /** Field write on a link — pre-mutation clone on first write per link id. */
16173
15656
  noteLinkField(linkId, current) {
16174
15657
  const journal = this._journal;
16175
15658
  if (!journal || journal.linkFieldCaptured.has(linkId)) return;
@@ -16187,17 +15670,11 @@ function cloneLink(link) {
16187
15670
 
16188
15671
  // src/internal/state/calendar-calculator.ts
16189
15672
  var CalendarCalculator = class {
16190
- // In-dispatch calendar API memoization. Lifetime = one scheduler run.
16191
15673
  _cache = {
16192
15674
  closestWorkTime: /* @__PURE__ */ new Map(),
16193
15675
  endDate: /* @__PURE__ */ new Map(),
16194
15676
  duration: /* @__PURE__ */ new Map()
16195
15677
  };
16196
- // Single owner of the calendar subsystem. The calc resolves calendars (incl.
16197
- // the `-base` ones and the default fallback) through the reader — one resolver
16198
- // for the whole calendar surface instead of a separate Map + default field.
16199
- /** Resolver for ANY calendar incl. the `-base` ones — also consumed by the
16200
- * column pipelines via `pipeline-context`. */
16201
15678
  reader;
16202
15679
  constructor(setup) {
16203
15680
  this.reader = setup.reader;
@@ -16240,11 +15717,6 @@ var CalendarCalculator = class {
16240
15717
  )
16241
15718
  );
16242
15719
  }
16243
- /**
16244
- * Clears the in-dispatch calendar API memoization. Call at the start of
16245
- * every scheduler run (calendars are immutable within a dispatch but may
16246
- * change across dispatches).
16247
- */
16248
15720
  clearCache() {
16249
15721
  this._cache.closestWorkTime.clear();
16250
15722
  this._cache.endDate.clear();
@@ -16277,16 +15749,7 @@ var HierarchyIndex = class {
16277
15749
  activities;
16278
15750
  _childrenByParent = /* @__PURE__ */ new Map();
16279
15751
  _roots = [];
16280
- /**
16281
- * When true, `_childrenByParent` is stale (a `parent` write happened) and is
16282
- * lazily rebuilt on the next `getChildren`. A bulk reparent (K rows) marks
16283
- * dirty K times but pays ONE rebuild on the next read instead of K — turning
16284
- * bulk indent/outdent from O(K·N) into O(K+N). Only `getChildren` reads this
16285
- * index; `getParent`/`getParentId`/`isChildOf` read `activities` directly and
16286
- * are always fresh, so they don't consult the flag. See PERFORMANCE.md §A3.
16287
- */
16288
15752
  _dirty = false;
16289
- /** Mark the children index stale; the next `getChildren` rebuilds it once. */
16290
15753
  markDirty() {
16291
15754
  this._dirty = true;
16292
15755
  }
@@ -16330,11 +15793,6 @@ var HierarchyIndex = class {
16330
15793
  getParentId(id) {
16331
15794
  return this.activities.get(id)?.parentId ?? null;
16332
15795
  }
16333
- /**
16334
- * Incremental O(1) insert for a freshly added activity (create/paste).
16335
- * The id is new, so no rebuild is needed — reparenting goes through
16336
- * `rebuild()` instead.
16337
- */
16338
15796
  addChild(parentId, id) {
16339
15797
  if (this._dirty) return;
16340
15798
  if (isRootParent(parentId)) {
@@ -16346,7 +15804,6 @@ var HierarchyIndex = class {
16346
15804
  if (arr) arr.push(id);
16347
15805
  else this._childrenByParent.set(key, [id]);
16348
15806
  }
16349
- /** Full rebuild from the activity store. */
16350
15807
  rebuild() {
16351
15808
  this._childrenByParent.clear();
16352
15809
  this._roots = [];
@@ -16379,12 +15836,22 @@ var HierarchyIndex = class {
16379
15836
  var ViewStateStore = class {
16380
15837
  checkedSet = /* @__PURE__ */ new Set();
16381
15838
  hiddenSet = /* @__PURE__ */ new Set();
15839
+ activeFilter = null;
16382
15840
  isChecked(activityId) {
16383
15841
  return this.checkedSet.has(activityId);
16384
15842
  }
16385
15843
  isVisible(activityId) {
16386
15844
  return !this.hiddenSet.has(activityId);
16387
15845
  }
15846
+ hiddenIds() {
15847
+ return [...this.hiddenSet];
15848
+ }
15849
+ getActiveFilter() {
15850
+ return this.activeFilter;
15851
+ }
15852
+ setActiveFilter(nextFilter) {
15853
+ this.activeFilter = nextFilter;
15854
+ }
16388
15855
  checkedIds() {
16389
15856
  return [...this.checkedSet];
16390
15857
  }
@@ -16410,55 +15877,40 @@ var ViewStateStore = class {
16410
15877
  hydrate(seed2) {
16411
15878
  this.checkedSet = new Set(seed2.checkedIds ?? []);
16412
15879
  this.hiddenSet = new Set(seed2.hiddenIds ?? []);
15880
+ this.activeFilter = null;
16413
15881
  }
16414
15882
  snapshot() {
16415
15883
  return {
16416
15884
  checked: new Set(this.checkedSet),
16417
- hidden: new Set(this.hiddenSet)
15885
+ hidden: new Set(this.hiddenSet),
15886
+ activeFilter: this.activeFilter
16418
15887
  };
16419
15888
  }
16420
15889
  restore(snapshot) {
16421
15890
  this.checkedSet = new Set(snapshot.checked);
16422
15891
  this.hiddenSet = new Set(snapshot.hidden);
15892
+ this.activeFilter = snapshot.activeFilter;
16423
15893
  }
16424
15894
  };
16425
15895
 
16426
15896
  // src/internal/state/schedule-state.ts
16427
15897
  var ScheduleState = class {
16428
- // Private so every mutation routes through setActivityField/addActivity/…
16429
- // (the only path that feeds the write-capture → ChangeSet). External readers
16430
- // use the AutoSchedulerPort read methods (getActivity / getAllActivities / …).
16431
15898
  _activities = /* @__PURE__ */ new Map();
16432
- // Transient gesture state: the start_date an activity had at its last
16433
- // duration edit / drag. Read only by the no-op constraint revert to decide
16434
- // whether a soft constraint repositioned the activity. Never persisted,
16435
- // never in the ChangeSet — not domain data on CoreActivity.
16436
15899
  _lastStartDate = /* @__PURE__ */ new Map();
16437
- // Transient gesture state: what a leaf looked like right before it gained its
16438
- // first child and became a summary. Read by the demotion to give the activity
16439
- // its own values back instead of the aggregate its children left behind. Not
16440
- // persisted and not in the ChangeSet: it only makes sense inside the session
16441
- // that performed the promotion. Kept (not consumed) so undo/redo of a
16442
- // demotion restores identically every time.
16443
15900
  _promotionSnapshot = /* @__PURE__ */ new Map();
16444
15901
  _links = /* @__PURE__ */ new Map();
16445
15902
  _outgoing = /* @__PURE__ */ new Map();
16446
15903
  _incoming = /* @__PURE__ */ new Map();
16447
- // Parent → children index. Assigned in the constructor (needs the
16448
- // activities Map reference). See `HierarchyIndex`.
16449
15904
  _hierarchy;
16450
15905
  _cache = {
16451
15906
  ids: null,
16452
15907
  visualOrderIds: null
16453
15908
  };
16454
- // Per-dispatch write journal. See `WriteCapture` / `ActivityWriteCapture`.
16455
15909
  _writeCapture = new WriteCapture();
16456
15910
  _viewState = new ViewStateStore();
16457
15911
  _viewStateBefore = null;
16458
15912
  _lastStartDateBefore = null;
16459
15913
  _promotionSnapshotBefore = null;
16460
- // Calendar arithmetic + in-dispatch memoization. Assigned in the
16461
- // constructor once the calendar reader is built. See `CalendarCalculator`.
16462
15914
  _calendar;
16463
15915
  _flags;
16464
15916
  constructor(snapshot) {
@@ -16476,22 +15928,12 @@ var ScheduleState = class {
16476
15928
  this._hierarchy = new HierarchyIndex(this._activities);
16477
15929
  this._hierarchy.rebuild();
16478
15930
  }
16479
- // -- AutoSchedulerPort: reads ------------------------------------------------
16480
- /**
16481
- * Materializes every alive activity. O(N) allocation.
16482
- * AVOID per-frame / per-dispatch consumers — prefer `forEachActivity` /
16483
- * `getAllIds` when only ids or fast field reads are needed.
16484
- */
16485
15931
  getAllActivities() {
16486
15932
  return Array.from(this._activities.values());
16487
15933
  }
16488
15934
  getAllLinks() {
16489
15935
  return Array.from(this._links.values());
16490
15936
  }
16491
- /**
16492
- * Read-only snapshot of every alive activity id. Cached and invalidated
16493
- * lazily on structural mutations (add/remove/parent change).
16494
- */
16495
15937
  getAllIds() {
16496
15938
  if (this._cache.ids) return this._cache.ids;
16497
15939
  this._cache.ids = Array.from(this._activities.keys());
@@ -16500,14 +15942,6 @@ var ScheduleState = class {
16500
15942
  activityCount() {
16501
15943
  return this._activities.size;
16502
15944
  }
16503
- /**
16504
- * Every alive activity id in canonical DFS visual order (pre-order from
16505
- * roots, siblings by `correlative_id` ASC — `iterateInVisualOrder`).
16506
- * Cached like `getAllIds`; invalidated on add/remove, on `parent` /
16507
- * `correlative_id` writes, and by `recomputeCorrelativeIds` (the only
16508
- * order chokepoint, which mutates `correlative_id` directly on the
16509
- * snapshots without going through `setActivityField`).
16510
- */
16511
15945
  getVisualOrderIds() {
16512
15946
  if (this._cache.visualOrderIds) return this._cache.visualOrderIds;
16513
15947
  this._cache.visualOrderIds = iterateInVisualOrder(this).map(
@@ -16515,14 +15949,9 @@ var ScheduleState = class {
16515
15949
  );
16516
15950
  return this._cache.visualOrderIds;
16517
15951
  }
16518
- /** Drops the memoized visual order. See `getVisualOrderIds`. */
16519
15952
  invalidateVisualOrderIds() {
16520
15953
  this._cache.visualOrderIds = null;
16521
15954
  }
16522
- /**
16523
- * Iterates every alive activity without materializing intermediate arrays.
16524
- * Use in hot paths that today call `getAllActivities()` only to walk it.
16525
- */
16526
15955
  forEachActivity(visit) {
16527
15956
  for (const [id, activity] of this._activities) {
16528
15957
  visit(activity, id);
@@ -16575,6 +16004,9 @@ var ScheduleState = class {
16575
16004
  checkedIds() {
16576
16005
  return this._viewState.checkedIds();
16577
16006
  }
16007
+ hiddenIds() {
16008
+ return this._viewState.hiddenIds();
16009
+ }
16578
16010
  setChecked(activityId, nextChecked) {
16579
16011
  this._captureViewStateOnce();
16580
16012
  return this._viewState.setChecked(String(activityId), nextChecked);
@@ -16583,6 +16015,13 @@ var ScheduleState = class {
16583
16015
  this._captureViewStateOnce();
16584
16016
  return this._viewState.setVisible(String(activityId), nextVisible);
16585
16017
  }
16018
+ getActiveFilter() {
16019
+ return this._viewState.getActiveFilter();
16020
+ }
16021
+ setActiveFilter(nextFilter) {
16022
+ this._captureViewStateOnce();
16023
+ this._viewState.setActiveFilter(nextFilter);
16024
+ }
16586
16025
  hydrateViewState(seed2) {
16587
16026
  this._viewState.hydrate(seed2);
16588
16027
  }
@@ -16598,7 +16037,6 @@ var ScheduleState = class {
16598
16037
  getIncomingLinkIds(activityId) {
16599
16038
  return this._incoming.get(String(activityId)) ?? EMPTY_LINK_IDS;
16600
16039
  }
16601
- // -- AutoSchedulerPort: hierarchy --------------------------------------------
16602
16040
  getChildren(parentId) {
16603
16041
  return this._hierarchy.getChildren(parentId);
16604
16042
  }
@@ -16614,7 +16052,6 @@ var ScheduleState = class {
16614
16052
  getRootIds() {
16615
16053
  return this._hierarchy.getRootIds();
16616
16054
  }
16617
- // -- AutoSchedulerPort: calendar (snapshot-aware, M-F 08-16 UTC fallback) ---
16618
16055
  getClosestWorkTime(params) {
16619
16056
  return this._calendar.getClosestWorkTime(params);
16620
16057
  }
@@ -16624,66 +16061,44 @@ var ScheduleState = class {
16624
16061
  calculateDuration(params) {
16625
16062
  return this._calendar.calculateDuration(params);
16626
16063
  }
16627
- /**
16628
- * Clears the in-dispatch calendar API memoization. Call at the start of
16629
- * every scheduler run (calendars are immutable within a dispatch but may
16630
- * change across dispatches).
16631
- */
16632
16064
  clearCalendarCache() {
16633
16065
  this._calendar.clearCache();
16634
16066
  }
16635
- // Calendar resolver exposed for external consumers (initial-passes'
16636
- // expected_progress, adjust-link-lag, pipeline-context). The single owner is
16637
- // `_calendar`; this getter just delegates.
16638
16067
  get calendarReader() {
16639
16068
  return this._calendar.reader;
16640
16069
  }
16641
- // -- AutoSchedulerPort: mutations --------------------------------------------
16642
16070
  batchUpdate(runMutations) {
16643
16071
  runMutations();
16644
16072
  }
16645
- /**
16646
- * Part of the `AutoSchedulerPort` port (live caller: `applyResults`). No-op
16647
- * here because activities mutate in place via `getLiveActivity`; only a
16648
- * DHTMLX-backed adapter needs this to trigger a re-render.
16649
- */
16650
16073
  updateActivity(_id) {
16651
16074
  }
16652
16075
  getLiveActivity(activityId) {
16653
16076
  return this.getActivity(activityId);
16654
16077
  }
16655
- // -- AutoSchedulerPort: flags / config ---------------------------------------
16656
16078
  getFlags() {
16657
16079
  return {
16658
16080
  ...this._flags,
16659
16081
  allCheckedTaskIds: this._viewState.checkedIds()
16660
16082
  };
16661
16083
  }
16662
- // Backend ships no project-level dates, so this is always null in
16663
- // production. The ALAP root-boundary branch that reads it stays dormant.
16664
16084
  getProjectEnd() {
16665
16085
  return null;
16666
16086
  }
16667
- // -- Write capture (per-dispatch journal) --------------------------------
16668
- /** Start recording every `setActivityField` write of the current dispatch. */
16669
16087
  beginWriteCapture() {
16670
16088
  this._writeCapture.begin();
16671
16089
  this._viewStateBefore = null;
16672
16090
  this._lastStartDateBefore = null;
16673
16091
  this._promotionSnapshotBefore = null;
16674
16092
  }
16675
- /** The live journal, or null when no capture is active. */
16676
16093
  peekWriteCapture() {
16677
16094
  return this._writeCapture.peek();
16678
16095
  }
16679
- /** Stop and discard the current dispatch's write journal. */
16680
16096
  endWriteCapture() {
16681
16097
  this._writeCapture.end();
16682
16098
  this._viewStateBefore = null;
16683
16099
  this._lastStartDateBefore = null;
16684
16100
  this._promotionSnapshotBefore = null;
16685
16101
  }
16686
- // -- Replay-specific mutators --------------------------------------------
16687
16102
  setActivityField(activityId, field, value) {
16688
16103
  const activity = this.getActivity(activityId);
16689
16104
  if (!activity) return;
@@ -16749,11 +16164,6 @@ var ScheduleState = class {
16749
16164
  this._writeCapture.noteLinkField(String(linkId), link);
16750
16165
  Reflect.set(link, field, value);
16751
16166
  }
16752
- /**
16753
- * Applies the backend identity returned after a successful persistence
16754
- * request. `proplannerId` is deliberately not a regular editable link field:
16755
- * it is boundary-owned identity and must never enter link-update/undo logic.
16756
- */
16757
16167
  setLinkProplannerId(linkId, proplannerId) {
16758
16168
  const link = this.getLink(linkId);
16759
16169
  if (!link) return;
@@ -16793,28 +16203,9 @@ var ScheduleState = class {
16793
16203
  this._cache.visualOrderIds = null;
16794
16204
  this._hierarchy.markDirty();
16795
16205
  }
16796
- /**
16797
- * Transactional rollback: invert every journaled mutation so the store returns
16798
- * to its pre-dispatch state. Consumed by the facade on a failed dispatch,
16799
- * BEFORE `endWriteCapture` discards the journal. Reverse-chronological replay,
16800
- * bucketed in the dependency order the red-team fixed (endpoints before links,
16801
- * re-inserts before re-adds). All writes are DIRECT (never through the
16802
- * journaling mutators) so the rollback does not re-journal itself. O(touched).
16803
- *
16804
- * NOTE: covers everything routed through setActivityField + the structural
16805
- * mutators (the whole handler phase). The autoscheduler's `applyResults` date
16806
- * writes bypass the journal and are not yet reverted here (transaction plan
16807
- * Stage 4) — a create that throws AFTER autoschedule leaves those dates, which
16808
- * is still strictly less corrupt than today's no-rollback.
16809
- */
16810
- /** Pre-sweep correlative_id of an activity the renumbering shifted. Journaled
16811
- * separately (the sweep bypasses setActivityField) so rollback can revert it. */
16812
16206
  noteCorrelativeBefore(activityId, before) {
16813
16207
  this._writeCapture.noteCorrelativeBefore(activityId, before);
16814
16208
  }
16815
- /** Pre-applyResults clone of an activity the autoscheduler will move. Journaled
16816
- * separately (applyResults bypasses setActivityField) so rollback can revert
16817
- * the scheduler's date writes. */
16818
16209
  noteScheduledBefore(activityId, current) {
16819
16210
  this._writeCapture.noteScheduledBefore(activityId, current);
16820
16211
  }
@@ -16924,11 +16315,6 @@ function buildFlags(snapshot) {
16924
16315
  };
16925
16316
  }
16926
16317
 
16927
- // src/shared/clone-domain-value.ts
16928
- function cloneDomainValue(value) {
16929
- return structuredClone(value);
16930
- }
16931
-
16932
16318
  // src/init/read-api.ts
16933
16319
  function readActivity(state, id) {
16934
16320
  const activity = state.getActivity(id);
@@ -17020,9 +16406,6 @@ function computeProjectWorkHours(calendars) {
17020
16406
  // src/internal/state/pipeline-context.ts
17021
16407
  function buildPipelineContext(adapter, options) {
17022
16408
  return {
17023
- // Same work-calendar engine instance used by the mock adapter so both
17024
- // halves of the replay (auto-scheduler + column pipelines) agree on
17025
- // working-time math.
17026
16409
  calendars: adapter.calendarReader,
17027
16410
  hierarchy: createStateBackedHierarchyReader(adapter),
17028
16411
  activityReader: createStateBackedActivityReader(adapter),
@@ -17039,6 +16422,21 @@ function willRunCriticalPath(action) {
17039
16422
  }
17040
16423
 
17041
16424
  // src/dispatch/undo/undo-entry.ts
16425
+ function buildHistoryChangeSet(changes) {
16426
+ const activitiesWithoutAfter = changes.activities.map((entry) => ({
16427
+ ...entry,
16428
+ after: null
16429
+ }));
16430
+ const linksWithoutAfter = changes.links.map((entry) => ({
16431
+ ...entry,
16432
+ after: null
16433
+ }));
16434
+ return cloneDomainValue({
16435
+ ...changes,
16436
+ activities: activitiesWithoutAfter,
16437
+ links: linksWithoutAfter
16438
+ });
16439
+ }
17042
16440
  function buildUndoEntry(changeSet, beforeSnap, beforeLinks, afterSnap, afterLinks) {
17043
16441
  return { changeSet, beforeSnap, beforeLinks, afterSnap, afterLinks };
17044
16442
  }
@@ -17094,7 +16492,7 @@ function mergeCoalesced(top, next) {
17094
16492
  }
17095
16493
  function getDispatchHistoryPolicy(action) {
17096
16494
  if (action.kind === "persistence-acknowledge") return "clear-on-success";
17097
- if (action.kind === "sir-sync" || action.kind === "activity-lookahead-sync" || action.kind === "baseline-apply" || action.kind === "ponderator-criterion-set" || action.kind === "status-criteria-set") {
16495
+ if (action.kind === "sir-sync" || action.kind === "activity-lookahead-sync" || action.kind === "baseline-apply" || action.kind === "ponderator-criterion-set" || action.kind === "status-criteria-set" || action.kind === "selection-toggle" || action.kind === "selection-replace" || action.kind === "visibility-set" || action.kind === "filter-set") {
17098
16496
  return "skip";
17099
16497
  }
17100
16498
  return "record";
@@ -17336,24 +16734,20 @@ var UndoRecorder = class {
17336
16734
  redoStack = [];
17337
16735
  _lastKey = null;
17338
16736
  _lastTime = 0;
17339
- /**
17340
- * Push a forward entry; a new action invalidates the redo branch. When the
17341
- * entry coalesces with the top one (same cell key, within the time window),
17342
- * it merges into the top step instead of pushing a new one (decision #4).
17343
- */
17344
16737
  record(entry, coalesceKey = null, now = 0) {
17345
16738
  const top = this.undoStack[this.undoStack.length - 1];
17346
16739
  if (coalesceKey != null && coalesceKey === this._lastKey && now - this._lastTime <= COALESCE_WINDOW_MS && top !== void 0 && canCoalesce(top, entry)) {
17347
16740
  this.undoStack[this.undoStack.length - 1] = mergeCoalesced(top, entry);
17348
16741
  } else {
17349
16742
  this.undoStack.push(entry);
17350
- if (this.undoStack.length > this.maxDepth) this.undoStack.shift();
16743
+ if (this.undoStack.length > this.maxDepth) {
16744
+ this.undoStack.splice(0, this.undoStack.length - this.maxDepth);
16745
+ }
17351
16746
  }
17352
16747
  this._lastKey = coalesceKey;
17353
16748
  this._lastTime = now;
17354
16749
  this.redoStack.length = 0;
17355
16750
  }
17356
- /** Break the coalescing chain (called on undo/redo). */
17357
16751
  resetCoalesce() {
17358
16752
  this._lastKey = null;
17359
16753
  }
@@ -17388,10 +16782,6 @@ var UndoRecorder = class {
17388
16782
  // src/init/build-state-snapshot.ts
17389
16783
  function buildStoreLink(link) {
17390
16784
  return {
17391
- // Spread first to preserve passthrough backend fields (proplannerId,
17392
- // ganttId, sectorId) through the snapshot — dropping proplannerId here was
17393
- // a bug: the core lost each link's backend id, so save dirty-detection and
17394
- // the DHTMLX adapter could not tell persisted links from new ones.
17395
16785
  ...link,
17396
16786
  id: String(link.id),
17397
16787
  source: String(link.source),
@@ -17404,11 +16794,6 @@ function serializeWorktime(worktime) {
17404
16794
  return {
17405
16795
  days: worktime.days,
17406
16796
  hours: worktime.hours,
17407
- // Preserve per-date overrides (holidays + workday shift exceptions)
17408
- // through the snapshot so the work-calendar engine sees them when
17409
- // the state hydrates. Dropping these here was the bug that made
17410
- // multi-shift / exception-day calendars snap to wrong hours after
17411
- // every edit.
17412
16797
  ...worktime.dates ? { dates: worktime.dates } : {},
17413
16798
  ...worktime.customWeeks ? { customWeeks: worktime.customWeeks } : {}
17414
16799
  };
@@ -17525,13 +16910,11 @@ var SaveTracker = class {
17525
16910
  initialized = false;
17526
16911
  linksAtLastSave = /* @__PURE__ */ new Map();
17527
16912
  activitiesAtLastSave = /* @__PURE__ */ new Map();
17528
- /** Take the initial snapshot once (after the autoscheduler settles). */
17529
16913
  init(activities, links) {
17530
16914
  this.snapshotActivities(activities);
17531
16915
  this.snapshotLinks(links);
17532
16916
  this.initialized = true;
17533
16917
  }
17534
- /** Re-snapshot activities (call after a save persists them). */
17535
16918
  snapshotActivities(activities) {
17536
16919
  this.activitiesAtLastSave.clear();
17537
16920
  for (const activity of activities) {
@@ -17542,7 +16925,6 @@ var SaveTracker = class {
17542
16925
  );
17543
16926
  }
17544
16927
  }
17545
- /** Re-snapshot links (call after a save persists them). */
17546
16928
  snapshotLinks(links) {
17547
16929
  this.linksAtLastSave.clear();
17548
16930
  for (const link of links) {
@@ -17553,7 +16935,6 @@ var SaveTracker = class {
17553
16935
  });
17554
16936
  }
17555
16937
  }
17556
- /** Persisted activities whose value changed since the last snapshot. */
17557
16938
  modifiedActivities(activities) {
17558
16939
  if (!this.initialized) return [];
17559
16940
  return activities.filter((activity) => {
@@ -17564,7 +16945,6 @@ var SaveTracker = class {
17564
16945
  return activityChangedSince(activity, saved);
17565
16946
  });
17566
16947
  }
17567
- /** Persisted links whose `lag`/`type` changed since the last snapshot. */
17568
16948
  modifiedLinks(links) {
17569
16949
  if (!this.initialized) return [];
17570
16950
  return links.filter((link) => {
@@ -17574,7 +16954,6 @@ var SaveTracker = class {
17574
16954
  return link.lag !== saved.lag || link.type !== saved.type;
17575
16955
  });
17576
16956
  }
17577
- /** Drop both mirrors (teardown). */
17578
16957
  clear() {
17579
16958
  this.linksAtLastSave.clear();
17580
16959
  this.activitiesAtLastSave.clear();
@@ -18344,35 +17723,58 @@ function cloneStats(stats) {
18344
17723
  var CustomIdTracker = class {
18345
17724
  prefixMap = /* @__PURE__ */ new Map();
18346
17725
  processedIds = /* @__PURE__ */ new Set();
18347
- _journal = null;
17726
+ _journalPrefixBefore = null;
17727
+ _journalIds = null;
18348
17728
  beginCustomIdTransaction() {
18349
- this._journal = [];
17729
+ this._journalPrefixBefore = /* @__PURE__ */ new Map();
17730
+ this._journalIds = [];
18350
17731
  }
18351
17732
  commitCustomIdTransaction() {
18352
- this._journal = null;
17733
+ this._journalPrefixBefore = null;
17734
+ this._journalIds = null;
18353
17735
  }
18354
17736
  rollbackCustomIdTransaction() {
18355
- const journal = this._journal;
18356
- if (journal === null) return;
18357
- for (const entry of [...journal].reverse()) {
18358
- const { prefix } = this.analyzeCustomId(entry.customId);
18359
- if (entry.prefixBefore === null) this.prefixMap.delete(prefix);
18360
- else this.prefixMap.set(prefix, entry.prefixBefore);
17737
+ const prefixBeforeByPrefix = this._journalPrefixBefore;
17738
+ const journaledIds = this._journalIds;
17739
+ if (prefixBeforeByPrefix === null || journaledIds === null) return;
17740
+ for (const [prefix, statsBefore] of prefixBeforeByPrefix) {
17741
+ if (statsBefore === null) this.prefixMap.delete(prefix);
17742
+ else this.prefixMap.set(prefix, statsBefore);
17743
+ }
17744
+ for (const entry of [...journaledIds].reverse()) {
18361
17745
  if (entry.hadId) this.processedIds.add(entry.customId);
18362
17746
  else this.processedIds.delete(entry.customId);
18363
17747
  }
18364
- this._journal = null;
17748
+ this._journalPrefixBefore = null;
17749
+ this._journalIds = null;
18365
17750
  }
18366
17751
  _noteCustomIdBefore(customId) {
18367
- if (this._journal === null) return;
17752
+ if (this._journalPrefixBefore === null || this._journalIds === null) {
17753
+ return;
17754
+ }
18368
17755
  const { prefix } = this.analyzeCustomId(customId);
18369
- const current = this.prefixMap.get(prefix);
18370
- this._journal.push({
17756
+ if (!this._journalPrefixBefore.has(prefix)) {
17757
+ const current = this.prefixMap.get(prefix);
17758
+ this._journalPrefixBefore.set(
17759
+ prefix,
17760
+ current ? cloneStats(current) : null
17761
+ );
17762
+ }
17763
+ this._journalIds.push({
18371
17764
  customId,
18372
- prefixBefore: current ? cloneStats(current) : null,
18373
17765
  hadId: this.processedIds.has(customId)
18374
17766
  });
18375
17767
  }
17768
+ _ensureFreshBounds(prefix) {
17769
+ const stats = this.prefixMap.get(prefix);
17770
+ if (!stats?.boundsDirty) return;
17771
+ stats.boundsDirty = false;
17772
+ const remaining = Array.from(stats.usedSuffixes);
17773
+ stats.min = minSuffixFromArray(remaining);
17774
+ stats.max = maxSuffixFromArray(remaining);
17775
+ stats.quantity = remaining.length;
17776
+ this._recalculateNext(prefix);
17777
+ }
18376
17778
  defaultPrefix;
18377
17779
  suffixIncrement;
18378
17780
  constructor(options = {}) {
@@ -18392,6 +17794,7 @@ var CustomIdTracker = class {
18392
17794
  };
18393
17795
  }
18394
17796
  _updatePrefixStats(prefix, suffix) {
17797
+ this._ensureFreshBounds(prefix);
18395
17798
  if (!this.prefixMap.has(prefix)) {
18396
17799
  this.prefixMap.set(prefix, {
18397
17800
  min: suffix,
@@ -18418,6 +17821,7 @@ var CustomIdTracker = class {
18418
17821
  stats.next = next ?? this.suffixIncrement;
18419
17822
  }
18420
17823
  getPrefixStats(prefix) {
17824
+ this._ensureFreshBounds(prefix);
18421
17825
  const stats = this.prefixMap.get(prefix);
18422
17826
  if (!stats) return null;
18423
17827
  return {
@@ -18428,6 +17832,7 @@ var CustomIdTracker = class {
18428
17832
  };
18429
17833
  }
18430
17834
  getNextSuffix(prefix) {
17835
+ this._ensureFreshBounds(prefix);
18431
17836
  const stats = this.prefixMap.get(prefix);
18432
17837
  return stats ? stats.next : this.suffixIncrement;
18433
17838
  }
@@ -18441,6 +17846,7 @@ var CustomIdTracker = class {
18441
17846
  const { prefix, suffix } = this.analyzeCustomId(customId);
18442
17847
  if (!prefix && !suffix) return { prefix, suffix };
18443
17848
  this._noteCustomIdBefore(customId);
17849
+ this._ensureFreshBounds(prefix);
18444
17850
  if (this.prefixMap.has(prefix)) {
18445
17851
  const stats = this.prefixMap.get(prefix);
18446
17852
  if (!stats.usedSuffixes.has(suffix)) {
@@ -18471,22 +17877,12 @@ var CustomIdTracker = class {
18471
17877
  this._noteCustomIdBefore(customId);
18472
17878
  const currentStats = this.prefixMap.get(prefix);
18473
17879
  if (currentStats.usedSuffixes.has(suffix)) {
18474
- const newQuantity = currentStats.quantity - 1;
18475
- if (newQuantity === 0) {
17880
+ currentStats.usedSuffixes.delete(suffix);
17881
+ currentStats.quantity -= 1;
17882
+ if (currentStats.usedSuffixes.size === 0) {
18476
17883
  this.prefixMap.delete(prefix);
18477
17884
  } else {
18478
- const newUsed = new Set(currentStats.usedSuffixes);
18479
- newUsed.delete(suffix);
18480
- const remaining = Array.from(newUsed);
18481
- if (remaining.length === 0) {
18482
- this.prefixMap.delete(prefix);
18483
- } else {
18484
- currentStats.usedSuffixes = newUsed;
18485
- currentStats.min = minSuffixFromArray(remaining);
18486
- currentStats.max = maxSuffixFromArray(remaining);
18487
- currentStats.quantity = newQuantity;
18488
- this._recalculateNext(prefix);
18489
- }
17885
+ currentStats.boundsDirty = true;
18490
17886
  }
18491
17887
  }
18492
17888
  this.processedIds.delete(customId);
@@ -18506,12 +17902,19 @@ var CustomIdTracker = class {
18506
17902
  return customId.length > MAX_CUSTOM_ID_LENGTH;
18507
17903
  }
18508
17904
  _shouldSearchForGaps(prefix) {
17905
+ this._ensureFreshBounds(prefix);
18509
17906
  if (!this.prefixMap.has(prefix)) return false;
18510
17907
  const stats = this.prefixMap.get(prefix);
18511
17908
  const nextWouldBe = `${prefix}${addToSuffix(stats.max, this.suffixIncrement)}`;
18512
17909
  return nextWouldBe.length > MAX_CUSTOM_ID_LENGTH;
18513
17910
  }
17911
+ _suffixForUnknownPrefix(prefix, baseSuffix) {
17912
+ const candidate = baseSuffix && isValidSuffix(baseSuffix) ? baseSuffix : this.suffixIncrement;
17913
+ if (`${prefix}${candidate}`.length > MAX_CUSTOM_ID_LENGTH) return null;
17914
+ return candidate;
17915
+ }
18514
17916
  _findFirstAvailableGap(prefix) {
17917
+ this._ensureFreshBounds(prefix);
18515
17918
  if (!this.prefixMap.has(prefix)) return null;
18516
17919
  const stats = this.prefixMap.get(prefix);
18517
17920
  let candidate = this.suffixIncrement;
@@ -18535,10 +17938,9 @@ var CustomIdTracker = class {
18535
17938
  return `${this.defaultPrefix}${nextSuffix}`;
18536
17939
  }
18537
17940
  getNextAvailableSuffix(prefix, baseSuffix = null) {
17941
+ this._ensureFreshBounds(prefix);
18538
17942
  if (!this.prefixMap.has(prefix)) {
18539
- const candidate2 = baseSuffix && isValidSuffix(baseSuffix) ? baseSuffix : this.suffixIncrement;
18540
- if (`${prefix}${candidate2}`.length > MAX_CUSTOM_ID_LENGTH) return null;
18541
- return candidate2;
17943
+ return this._suffixForUnknownPrefix(prefix, baseSuffix);
18542
17944
  }
18543
17945
  const stats = this.prefixMap.get(prefix);
18544
17946
  const step = this.suffixIncrement;
@@ -18579,9 +17981,6 @@ var CustomIdTracker = class {
18579
17981
  }
18580
17982
  return generatedId;
18581
17983
  }
18582
- /**
18583
- * Seed the tracker from an array of activities. Idempotent.
18584
- */
18585
17984
  populateFromActivities(activities) {
18586
17985
  if (!Array.isArray(activities)) return this;
18587
17986
  const uniqueCustomIds = [
@@ -18602,14 +18001,6 @@ var CustomIdTracker = class {
18602
18001
  getDefaults() {
18603
18002
  return { prefix: this.defaultPrefix, increment: this.suffixIncrement };
18604
18003
  }
18605
- /**
18606
- * Generates a custom ID for a new child activity.
18607
- *
18608
- * Three strategies (see `selectGenerationStrategy`):
18609
- * - parentConversion: parent has customId → release it, child uses defaults.
18610
- * - pasteReference: reference has customId → use its prefix + suffix as base.
18611
- * - noContext: no reference → use defaults.
18612
- */
18613
18004
  generateCustomIdForNewChild(params) {
18614
18005
  const { activity, useActivityCustomIdAsReference = false } = params;
18615
18006
  const customId = getCustomIdFromActivity(activity);
@@ -18623,6 +18014,7 @@ var CustomIdTracker = class {
18623
18014
  );
18624
18015
  let capturedNextSuffix = null;
18625
18016
  if (strategyKey === "parentConversion" && this.prefixMap.has(prefix)) {
18017
+ this._ensureFreshBounds(prefix);
18626
18018
  const currentMax = this.prefixMap.get(prefix).max;
18627
18019
  capturedNextSuffix = addToSuffix(currentMax, this.suffixIncrement);
18628
18020
  }
@@ -18653,11 +18045,6 @@ var CustomIdTracker = class {
18653
18045
  return noContextStrategy(this.defaultPrefix);
18654
18046
  }
18655
18047
  }
18656
- /**
18657
- * Generates customId for parent-to-child conversion after outdent demote.
18658
- * If `siblingCustomId` is provided, follows its pattern (prefix + next
18659
- * suffix). Otherwise uses defaults.
18660
- */
18661
18048
  generateCustomIdForRestoredChild(siblingCustomId = null) {
18662
18049
  if (siblingCustomId) {
18663
18050
  const trimmed = siblingCustomId.trim();
@@ -18693,11 +18080,6 @@ var CustomIdTracker = class {
18693
18080
  hasPrefix(prefix) {
18694
18081
  return this.prefixMap.has(prefix);
18695
18082
  }
18696
- /**
18697
- * O(1) check — used by inline-edit to validate "no duplicate". When
18698
- * `currentCustomId` is passed, returns false if the new value matches
18699
- * (no-op edit). Used by the dispatch's `customIdPipeline.validate`.
18700
- */
18701
18083
  isCustomIdInUse(customId, currentCustomId = null) {
18702
18084
  if (!customId || typeof customId !== "string" || !customId.trim()) {
18703
18085
  return false;
@@ -18864,8 +18246,6 @@ function normalizeMilestoneConstraintDatesForDisplay(state) {
18864
18246
  var SCHEDULE_CORE_STATUS = {
18865
18247
  READY: "ready",
18866
18248
  DESTROYED: "destroyed",
18867
- /** A rollback failed mid-restore — state may be inconsistent; the host must
18868
- * reload from backend. All further dispatches are refused. */
18869
18249
  POISONED: "poisoned"
18870
18250
  };
18871
18251
  function initializeCore(input) {
@@ -18925,9 +18305,6 @@ function initializeCore(input) {
18925
18305
  sector,
18926
18306
  scheduler,
18927
18307
  skipAutoSchedule: input.skipInitialAutoSchedule === true,
18928
- // `loadNow` is rounded to end-of-local-day (legacy `calculateExpected`
18929
- // parity) — the LOAD expected_progress pass. Dispatch-time recomputes call
18930
- // `clock()` fresh, so a long-lived session tracks the real day.
18931
18308
  now: loadNow ?? void 0
18932
18309
  });
18933
18310
  return {
@@ -19043,13 +18420,10 @@ var ScheduleCore = class {
19043
18420
  this.assertReady();
19044
18421
  return readSelectedActivityIds(this.coreRuntime.state);
19045
18422
  }
19046
- /**
19047
- * Every activity id in canonical DFS visual order (pre-order from roots,
19048
- * siblings by `correlative_id` ASC) — ALL activities; filtering by
19049
- * `visible` is the consumer's job. Memoized in the state and invalidated
19050
- * on any structural mutation (add/remove/reparent/renumber), so repeated
19051
- * reads between mutations are O(1).
19052
- */
18423
+ getHiddenActivityIds() {
18424
+ this.assertReady();
18425
+ return this.coreRuntime.state.hiddenIds().map(String);
18426
+ }
19053
18427
  getVisualOrderIds() {
19054
18428
  this.assertReady();
19055
18429
  return [...this.coreRuntime.state.getVisualOrderIds()];
@@ -19149,7 +18523,7 @@ var ScheduleCore = class {
19149
18523
  );
19150
18524
  this._undo.record(
19151
18525
  buildUndoEntry(
19152
- result.changes,
18526
+ buildHistoryChangeSet(result.changes),
19153
18527
  result.__beforeSnap,
19154
18528
  result.__beforeLinks,
19155
18529
  created.afterSnap,
@@ -19166,19 +18540,13 @@ var ScheduleCore = class {
19166
18540
  this._saveTracker.snapshotLinks(this.getAllLinksView());
19167
18541
  this._undo.clear();
19168
18542
  }
18543
+ result = this._withReappliedFilter(action, result);
19169
18544
  if (!result.ok) return result;
19170
18545
  if (dispatchChangesSchedulingState(action) && changeSetIsSubstantive(result.changes)) {
19171
18546
  this._recordScheduleMutation(options.skipCriticalPath !== true);
19172
18547
  }
19173
- return cloneDomainValue(result);
18548
+ return toPublicDispatchResult(result);
19174
18549
  }
19175
- /**
19176
- * Starts or joins the Critical Path calculation for the current schedule
19177
- * revision. Snapshot capture and the final commit are serialized with user
19178
- * mutations, but the expensive calculation runs outside `_opQueue` against
19179
- * an isolated state. A newer revision aborts this job and makes its result
19180
- * ineligible to commit.
19181
- */
19182
18550
  recomputeCriticalPath() {
19183
18551
  const operation = this._enqueue(async () => ({
19184
18552
  job: this._startCriticalPathForCurrentRevision()
@@ -19194,6 +18562,28 @@ var ScheduleCore = class {
19194
18562
  await this.recomputeCriticalPath();
19195
18563
  }
19196
18564
  }
18565
+ _withReappliedFilter(action, result) {
18566
+ if (!result.ok || !reappliesActiveFilter(action)) return result;
18567
+ const merged = this._reapplyActiveFilter(result.changes);
18568
+ return merged === null ? result : { ...result, changes: merged };
18569
+ }
18570
+ _reapplyActiveFilter(changes) {
18571
+ const filter = this.coreRuntime.state.getActiveFilter();
18572
+ if (filter === null) return null;
18573
+ const adapter = this.coreRuntime.state;
18574
+ const visibleIds = evaluateVisibleIds({
18575
+ activities: adapter.getAllActivities(),
18576
+ parentOf: (activityId) => adapter.getParentId(activityId),
18577
+ filter,
18578
+ context: { hoursPerDay: this.coreRuntime.sector.hoursPerDay }
18579
+ });
18580
+ const viewState = applyVisibleSet(adapter, visibleIds);
18581
+ if (viewState.length === 0) return null;
18582
+ return {
18583
+ ...changes,
18584
+ viewState: [...changes.viewState ?? [], ...viewState]
18585
+ };
18586
+ }
19197
18587
  _recordScheduleMutation(criticalPathIsFresh) {
19198
18588
  this._scheduleRevision++;
19199
18589
  if (this._activeCriticalPath) {
@@ -19244,7 +18634,7 @@ var ScheduleCore = class {
19244
18634
  for (const [activityId, fields] of fieldsByActivity) {
19245
18635
  this.coreRuntime.state.setActivityFields(activityId, fields);
19246
18636
  }
19247
- changes = assembleChangeSet(this.coreRuntime.state, {
18637
+ changes = await assembleChangeSet(this.coreRuntime.state, {
19248
18638
  source: { kind: "init" },
19249
18639
  beforeSnap: /* @__PURE__ */ new Map(),
19250
18640
  touchedIds: [],
@@ -19271,7 +18661,6 @@ var ScheduleCore = class {
19271
18661
  void promise.then(clearIfActive, clearIfActive);
19272
18662
  return promise;
19273
18663
  }
19274
- // bridge-load artifact: emits HOURS (no duration/lag diff anyway; bridge applies verbatim).
19275
18664
  async _runCriticalPathAndCapture() {
19276
18665
  if (this._status === SCHEDULE_CORE_STATUS.DESTROYED) {
19277
18666
  return {
@@ -19292,7 +18681,7 @@ var ScheduleCore = class {
19292
18681
  this.coreRuntime.state,
19293
18682
  this.coreRuntime.sector.hoursPerDay
19294
18683
  );
19295
- changes = assembleChangeSet(this.coreRuntime.state, {
18684
+ changes = await assembleChangeSet(this.coreRuntime.state, {
19296
18685
  source: { kind: "init" },
19297
18686
  beforeSnap: /* @__PURE__ */ new Map(),
19298
18687
  touchedIds: [],
@@ -19305,11 +18694,6 @@ var ScheduleCore = class {
19305
18694
  }
19306
18695
  return { changes };
19307
18696
  }
19308
- /**
19309
- * Undo/Redo restores the user's historical mutation while retaining current
19310
- * non-historical truth (for example a refreshed baseline). Re-derive every
19311
- * value that depends on both so the restored model is immediately coherent.
19312
- */
19313
18697
  _recomputeAfterHistoryRestore() {
19314
18698
  const state = this.coreRuntime.state;
19315
18699
  recomputeAllProgressRollup(state);
@@ -19345,7 +18729,12 @@ var ScheduleCore = class {
19345
18729
  if (needsResync(entry)) this._resyncCustomIdTrackerFromModel();
19346
18730
  this._undo.pushRedo(entry);
19347
18731
  this._undo.resetCoalesce();
19348
- return buildInverseChangeSet(this.coreRuntime.state, entry, "before");
18732
+ const changes = buildInverseChangeSet(
18733
+ this.coreRuntime.state,
18734
+ entry,
18735
+ "before"
18736
+ );
18737
+ return this._reapplyActiveFilter(changes) ?? changes;
19349
18738
  });
19350
18739
  void operation.then(
19351
18740
  (changes) => {
@@ -19373,7 +18762,12 @@ var ScheduleCore = class {
19373
18762
  if (needsResync(entry)) this._resyncCustomIdTrackerFromModel();
19374
18763
  this._undo.pushUndo(entry);
19375
18764
  this._undo.resetCoalesce();
19376
- return buildInverseChangeSet(this.coreRuntime.state, entry, "after");
18765
+ const changes = buildInverseChangeSet(
18766
+ this.coreRuntime.state,
18767
+ entry,
18768
+ "after"
18769
+ );
18770
+ return this._reapplyActiveFilter(changes) ?? changes;
19377
18771
  });
19378
18772
  void operation.then(
19379
18773
  (changes) => {
@@ -19396,11 +18790,6 @@ var ScheduleCore = class {
19396
18790
  canRedo() {
19397
18791
  return this._undo.canRedo();
19398
18792
  }
19399
- /**
19400
- * Establishes a new persistence boundary without mutating schedule state.
19401
- * Completed saves call this synchronously so neither prior undo entries nor
19402
- * their redo branch can cross the persisted boundary.
19403
- */
19404
18793
  clearHistory() {
19405
18794
  this._undo.clear();
19406
18795
  }
@@ -19435,13 +18824,6 @@ var ScheduleCore = class {
19435
18824
  );
19436
18825
  }
19437
18826
  }
19438
- /**
19439
- * Revert the current dispatch's mutations from the write-capture journal. If
19440
- * the restore ITSELF throws, the state may be a third, partially-inverted
19441
- * state — worse than either endpoint — so poison the core: refuse all further
19442
- * dispatches and surface the fault so the host reloads from backend. A failed
19443
- * rollback is never swallowed.
19444
- */
19445
18827
  _rollback() {
19446
18828
  try {
19447
18829
  this.coreRuntime.state.restoreFromCapture();
@@ -19456,6 +18838,14 @@ var ScheduleCore = class {
19456
18838
  }
19457
18839
  }
19458
18840
  };
18841
+ function toPublicDispatchResult(result) {
18842
+ const {
18843
+ __beforeSnap: droppedSnapshots,
18844
+ __beforeLinks: droppedLinks,
18845
+ ...publicResult
18846
+ } = result;
18847
+ return publicResult;
18848
+ }
19459
18849
 
19460
18850
  // src/boundary/save/link-changes.ts
19461
18851
  function checkNoUpdatedLinks(baseline, current) {
@@ -19510,6 +18900,7 @@ var DISPATCH_ACTION_KIND = {
19510
18900
  SELECTION_TOGGLE: "selection-toggle",
19511
18901
  SELECTION_REPLACE: "selection-replace",
19512
18902
  VISIBILITY_SET: "visibility-set",
18903
+ FILTER_SET: "filter-set",
19513
18904
  SIR_SYNC: "sir-sync",
19514
18905
  ACTIVITY_LOOKAHEAD_SYNC: "activity-lookahead-sync"
19515
18906
  };
@@ -19535,6 +18926,7 @@ var KIND_CATALOG_COVERS_UNION = {
19535
18926
  [DISPATCH_ACTION_KIND.SELECTION_TOGGLE]: true,
19536
18927
  [DISPATCH_ACTION_KIND.SELECTION_REPLACE]: true,
19537
18928
  [DISPATCH_ACTION_KIND.VISIBILITY_SET]: true,
18929
+ [DISPATCH_ACTION_KIND.FILTER_SET]: true,
19538
18930
  [DISPATCH_ACTION_KIND.SIR_SYNC]: true,
19539
18931
  [DISPATCH_ACTION_KIND.ACTIVITY_LOOKAHEAD_SYNC]: true
19540
18932
  };