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