@outbuild-company/schedule-core 1.2.0 → 1.4.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,390 @@ 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 STATUS_ORDER = [
249
+ "Waiting",
250
+ "Done",
251
+ "Doing",
252
+ "Overdue",
253
+ "Advancement"
254
+ ];
255
+ var CONSTRAINT_TYPE_ORDER = [
256
+ "mfo",
257
+ "mso",
258
+ "snlt",
259
+ "snet",
260
+ "alap",
261
+ "asap",
262
+ "fnet",
263
+ "fnlt"
264
+ ];
265
+ var MILLISECONDS_PER_DAY = 1e3 * 60 * 60 * 24;
266
+ function toDays(hours, hoursPerDay) {
267
+ if (hours === null) return null;
268
+ if (hoursPerDay <= 0) return null;
269
+ return hours / hoursPerDay;
270
+ }
271
+ function calendarDaySpan(startDate, endDate) {
272
+ const elapsed = endDate.getTime() - startDate.getTime();
273
+ return Math.floor(elapsed / MILLISECONDS_PER_DAY) + 1;
274
+ }
275
+ var FIELD_REGISTRY = {
276
+ name: { valueKind: "string", extract: (activity) => activity.name },
277
+ description: {
278
+ valueKind: "string",
279
+ extract: (activity) => activity.description
280
+ },
281
+ customId: { valueKind: "string", extract: (activity) => activity.customId },
282
+ correlativeId: {
283
+ valueKind: "number",
284
+ extract: (activity) => activity.correlativeId
285
+ },
286
+ uniqueCorrelativeId: {
287
+ valueKind: "number",
288
+ extract: (activity) => Number(activity.uniqueCorrelativeId)
289
+ },
290
+ progress: { valueKind: "number", extract: (activity) => activity.progress },
291
+ durationDays: {
292
+ valueKind: "number",
293
+ extract: (activity, context) => toDays(activity.durationHours, context.hoursPerDay)
294
+ },
295
+ calendarDuration: {
296
+ valueKind: "number",
297
+ extract: (activity) => calendarDaySpan(activity.startDate, activity.endDate)
298
+ },
299
+ cost: { valueKind: "number", extract: (activity) => activity.cost },
300
+ usedCost: { valueKind: "number", extract: (activity) => activity.usedCost },
301
+ realCost: { valueKind: "number", extract: (activity) => activity.realCost },
302
+ workHours: { valueKind: "number", extract: (activity) => activity.workHours },
303
+ realWorkHours: {
304
+ valueKind: "number",
305
+ extract: (activity) => activity.realWorkHours
306
+ },
307
+ ponderator: {
308
+ valueKind: "number",
309
+ extract: (activity) => activity.ponderator
310
+ },
311
+ freeSlackDays: {
312
+ valueKind: "number",
313
+ extract: (activity, context) => toDays(activity.freeSlackHours, context.hoursPerDay)
314
+ },
315
+ totalSlackDays: {
316
+ valueKind: "number",
317
+ extract: (activity, context) => toDays(
318
+ activity.criticalPath?.totalSlackHours ?? null,
319
+ context.hoursPerDay
320
+ )
321
+ },
322
+ expectedProgressBaseline: {
323
+ valueKind: "number",
324
+ extract: (activity) => activity.expectedProgressBaseline
325
+ },
326
+ baselineDurationDays: {
327
+ valueKind: "number",
328
+ extract: (activity) => activity.baselineSnapshot?.durationDays ?? null
329
+ },
330
+ baselineCost: {
331
+ valueKind: "number",
332
+ extract: (activity) => activity.baselineSnapshot?.cost ?? null
333
+ },
334
+ baselineWorkHours: {
335
+ valueKind: "number",
336
+ extract: (activity) => activity.baselineSnapshot?.workHours ?? null
337
+ },
338
+ startDate: { valueKind: "date", extract: (activity) => activity.startDate },
339
+ endDate: { valueKind: "date", extract: (activity) => activity.endDate },
340
+ constraintDate: {
341
+ valueKind: "date",
342
+ extract: (activity) => activity.constraintDate
343
+ },
344
+ baselineStartDate: {
345
+ valueKind: "date",
346
+ extract: (activity) => activity.baselineSnapshot?.startDate ?? null
347
+ },
348
+ baselineEndDate: {
349
+ valueKind: "date",
350
+ extract: (activity) => activity.baselineSnapshot?.endDate ?? null
351
+ },
352
+ earlyStart: {
353
+ valueKind: "date",
354
+ extract: (activity) => activity.criticalPath?.earlyStart ?? null
355
+ },
356
+ earlyFinish: {
357
+ valueKind: "date",
358
+ extract: (activity) => activity.criticalPath?.earlyFinish ?? null
359
+ },
360
+ lateStart: {
361
+ valueKind: "date",
362
+ extract: (activity) => activity.criticalPath?.lateStart ?? null
363
+ },
364
+ lateFinish: {
365
+ valueKind: "date",
366
+ extract: (activity) => activity.criticalPath?.lateFinish ?? null
367
+ },
368
+ responsableIds: {
369
+ valueKind: "id-array",
370
+ extract: (activity) => activity.responsableIds
371
+ },
372
+ tagIds: { valueKind: "id-array", extract: (activity) => activity.tagIds },
373
+ status: {
374
+ valueKind: "enum",
375
+ order: STATUS_ORDER,
376
+ extract: (activity) => activity.status
377
+ },
378
+ constraintType: {
379
+ valueKind: "enum",
380
+ order: CONSTRAINT_TYPE_ORDER,
381
+ extract: (activity) => activity.constraintType
382
+ },
383
+ calendarId: {
384
+ valueKind: "reference",
385
+ extract: (activity) => activity.calendarId === null ? null : String(activity.calendarId)
386
+ },
387
+ // Normalized to string like calendarId. It is stored as a number, so it used
388
+ // to reach compareValues through the numeric branch while its sibling
389
+ // reference went through the string one — the same field kind comparing two
390
+ // different ways. localeCompare with numeric:true keeps the digit ordering.
391
+ subcontractId: {
392
+ valueKind: "reference",
393
+ extract: (activity) => activity.subcontractId === null ? null : String(activity.subcontractId)
394
+ },
395
+ // Declared boolean, not enum: it is one, and saying so is what lets the enum
396
+ // branch demand an order without inventing one for true/false.
397
+ isCritical: {
398
+ valueKind: "boolean",
399
+ extract: (activity) => activity.isCritical
400
+ }
401
+ };
402
+ function getFieldDescriptor(field) {
403
+ return FIELD_REGISTRY[field] ?? null;
404
+ }
405
+
406
+ // src/internal/filter/evaluate-filter.ts
407
+ function toTargetDate(value) {
408
+ if (value instanceof Date) return value;
409
+ if (typeof value === "string" || typeof value === "number") {
410
+ return new Date(value);
411
+ }
412
+ return new Date(Number.NaN);
413
+ }
414
+ function matchString(value, target, operator) {
415
+ const isAbsent = value === null;
416
+ if (operator === "includes") {
417
+ return !isAbsent && String(value).toLowerCase().includes(target.toLowerCase());
418
+ }
419
+ if (operator === "notIncludes") {
420
+ return isAbsent || !String(value).toLowerCase().includes(target.toLowerCase());
421
+ }
422
+ if (operator === "is") return !isAbsent && String(value) === target;
423
+ if (operator === "isNot") return isAbsent || String(value) !== target;
424
+ return false;
425
+ }
426
+ function matchNumber(value, target, operator) {
427
+ if (value === null || typeof value !== "number") {
428
+ return operator === "notEquals";
429
+ }
430
+ if (operator === "equals") return value === target;
431
+ if (operator === "notEquals") return value !== target;
432
+ if (operator === "greaterThan") return value > target;
433
+ if (operator === "lessThan") return value < target;
434
+ if (operator === "greaterOrEqual") return value >= target;
435
+ if (operator === "lessOrEqual") return value <= target;
436
+ return false;
437
+ }
438
+ function matchDate(value, target, operator) {
439
+ if (!(value instanceof Date)) return false;
440
+ if (operator === "after") return value.getTime() > target.getTime();
441
+ if (operator === "before") return value.getTime() < target.getTime();
442
+ return false;
443
+ }
444
+ function matchIdArray(value, allowed, operator) {
445
+ const ids = Array.isArray(value) ? value : [];
446
+ const intersects = ids.some((id) => allowed.has(String(id)));
447
+ if (operator === "someOf") return intersects;
448
+ if (operator === "notSomeOf") return !intersects;
449
+ return false;
450
+ }
451
+ function matchEnum(value, allowed, operator) {
452
+ const isMember = value !== null && allowed.has(String(value));
453
+ if (operator === "someOf") return isMember;
454
+ if (operator === "notSomeOf") return !isMember;
455
+ return false;
456
+ }
457
+ function toAllowedSet(value) {
458
+ const items = Array.isArray(value) ? value : [value];
459
+ return new Set(items.map((item) => String(item)));
460
+ }
461
+ function matchCriterion(activity, criterion, context) {
462
+ const descriptor = getFieldDescriptor(criterion.field);
463
+ if (descriptor === null) return false;
464
+ const value = descriptor.extract(activity, context);
465
+ const { operator } = criterion;
466
+ if (descriptor.valueKind === "string") {
467
+ return matchString(value, String(criterion.value), operator);
468
+ }
469
+ if (descriptor.valueKind === "number") {
470
+ return matchNumber(value, Number(criterion.value), operator);
471
+ }
472
+ if (descriptor.valueKind === "date") {
473
+ return matchDate(value, toTargetDate(criterion.value), operator);
474
+ }
475
+ if (descriptor.valueKind === "id-array") {
476
+ return matchIdArray(value, toAllowedSet(criterion.value), operator);
477
+ }
478
+ return matchEnum(value, toAllowedSet(criterion.value), operator);
479
+ }
480
+ function matchesCriteria(activity, filter, context) {
481
+ if (filter.criteria.length === 0) return true;
482
+ if (filter.logic === "or") {
483
+ return filter.criteria.some(
484
+ (criterion) => matchCriterion(activity, criterion, context)
485
+ );
486
+ }
487
+ return filter.criteria.every(
488
+ (criterion) => matchCriterion(activity, criterion, context)
489
+ );
490
+ }
491
+ function overlapsRange(activity, range) {
492
+ const taskStart = activity.startDate.getTime();
493
+ const taskEnd = activity.endDate.getTime();
494
+ const windowStart = range.start.getTime();
495
+ const windowEnd = range.end.getTime();
496
+ const fullyInside = taskStart >= windowStart && taskEnd <= windowEnd;
497
+ const startsInside = taskStart >= windowStart && taskStart <= windowEnd;
498
+ const windowStartsInside = windowStart >= taskStart && windowStart <= taskEnd;
499
+ return fullyInside || startsInside || windowStartsInside;
500
+ }
501
+ function addAncestors(matchedId, parentOf, visibleIds) {
502
+ let ancestorId = parentOf(matchedId);
503
+ while (ancestorId !== null && !visibleIds.has(String(ancestorId))) {
504
+ visibleIds.add(String(ancestorId));
505
+ ancestorId = parentOf(ancestorId);
506
+ }
507
+ }
508
+ function evaluateVisibleIds(input) {
509
+ const { activities, parentOf, filter, context } = input;
510
+ const range = filter.dateRange;
511
+ const visibleIds = /* @__PURE__ */ new Set();
512
+ const matchedIds = [];
513
+ for (const activity of activities) {
514
+ const passesCriteria = matchesCriteria(activity, filter, context);
515
+ const passesRange = range === void 0 || overlapsRange(activity, range);
516
+ if (passesCriteria && passesRange) {
517
+ visibleIds.add(String(activity.id));
518
+ matchedIds.push(activity.id);
519
+ }
520
+ }
521
+ for (const matchedId of matchedIds) {
522
+ addAncestors(matchedId, parentOf, visibleIds);
523
+ }
524
+ return visibleIds;
525
+ }
526
+
527
+ // src/internal/filter/context.ts
528
+ var COLLATION_LOCALE = "en";
529
+ function buildFilterContext(hoursPerDay) {
530
+ return { hoursPerDay, locale: COLLATION_LOCALE };
531
+ }
532
+
533
+ // src/internal/filter/validate.ts
534
+ var OPERATORS_BY_KIND = {
535
+ string: /* @__PURE__ */ new Set(["includes", "notIncludes", "is", "isNot"]),
536
+ number: /* @__PURE__ */ new Set([
537
+ "equals",
538
+ "notEquals",
539
+ "greaterThan",
540
+ "lessThan",
541
+ "greaterOrEqual",
542
+ "lessOrEqual"
543
+ ]),
544
+ date: /* @__PURE__ */ new Set(["after", "before"]),
545
+ "id-array": /* @__PURE__ */ new Set(["someOf", "notSomeOf"]),
546
+ enum: /* @__PURE__ */ new Set(["someOf", "notSomeOf"]),
547
+ // Same membership operators as enum: splitting the kinds was about ordering,
548
+ // not about filtering, and these two filter exactly like an enum.
549
+ boolean: /* @__PURE__ */ new Set(["someOf", "notSomeOf"]),
550
+ reference: /* @__PURE__ */ new Set(["someOf", "notSomeOf"])
551
+ };
552
+ function validateCriterion(criterion) {
553
+ const descriptor = getFieldDescriptor(criterion.field);
554
+ if (descriptor === null) return "unknown_field";
555
+ if (!OPERATORS_BY_KIND[descriptor.valueKind].has(criterion.operator)) {
556
+ return "unknown_operator";
557
+ }
558
+ return validateValueForKind(criterion, descriptor.valueKind);
559
+ }
560
+ function validateValueForKind(criterion, valueKind) {
561
+ const { value } = criterion;
562
+ if (valueKind === "id-array" || valueKind === "enum") {
563
+ return Array.isArray(value) ? null : "invalid_value";
564
+ }
565
+ if (Array.isArray(value)) return "invalid_value";
566
+ if (valueKind === "number") {
567
+ return Number.isFinite(Number(value)) ? null : "invalid_value";
568
+ }
569
+ if (valueKind === "date") {
570
+ return isValidDateValue(value) ? null : "invalid_value";
571
+ }
572
+ return null;
573
+ }
574
+ function isValidDateValue(value) {
575
+ if (value instanceof Date) return true;
576
+ if (typeof value === "string" || typeof value === "number") {
577
+ return !Number.isNaN(new Date(value).getTime());
578
+ }
579
+ return false;
580
+ }
581
+
582
+ // src/dispatch/filter.ts
583
+ function isEmptyFilter(filter) {
584
+ return filter.criteria.length === 0 && filter.dateRange === void 0;
585
+ }
586
+ function resolveVisibleIds(adapter, filter, hoursPerDay) {
587
+ const activities = adapter.getAllActivities();
588
+ if (isEmptyFilter(filter)) {
589
+ return new Set(activities.map((activity) => String(activity.id)));
590
+ }
591
+ return evaluateVisibleIds({
592
+ activities,
593
+ parentOf: (activityId) => adapter.getParentId(activityId),
594
+ filter,
595
+ context: buildFilterContext(hoursPerDay)
596
+ });
597
+ }
598
+ function dispatchFilterSet(action, deps) {
599
+ const { adapter, hoursPerDay } = deps;
600
+ for (const criterion of action.criteria) {
601
+ const rejection = validateCriterion(criterion);
602
+ if (rejection !== null) return { ok: false, reason: rejection };
603
+ }
604
+ const filter = action.dateRange === void 0 ? { criteria: action.criteria, logic: action.logic } : {
605
+ criteria: action.criteria,
606
+ logic: action.logic,
607
+ dateRange: action.dateRange
608
+ };
609
+ adapter.setActiveFilter(isEmptyFilter(filter) ? null : filter);
610
+ const visibleIds = resolveVisibleIds(adapter, filter, hoursPerDay);
611
+ const viewState = applyVisibleSet(adapter, visibleIds);
241
612
  const changes = {
242
613
  source: action,
243
614
  activities: [],
@@ -249,6 +620,140 @@ function dispatchVisibilitySet(action, deps) {
249
620
  return { ok: true, changes };
250
621
  }
251
622
 
623
+ // src/internal/hierarchy/root-parent.ts
624
+ var ROOT_PARENT_ID = "0";
625
+ function isRootParent(parent) {
626
+ return parent == null || parent === 0 || parent === ROOT_PARENT_ID;
627
+ }
628
+ function normalizeParentKey(parent) {
629
+ return isRootParent(parent) ? ROOT_PARENT_ID : String(parent);
630
+ }
631
+
632
+ // src/internal/hierarchy/visual-order.ts
633
+ var NOT_SET_SORT_VALUE = Number.MAX_SAFE_INTEGER;
634
+ function getChildrenInVisualOrder(parentId, adapter) {
635
+ const children = collectChildrenSnapshots(parentId, adapter);
636
+ const userOrder = adapter.getOrderComparator?.() ?? null;
637
+ children.sort(
638
+ userOrder === null ? compareActivitiesInVisualOrder : (a, b) => userOrder(a, b) || compareActivitiesInVisualOrder(a, b)
639
+ );
640
+ return children.map((a) => String(a.id));
641
+ }
642
+ function iterateInVisualOrder(adapter) {
643
+ const result = [];
644
+ const visit = (activity) => {
645
+ result.push(activity);
646
+ const childIds = getChildrenInVisualOrder(String(activity.id), adapter);
647
+ for (const childId of childIds) {
648
+ const child = adapter.getActivity(childId);
649
+ if (child) visit(child);
650
+ }
651
+ };
652
+ const rootIds = getChildrenInVisualOrder(ROOT_PARENT_ID, adapter);
653
+ for (const rootId of rootIds) {
654
+ const root = adapter.getActivity(rootId);
655
+ if (root) visit(root);
656
+ }
657
+ return result;
658
+ }
659
+ function findPreviousNonSelectedSibling(taskId, selected, adapter) {
660
+ const activity = adapter.getActivity(taskId);
661
+ if (!activity) return null;
662
+ const parentKey = parentKeyOf(activity);
663
+ const siblings = getChildrenInVisualOrder(parentKey, adapter);
664
+ const idx = siblings.findIndex((id) => String(id) === String(taskId));
665
+ if (idx <= 0) return null;
666
+ for (let i = idx - 1; i >= 0; i--) {
667
+ const candidateId = siblings[i];
668
+ if (candidateId === void 0) continue;
669
+ if (!setHas(selected, candidateId)) return candidateId;
670
+ }
671
+ return null;
672
+ }
673
+ function visualIndexInParent(taskId, adapter) {
674
+ const activity = adapter.getActivity(taskId);
675
+ if (!activity) return -1;
676
+ const parentKey = parentKeyOf(activity);
677
+ const siblings = getChildrenInVisualOrder(parentKey, adapter);
678
+ return siblings.findIndex((id) => String(id) === String(taskId));
679
+ }
680
+ function collectChildrenSnapshots(parentId, adapter) {
681
+ const key = String(parentId);
682
+ if (key === "0") {
683
+ return adapter.getAllActivities().filter((a) => a.parentId === null);
684
+ }
685
+ const childIds = adapter.getChildren(parentId);
686
+ const out = [];
687
+ for (const id of childIds) {
688
+ const snap = adapter.getActivity(id);
689
+ if (snap) out.push(snap);
690
+ }
691
+ return out;
692
+ }
693
+ function compareActivitiesInVisualOrder(a, b) {
694
+ const ac = correlativeIdOf(a);
695
+ const bc = correlativeIdOf(b);
696
+ if (ac !== bc) return ac - bc;
697
+ return String(a.id).localeCompare(String(b.id));
698
+ }
699
+ function correlativeIdOf(activity) {
700
+ const raw = activity.correlativeId;
701
+ const n = typeof raw === "number" ? raw : Number(raw);
702
+ return Number.isFinite(n) ? n : NOT_SET_SORT_VALUE;
703
+ }
704
+ function parentKeyOf(activity) {
705
+ const parentId = activity.parentId;
706
+ if (parentId === null) return "0";
707
+ return parentId;
708
+ }
709
+ function setHas(set, id) {
710
+ if (set.has(id)) return true;
711
+ return set.has(String(id));
712
+ }
713
+
714
+ // src/dispatch/shared/collect-branch-order.ts
715
+ function collectBranchOrder(adapter) {
716
+ const branches = [];
717
+ const visit = (parentId) => {
718
+ const childIds = getChildrenInVisualOrder(parentId, adapter);
719
+ if (childIds.length > 1) {
720
+ branches.push({ parentId, childIds });
721
+ }
722
+ for (const childId of childIds) {
723
+ visit(childId);
724
+ }
725
+ };
726
+ visit(ROOT_PARENT_ID);
727
+ return branches;
728
+ }
729
+
730
+ // src/dispatch/order.ts
731
+ function validateRule(rule) {
732
+ if (getFieldDescriptor(rule.field) === null) return "unknown_field";
733
+ if (rule.direction !== "asc" && rule.direction !== "desc") {
734
+ return "unknown_operator";
735
+ }
736
+ return null;
737
+ }
738
+ function dispatchSortSet(action, deps) {
739
+ const { adapter } = deps;
740
+ for (const rule of action.rules) {
741
+ const rejection = validateRule(rule);
742
+ if (rejection !== null) return { ok: false, reason: rejection };
743
+ }
744
+ const order = action.rules.length === 0 ? null : { rules: action.rules };
745
+ adapter.setActiveOrder(order);
746
+ const changes = {
747
+ source: action,
748
+ activities: [],
749
+ links: [],
750
+ calendars: [],
751
+ trackingEvents: [],
752
+ order: collectBranchOrder(adapter)
753
+ };
754
+ return { ok: true, changes };
755
+ }
756
+
252
757
  // src/columns/text/constants.ts
253
758
  var TEXT = "text";
254
759
 
@@ -630,19 +1135,22 @@ var ACTIVITY_TYPE = {
630
1135
  MILESTONE: "milestone"
631
1136
  };
632
1137
  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
1138
  YIELD_SLICE_MS: 8
636
1139
  };
637
1140
 
638
1141
  // src/shared/timing.ts
639
1142
  var isNode = typeof window === "undefined";
640
- var channel = !isNode && typeof MessageChannel !== "undefined" ? new MessageChannel() : null;
1143
+ var hasMessageChannel = !isNode && typeof MessageChannel !== "undefined";
641
1144
  function yieldToBrowser() {
642
- if (isNode || !channel) return Promise.resolve();
1145
+ if (!hasMessageChannel) return Promise.resolve();
643
1146
  return new Promise((resolve) => {
644
- channel.port1.onmessage = () => resolve();
645
- channel.port2.postMessage(null);
1147
+ const oneShotChannel = new MessageChannel();
1148
+ oneShotChannel.port1.onmessage = () => {
1149
+ oneShotChannel.port1.close();
1150
+ oneShotChannel.port2.close();
1151
+ resolve();
1152
+ };
1153
+ oneShotChannel.port2.postMessage(null);
646
1154
  });
647
1155
  }
648
1156
 
@@ -1250,7 +1758,6 @@ function calculateSuccessorStartFromLink(predecessor, successor, link, adapter)
1250
1758
  startDate: date2,
1251
1759
  durationHours: sourceLag,
1252
1760
  task: predecessor
1253
- // sourceLag always on predecessor calendar
1254
1761
  });
1255
1762
  }
1256
1763
  if (targetLag !== 0) {
@@ -1258,7 +1765,6 @@ function calculateSuccessorStartFromLink(predecessor, successor, link, adapter)
1258
1765
  startDate: date2,
1259
1766
  durationHours: targetLag,
1260
1767
  task: successor
1261
- // targetLag always on successor calendar
1262
1768
  });
1263
1769
  }
1264
1770
  if (trueLag !== 0) {
@@ -1266,7 +1772,6 @@ function calculateSuccessorStartFromLink(predecessor, successor, link, adapter)
1266
1772
  startDate: date2,
1267
1773
  durationHours: trueLag,
1268
1774
  task: successor
1269
- // trueLag always on successor calendar
1270
1775
  });
1271
1776
  }
1272
1777
  if (successor.durationHours === 0) {
@@ -1555,15 +2060,6 @@ function isSummaryActivity(activity, adapter) {
1555
2060
  return isSummary(activity.type, adapter.getChildren(activity.id).length > 0);
1556
2061
  }
1557
2062
 
1558
- // src/internal/hierarchy/root-parent.ts
1559
- var ROOT_PARENT_ID = "0";
1560
- function isRootParent(parent) {
1561
- return parent == null || parent === 0 || parent === ROOT_PARENT_ID;
1562
- }
1563
- function normalizeParentKey(parent) {
1564
- return isRootParent(parent) ? ROOT_PARENT_ID : String(parent);
1565
- }
1566
-
1567
2063
  // src/autoscheduler/engine/alap-pass.ts
1568
2064
  async function alapPass(reversedIds, links, asapPlans, adapter, _options, isCurrent) {
1569
2065
  const plans = new Map(asapPlans);
@@ -1916,8 +2412,6 @@ function parseEntry(entry) {
1916
2412
  lag = sign === "-" ? -value : value;
1917
2413
  }
1918
2414
  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
2415
  correlativeId,
1922
2416
  type,
1923
2417
  lag
@@ -2024,36 +2518,6 @@ function lagDaysToHours(lagDays, hoursPerDay) {
2024
2518
 
2025
2519
  // src/autoscheduler/date-math/impl-current.ts
2026
2520
  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
2521
  rawInputToConstraintDate(rawDate, calendar) {
2058
2522
  const midnight = new Date(rawDate);
2059
2523
  midnight.setUTCHours(0, 0, 0, 0);
@@ -2069,16 +2533,6 @@ var currentImpl = {
2069
2533
  }
2070
2534
  return midnight;
2071
2535
  },
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
2536
  computeLagBetweenTasks(sourceDate, targetDate, calendar) {
2083
2537
  return calendar.calculateDuration(sourceDate, targetDate);
2084
2538
  }
@@ -2115,36 +2569,16 @@ var AutoScheduler = class {
2115
2569
  getCurrentCalculationId() {
2116
2570
  return this.currentCalculationId;
2117
2571
  }
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
2572
  invalidateTopoCache() {
2124
2573
  this.topoCache.invalidate();
2125
2574
  }
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
2575
  invalidateExpandedLinksCache() {
2132
2576
  this.expandedLinksCache.invalidate();
2133
2577
  }
2134
- /**
2135
- * Convenience: invalidate every cache held by the scheduler.
2136
- */
2137
2578
  invalidateAllCaches() {
2138
2579
  this.topoCache.invalidate();
2139
2580
  this.expandedLinksCache.invalidate();
2140
2581
  }
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
2582
  async schedule(options = {}) {
2149
2583
  const calculationId = ++this.currentCalculationId;
2150
2584
  const isCurrent = createIsCurrent(
@@ -2513,16 +2947,6 @@ function sortDeepestFirst(ids, depths) {
2513
2947
  // src/internal/post-processors/runner.ts
2514
2948
  var POST_PROCESSORS = {
2515
2949
  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
2950
  updateTaskTiming: runNoOp("updateTaskTiming"),
2527
2951
  adjustLinkLagOnTaskMove,
2528
2952
  recordLastStartDate: runRecordLastStartDate
@@ -2945,7 +3369,6 @@ function buildDescendantCascade(activity, newValue, autoScheduling, hierarchy, r
2945
3369
  const descendants = hierarchy.getDescendantIds(activity.id);
2946
3370
  return descendants.map((id) => ({
2947
3371
  activityId: id,
2948
- // Descendants of a recursive progress change inherit the primary value.
2949
3372
  fields: descendantFields(
2950
3373
  newValue,
2951
3374
  autoScheduling,
@@ -3258,7 +3681,6 @@ var startDatePipeline = {
3258
3681
  {
3259
3682
  startDate: finalStart,
3260
3683
  ...setEndDate(finalEnd),
3261
- // Sanea la duration de un milestone corrupto en el mismo move.
3262
3684
  ...milestoneActivity ? setDuration(0) : {},
3263
3685
  ...setConstraintTypeImplied(),
3264
3686
  ...setConstraintDate(constraintDate)
@@ -3537,9 +3959,11 @@ var calendarIdPipeline = {
3537
3959
  if (isEmpty(value)) return parseError("empty_calendar");
3538
3960
  return parsed(value);
3539
3961
  },
3540
- validate(activity, _oldValue, newValue) {
3962
+ validate(activity, _oldValue, newValue, ctx) {
3541
3963
  if (isUnchangedCalendar(activity.calendarId, newValue))
3542
3964
  return invalid("unchanged");
3965
+ if (!ctx.calendars.getCalendar(newValue))
3966
+ return invalid("unknown_calendar");
3543
3967
  return valid();
3544
3968
  },
3545
3969
  transform(activity, newValue, ctx) {
@@ -3754,9 +4178,6 @@ var COLUMN_PIPELINES = /* @__PURE__ */ new Map([
3754
4178
  [COLUMN.CONSTRAINT_DATE, constraintDatePipeline],
3755
4179
  [COLUMN.CALENDAR_ID, calendarIdPipeline],
3756
4180
  [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
4181
  [COLUMN.SUBCONTRACT_ID, subcontractIdPipeline],
3761
4182
  [COLUMN.RESPONSABLES, responsablesPipeline],
3762
4183
  [COLUMN.TAGS, tagsPipeline]
@@ -3881,7 +4302,13 @@ function cloneCriticalPath(value) {
3881
4302
  };
3882
4303
  }
3883
4304
 
4305
+ // src/shared/clone-domain-value.ts
4306
+ function cloneDomainValue(value) {
4307
+ return structuredClone(value);
4308
+ }
4309
+
3884
4310
  // src/dispatch/shared/snapshots.ts
4311
+ var YIELD_EVERY_N_ENTRIES = 200;
3885
4312
  function collectTouchedIds(primary, changes) {
3886
4313
  const ids = /* @__PURE__ */ new Set([String(primary)]);
3887
4314
  for (const mutation of changes.cascadeMutations ?? []) {
@@ -3889,9 +4316,12 @@ function collectTouchedIds(primary, changes) {
3889
4316
  }
3890
4317
  return ids;
3891
4318
  }
3892
- function snapshotActivities(adapter, ids) {
4319
+ async function snapshotActivities(adapter, ids) {
3893
4320
  const out = /* @__PURE__ */ new Map();
4321
+ let processed = 0;
3894
4322
  for (const id of ids) {
4323
+ processed += 1;
4324
+ if (processed % YIELD_EVERY_N_ENTRIES === 0) await yieldToBrowser();
3895
4325
  const a = adapter.getActivity(id);
3896
4326
  if (a) out.set(id, structuredCloneActivity(a));
3897
4327
  }
@@ -3900,6 +4330,10 @@ function snapshotActivities(adapter, ids) {
3900
4330
  function structuredCloneActivity(activity) {
3901
4331
  return cloneCoreActivity(activity);
3902
4332
  }
4333
+ function snapshotSingleActivity(adapter, activityId) {
4334
+ const liveActivity = adapter.getActivity(activityId);
4335
+ return liveActivity ? cloneCoreActivity(liveActivity) : null;
4336
+ }
3903
4337
  function applyFieldChanges(adapter, activityId, changes) {
3904
4338
  applyCanonicalPatch(adapter, activityId, changes.patch);
3905
4339
  for (const mutation of changes.cascadeMutations ?? []) {
@@ -3916,35 +4350,69 @@ function applyCanonicalPatch(adapter, activityId, patch) {
3916
4350
  setActivityFieldDynamic(adapter, activityId, key, value);
3917
4351
  }
3918
4352
  }
3919
- function buildActivityChanges(adapter, before, touched) {
4353
+ async function buildActivityChanges(adapter, before, touched, correlativeBefore) {
3920
4354
  const out = [];
4355
+ let processed = 0;
3921
4356
  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
- }
4357
+ processed += 1;
4358
+ if (processed % YIELD_EVERY_N_ENTRIES === 0) await yieldToBrowser();
4359
+ const entry = buildEntryForTouchedId(
4360
+ adapter,
4361
+ before,
4362
+ id,
4363
+ correlativeBefore
4364
+ );
4365
+ if (entry) out.push(entry);
3945
4366
  }
3946
4367
  return out;
3947
4368
  }
4369
+ function buildEntryForTouchedId(adapter, before, activityId, correlativeBefore) {
4370
+ const afterSnap = adapter.getActivity(activityId);
4371
+ if (!afterSnap) {
4372
+ return { id: activityId, kind: "deleted", after: null };
4373
+ }
4374
+ const beforeSnap = before.get(activityId);
4375
+ if (!beforeSnap && correlativeBefore?.has(activityId)) {
4376
+ return buildCorrelativeOnlyEntry(
4377
+ activityId,
4378
+ correlativeBefore.get(activityId),
4379
+ afterSnap
4380
+ );
4381
+ }
4382
+ const diff = diffActivity(beforeSnap, afterSnap);
4383
+ mergeCorrelativeShiftIntoDiff(diff, correlativeBefore, activityId, afterSnap);
4384
+ if (beforeSnap && Object.keys(diff).length === 0) return null;
4385
+ return {
4386
+ id: activityId,
4387
+ kind: beforeSnap ? "updated" : "created",
4388
+ fields: diff,
4389
+ after: structuredCloneActivity(afterSnap)
4390
+ };
4391
+ }
4392
+ function buildCorrelativeOnlyEntry(activityId, correlativeIdBefore, liveActivity) {
4393
+ if (correlativeIdBefore === liveActivity.correlativeId) return null;
4394
+ return {
4395
+ id: activityId,
4396
+ kind: "updated",
4397
+ fields: {
4398
+ correlativeId: {
4399
+ before: correlativeIdBefore,
4400
+ after: liveActivity.correlativeId
4401
+ }
4402
+ },
4403
+ after: structuredCloneActivity(liveActivity)
4404
+ };
4405
+ }
4406
+ function mergeCorrelativeShiftIntoDiff(diff, correlativeBefore, activityId, liveActivity) {
4407
+ if (!correlativeBefore?.has(activityId)) return;
4408
+ if (Object.hasOwn(diff, "correlativeId")) return;
4409
+ const shiftedFrom = correlativeBefore.get(activityId);
4410
+ if (shiftedFrom === liveActivity.correlativeId) return;
4411
+ diff.correlativeId = {
4412
+ before: shiftedFrom,
4413
+ after: liveActivity.correlativeId
4414
+ };
4415
+ }
3948
4416
  function diffActivity(before, after) {
3949
4417
  const fields = {};
3950
4418
  const beforeRec = before ?? {};
@@ -3952,11 +4420,19 @@ function diffActivity(before, after) {
3952
4420
  const keys = /* @__PURE__ */ new Set([...Object.keys(beforeRec), ...Object.keys(afterRec)]);
3953
4421
  for (const k of keys) {
3954
4422
  if (Object.hasOwn(beforeRec, k) !== Object.hasOwn(afterRec, k) || !fieldValueEqual(beforeRec[k], afterRec[k])) {
3955
- fields[k] = { before: beforeRec[k], after: afterRec[k] };
4423
+ fields[k] = {
4424
+ before: cloneFieldValue(beforeRec[k]),
4425
+ after: cloneFieldValue(afterRec[k])
4426
+ };
3956
4427
  }
3957
4428
  }
3958
4429
  return fields;
3959
4430
  }
4431
+ function cloneFieldValue(value) {
4432
+ const isPrimitive = value === null || typeof value !== "object";
4433
+ if (isPrimitive) return value;
4434
+ return cloneDomainValue(value);
4435
+ }
3960
4436
  function fieldValueEqual(left, right) {
3961
4437
  if (Object.is(left, right)) return true;
3962
4438
  if (left instanceof Date && right instanceof Date) {
@@ -4633,12 +5109,6 @@ function mutateTheDateToFutureOrPastInBaseRestriction(dateBaseToCalculate, restr
4633
5109
 
4634
5110
  // src/critical-path/legacy/base/parents-calculations/forward.js
4635
5111
  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
5112
  constructor(linkedActivitiesData, activity, gantt) {
4643
5113
  this.linkedActivitiesData = linkedActivitiesData;
4644
5114
  this.activity = activity;
@@ -4650,10 +5120,6 @@ var CalculateForwardParentsWithLinks = class {
4650
5120
  );
4651
5121
  }
4652
5122
  }
4653
- /**
4654
- * Main method to perform the calculation.
4655
- * @returns {Object} The calculation result.
4656
- */
4657
5123
  calculate() {
4658
5124
  const calculationsFromLinks = this.calculateLinks();
4659
5125
  const maxEfFromLinks = getMaxEarlyStartSet(calculationsFromLinks);
@@ -4666,10 +5132,6 @@ var CalculateForwardParentsWithLinks = class {
4666
5132
  }
4667
5133
  return maxEfFromLinks;
4668
5134
  }
4669
- /**
4670
- * Calculates the dates based on the linked activities.
4671
- * @returns {Array<Object>} Array of calculation results from links.
4672
- */
4673
5135
  calculateLinks() {
4674
5136
  const calculations = [];
4675
5137
  for (const linkedActivity of this.linkedActivitiesData) {
@@ -4700,11 +5162,6 @@ var CalculateForwardParentsWithLinks = class {
4700
5162
  }
4701
5163
  return calculations;
4702
5164
  }
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
5165
  handleSNETConstraint(maxEfFromLinks) {
4709
5166
  const restriction = calculateRestrictionSnet({
4710
5167
  duration: this.activity.duration,
@@ -4717,11 +5174,6 @@ var CalculateForwardParentsWithLinks = class {
4717
5174
  }
4718
5175
  return maxEfFromLinks.ef > restriction.ef ? maxEfFromLinks : restriction;
4719
5176
  }
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
5177
  handleFNLTConstraint(maxEfFromLinks) {
4726
5178
  const restriction = calculateRestriction({
4727
5179
  duration: -this.activity.duration,
@@ -4734,11 +5186,6 @@ var CalculateForwardParentsWithLinks = class {
4734
5186
  }
4735
5187
  return maxEfFromLinks.ef > restriction.ef ? restriction : maxEfFromLinks;
4736
5188
  }
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
5189
  calculateSSLink({ lag, predecessorEs }) {
4743
5190
  const esLinked = mutateDate({
4744
5191
  linkType: "ss",
@@ -4769,11 +5216,6 @@ var CalculateForwardParentsWithLinks = class {
4769
5216
  );
4770
5217
  return { es, ef };
4771
5218
  }
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
5219
  calculateFFLink({ lag, predecessorEf }) {
4778
5220
  const efLinked = mutateDate({
4779
5221
  linkType: "ff",
@@ -4804,11 +5246,6 @@ var CalculateForwardParentsWithLinks = class {
4804
5246
  }
4805
5247
  return { es, ef };
4806
5248
  }
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
5249
  calculateFSLink({ lag, predecessorEf }) {
4813
5250
  let efLinked = predecessorEf;
4814
5251
  if (lag === 0) {
@@ -4833,11 +5270,6 @@ var CalculateForwardParentsWithLinks = class {
4833
5270
  );
4834
5271
  return { es, ef };
4835
5272
  }
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
5273
  calculateSFLink({ lag, predecessorEs }) {
4842
5274
  const ef = addDurationToDate(
4843
5275
  this.activityCalendar,
@@ -5143,14 +5575,6 @@ var CalculateBackwardParentsLinks = class {
5143
5575
  });
5144
5576
  return newDate;
5145
5577
  }
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
5578
  isActivityInInitHour(activityCalendar, date2) {
5155
5579
  const normalizedDate = date2 instanceof Date ? date2 : new Date(date2);
5156
5580
  const shifts = activityCalendar.getWorkHours(normalizedDate);
@@ -5491,22 +5915,12 @@ var calculation_of_parent_default = CalculationOfParent;
5491
5915
 
5492
5916
  // src/critical-path/legacy/base/third-level-activities/index.js
5493
5917
  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
5918
  constructor({ gantt, linkProperty }) {
5502
5919
  this.gantt = gantt;
5503
5920
  this.linkProperty = linkProperty;
5504
5921
  this.structureOfParents = /* @__PURE__ */ new Map();
5505
5922
  this.singleParents = /* @__PURE__ */ new Map();
5506
5923
  }
5507
- /**
5508
- * Identifies third-level activities and populates the structureOfParents map.
5509
- */
5510
5924
  identifyThirdLevelActivities() {
5511
5925
  try {
5512
5926
  const parents = this.getFirstLevelParents();
@@ -5531,18 +5945,9 @@ var ThirdLevelActivityIdentifier = class {
5531
5945
  throw e;
5532
5946
  }
5533
5947
  }
5534
- /**
5535
- * Retrieves the first-level parent tasks.
5536
- * @returns {Array<Object>} Array of parent tasks.
5537
- */
5538
5948
  getFirstLevelParents() {
5539
5949
  return this.gantt.getTaskByTime().filter(filters_default.byFirstLevel).filter(filters_default.filterByParentType);
5540
5950
  }
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
5951
  processEachActivity(parentActivity) {
5547
5952
  const parentsIds = /* @__PURE__ */ new Set();
5548
5953
  const allTasks = /* @__PURE__ */ new Set();
@@ -5557,10 +5962,6 @@ var ThirdLevelActivityIdentifier = class {
5557
5962
  activitiesByLevel
5558
5963
  };
5559
5964
  }
5560
- /**
5561
- * Initializes the parent activity in singleParents map.
5562
- * @param {Object} parentActivity - The parent activity.
5563
- */
5564
5965
  initializeParent(parentActivity) {
5565
5966
  const parentId = Number(parentActivity.id);
5566
5967
  const hasLink = Boolean(parentActivity[this.linkProperty]?.length);
@@ -5571,13 +5972,6 @@ var ThirdLevelActivityIdentifier = class {
5571
5972
  childrens: []
5572
5973
  });
5573
5974
  }
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
5975
  processActivity(activity, parentsIds, allTasks, activitiesByLevel) {
5582
5976
  const activityId = Number(activity.id);
5583
5977
  const parentId = Number(activity.parent);
@@ -5592,27 +5986,12 @@ var ThirdLevelActivityIdentifier = class {
5592
5986
  }
5593
5987
  this.addActivityToLevel(activity, activitiesByLevel);
5594
5988
  }
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
5989
  isProjectActivity(activity) {
5601
5990
  return activity.type === "project";
5602
5991
  }
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
5992
  hasLink(activity) {
5609
5993
  return Boolean(activity[this.linkProperty]?.length);
5610
5994
  }
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
5995
  addParentInfo(activity, parentsIds) {
5617
5996
  const parentId = Number(activity.id);
5618
5997
  const level = activity["$level"];
@@ -5625,27 +6004,12 @@ var ThirdLevelActivityIdentifier = class {
5625
6004
  parentsIds.add(parentId);
5626
6005
  this.singleParents.set(parentId, parentInfo);
5627
6006
  }
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
6007
  doesParentExist(parentId) {
5634
6008
  return this.singleParents.has(parentId);
5635
6009
  }
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
6010
  addChildToParent(parentId, activityId) {
5642
6011
  this.singleParents.get(parentId).childrens.push(activityId);
5643
6012
  }
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
6013
  addActivityToLevel(activity, activitiesByLevel) {
5650
6014
  const levelKey = activity["$level"];
5651
6015
  const parentKey = Number(activity.parent);
@@ -5662,33 +6026,15 @@ var ThirdLevelActivityIdentifier = class {
5662
6026
  calculated: false
5663
6027
  });
5664
6028
  }
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
6029
  getAllLevels(activitiesByLevel) {
5671
6030
  return new Set(activitiesByLevel.keys());
5672
6031
  }
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
6032
  getDeepestLevel(allLevels) {
5679
6033
  if (allLevels.size === 0) {
5680
6034
  return 0;
5681
6035
  }
5682
6036
  return Math.max(...allLevels);
5683
6037
  }
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
6038
  createResult(parent, processPayload, deepestLevel, allLevels) {
5693
6039
  const { activitiesByLevel, parentsIds, allTasks } = processPayload;
5694
6040
  return {
@@ -5854,22 +6200,6 @@ var CriticalPathHelpers = class {
5854
6200
  throw e;
5855
6201
  }
5856
6202
  }
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
6203
  identifyInitialActivities() {
5874
6204
  try {
5875
6205
  const {
@@ -5980,27 +6310,6 @@ var CriticalPathHelpers = class {
5980
6310
  }
5981
6311
  return sorted.reverse();
5982
6312
  }
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
6313
  calculateStartAndFinishOfChainOrigin(activityFromLink = null, customDirection = null) {
6005
6314
  try {
6006
6315
  let activity = activityFromLink;
@@ -6046,25 +6355,6 @@ var CriticalPathHelpers = class {
6046
6355
  throw e;
6047
6356
  }
6048
6357
  }
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
6358
  calculateBackwardWhenZeroProgress(activity, calendar) {
6069
6359
  let lateStart = moment_default(activity.start_date).clone();
6070
6360
  let lateFinish = moment_default(activity.end_date).clone();
@@ -6101,23 +6391,6 @@ var CriticalPathHelpers = class {
6101
6391
  lf: lateFinish
6102
6392
  };
6103
6393
  }
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
6394
  calculateWhenProgressIsBetweenZeroAndOneHundred(activity) {
6122
6395
  let lateStart = activity.start_date;
6123
6396
  let lateFinish = null;
@@ -6178,7 +6451,6 @@ var CriticalPathHelpers = class {
6178
6451
  throw e;
6179
6452
  }
6180
6453
  }
6181
- // Main function
6182
6454
  doCalculationForParentType(activity) {
6183
6455
  const calculationOfParent = new calculation_of_parent_default({
6184
6456
  activity,
@@ -6256,22 +6528,6 @@ var LinksRulesCalculationsMethods = class {
6256
6528
  this.parentsCalculations = calculationObject.parentsCalculations;
6257
6529
  this.gantt = calculationObject.ganttInstance;
6258
6530
  }
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
6531
  getEsAndEfFromPreviousCalculatedActivities(activity) {
6276
6532
  const isAlap = this.alapMap.has(activity);
6277
6533
  if (isAlap) {
@@ -6279,29 +6535,6 @@ var LinksRulesCalculationsMethods = class {
6279
6535
  }
6280
6536
  return this.calculatedActivities.get(Number(activity));
6281
6537
  }
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
6538
  calculateSucessorTimes(predecessorTime, esDataCalculation, efDataCalculation = 0, lag, restrictionOfLink = LINK_TYPES.FS) {
6306
6539
  const activityCalendar = this.gantt.getCalendar(
6307
6540
  this.referenceActivity.calendar_id
@@ -6374,27 +6607,6 @@ var LinksRulesCalculationsMethods = class {
6374
6607
  }
6375
6608
  return { es, ef };
6376
6609
  }
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
6610
  calculateSS(link) {
6399
6611
  const predecessorCalculatedEsAndEf = this.getEsAndEfFromPreviousCalculatedActivities(Number(link.source));
6400
6612
  const esDataCalculation = link.lag || 0;
@@ -6409,27 +6621,6 @@ var LinksRulesCalculationsMethods = class {
6409
6621
  LINK_TYPES.SS
6410
6622
  );
6411
6623
  }
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
6624
  calculateFF(link) {
6434
6625
  const predecessorCalculatedEsAndEf = this.getEsAndEfFromPreviousCalculatedActivities(Number(link.source));
6435
6626
  const duration = this.referenceActivity.duration;
@@ -6444,27 +6635,6 @@ var LinksRulesCalculationsMethods = class {
6444
6635
  LINK_TYPES.FF
6445
6636
  );
6446
6637
  }
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
6638
  calculateFS(link) {
6469
6639
  const predecessorCalculatedEsAndEf = this.getEsAndEfFromPreviousCalculatedActivities(Number(link.source));
6470
6640
  const esDataCalculation = link.lag || 0;
@@ -6479,27 +6649,6 @@ var LinksRulesCalculationsMethods = class {
6479
6649
  LINK_TYPES.FS
6480
6650
  );
6481
6651
  }
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
6652
  calculateSF(link) {
6504
6653
  const predecessorCalculatedEsAndEf = this.getEsAndEfFromPreviousCalculatedActivities(Number(link.source));
6505
6654
  const duration = this.referenceActivity.duration;
@@ -6514,24 +6663,6 @@ var LinksRulesCalculationsMethods = class {
6514
6663
  LINK_TYPES.SF
6515
6664
  );
6516
6665
  }
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
6666
  mutateTheDateToFutureOrPastInBaseRestriction(dateBaseToCalculate, restrictionOfLink, activityCalendar) {
6536
6667
  if (![LINK_TYPES.FS, LINK_TYPES.SS, LINK_TYPES.FF].includes(restrictionOfLink)) {
6537
6668
  return dateBaseToCalculate;
@@ -6555,22 +6686,6 @@ var LinksConstraintCalculator = class extends LinksRulesCalculationsMethods_defa
6555
6686
  constructor(calculationObject) {
6556
6687
  super(calculationObject);
6557
6688
  }
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
6689
  calculate() {
6575
6690
  if (this.links.length === 0) {
6576
6691
  return new generic_calculations_default(
@@ -6601,23 +6716,6 @@ var LinksConstraintCalculator = class extends LinksRulesCalculationsMethods_defa
6601
6716
  }
6602
6717
  return getMaxEarlyStartSet(allLinksCalculations);
6603
6718
  }
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
6719
  calculateLink(linkData) {
6622
6720
  const calculationMapping = {
6623
6721
  0: () => this.calculateFS(linkData),
@@ -6643,11 +6741,6 @@ var ActivityCalculator = class {
6643
6741
  this.linkProperty = options.linkProperty;
6644
6742
  this.linkDirection = options.linkDirection;
6645
6743
  }
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
6744
  checkActivitiesThatNowCanBeCalculated(pendingToCalculate) {
6652
6745
  const activitiesThatCanBeCalculated = /* @__PURE__ */ new Set();
6653
6746
  const pendingActivities = new Set(pendingToCalculate);
@@ -6674,9 +6767,6 @@ var ActivityCalculator = class {
6674
6767
  pendingActivities
6675
6768
  };
6676
6769
  }
6677
- /**
6678
- * Handles logic for project-type activities.
6679
- */
6680
6770
  handleProjectActivity(activityId, activityData, activitiesThatCanBeCalculated, pendingActivities) {
6681
6771
  const isPendingParentWithNoLinks = this.pendingParentsWithNoLinks.has(activityId);
6682
6772
  const isPendingParentWithLinks = this.pendingParentsWithLinks.has(activityId);
@@ -6717,9 +6807,6 @@ var ActivityCalculator = class {
6717
6807
  }
6718
6808
  }
6719
6809
  }
6720
- /**
6721
- * Determines if a parent activity can be calculated.
6722
- */
6723
6810
  canCalculateParentActivity(activityData) {
6724
6811
  const hasNoLinks = (activityData[this.linkProperty] || []).length === 0;
6725
6812
  const constraintType = activityData.constraint_type;
@@ -6734,9 +6821,6 @@ var ActivityCalculator = class {
6734
6821
  (activityId) => this.calculations.has(activityId)
6735
6822
  );
6736
6823
  }
6737
- /**
6738
- * Handles logic for non-project activities.
6739
- */
6740
6824
  handleNonProjectActivity(activityId, activityData, activitiesThatCanBeCalculated, pendingActivities) {
6741
6825
  const parentId = Number(activityData.parent);
6742
6826
  const isParentPendingWithLinks = this.pendingParentsWithLinks.has(parentId);
@@ -6774,9 +6858,6 @@ var ActivityCalculator = class {
6774
6858
  pendingActivities.delete(activityId);
6775
6859
  }
6776
6860
  }
6777
- /**
6778
- * Retrieves linked activities based on link property.
6779
- */
6780
6861
  getLinkedActivities(predecessors) {
6781
6862
  if (!Array.isArray(predecessors)) {
6782
6863
  return [];
@@ -6795,9 +6876,6 @@ var ActivityCalculator = class {
6795
6876
  }
6796
6877
  return linkedActivities;
6797
6878
  }
6798
- /**
6799
- * Retrieves an array of linked activity IDs.
6800
- */
6801
6879
  getArrayOfLinkedActivities(links) {
6802
6880
  if (!Array.isArray(links)) {
6803
6881
  return [];
@@ -6819,8 +6897,7 @@ var get_activities_to_calculate_default = ActivityCalculator;
6819
6897
  var createIsCurrent2 = (calculationId, getCurrentId) => () => getCurrentId() === calculationId;
6820
6898
 
6821
6899
  // 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;
6900
+ var shouldAbortCalculation = (gantt) => !gantt?.fullyParsed || typeof window !== "undefined" && window.to_use_react_gantt?.conversionMode?.isActive;
6824
6901
 
6825
6902
  // src/critical-path/legacy/utils/timing.js
6826
6903
  var TIME_BUDGET_MS = 16;
@@ -6932,24 +7009,6 @@ var ForwardPath = class extends generic_calculations_default {
6932
7009
  isCurrent
6933
7010
  });
6934
7011
  }
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
7012
  calculateStartAndFinishTimes(activitiesToCalculate) {
6954
7013
  activitiesToCalculate.forEach((activity) => {
6955
7014
  const activityReference = this.gantt.getTask(activity);
@@ -7070,13 +7129,6 @@ var ForwardPath = class extends generic_calculations_default {
7070
7129
  this.activitiesWaitingForCalculation.delete(activity);
7071
7130
  });
7072
7131
  }
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
7132
  getTheGreatesDateBetweenRestrictionAndEsEf(restriction, linkCalculation, comparisonType = "greater") {
7081
7133
  if (comparisonType === "greater") {
7082
7134
  return linkCalculation.ef > restriction.ef ? linkCalculation : restriction;
@@ -7085,34 +7137,18 @@ var ForwardPath = class extends generic_calculations_default {
7085
7137
  return linkCalculation.ef < restriction.ef ? linkCalculation : restriction;
7086
7138
  }
7087
7139
  }
7088
- /**
7089
- * Set ES and EF dates for an activity with full progress.
7090
- * @param {Object} activity - The activity object.
7091
- */
7092
7140
  setDatesForActivityWithFullProgress(activity) {
7093
7141
  this.calculations.set(activity.id, {
7094
7142
  es: activity.start_date,
7095
7143
  ef: activity.end_date
7096
7144
  });
7097
7145
  }
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
7146
  getDatesForActivityWithZeroProgress(activity) {
7104
7147
  return {
7105
7148
  es: activity.start_date,
7106
7149
  ef: activity.end_date
7107
7150
  };
7108
7151
  }
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
7152
  recalculateInBaseConstraint(constraintType, calculatedRestriction, calculatedEsEf) {
7117
7153
  const comparisontype = [
7118
7154
  CONSTRAINT_TYPES.SNET,
@@ -7152,30 +7188,12 @@ var CalculationsGenericMethods = class {
7152
7188
  this.forwardPathCalculations = calculationObject.calculatedForwardActivitiesMap;
7153
7189
  this.gantt = calculationObject.ganttInstance;
7154
7190
  }
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
7191
  getForwardOrBackwardCalculations(activity, constraint = null) {
7164
7192
  if (constraint === CONSTRAINT_TYPES.ALAP) {
7165
7193
  return this.forwardPathCalculations.get(activity);
7166
7194
  }
7167
7195
  return this.calculatedActivities.get(activity);
7168
7196
  }
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
7197
  calculateSuccessorTimes(sucessorTime, lsDataCalculation, lfDataCalculation = 0, lag, type = LINK_TYPES.FS) {
7180
7198
  let activityCalendar = this.gantt.getCalendar(this.activity.calendar_id);
7181
7199
  if (!activityCalendar) {
@@ -7225,13 +7243,6 @@ var CalculationsGenericMethods = class {
7225
7243
  return { ls, lf };
7226
7244
  }
7227
7245
  }
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
7246
  calculateSS(link, alap = false) {
7236
7247
  let lsSuc = this.getValueForSS(link, alap);
7237
7248
  let lsDataForCalculation = -link.lag || 0;
@@ -7245,12 +7256,6 @@ var CalculationsGenericMethods = class {
7245
7256
  LINK_TYPES.SS
7246
7257
  );
7247
7258
  }
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
7259
  calculateFF(link, constraint) {
7255
7260
  const succesorDate = this.getForwardOrBackwardCalculations(
7256
7261
  Number(link.target)
@@ -7268,13 +7273,6 @@ var CalculationsGenericMethods = class {
7268
7273
  LINK_TYPES.FF
7269
7274
  );
7270
7275
  }
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
7276
  calculateFS(link, constraint) {
7279
7277
  let propertyToCalculate = "ls";
7280
7278
  propertyToCalculate = constraint === CONSTRAINT_TYPES.ALAP ? "es" : "ls";
@@ -7293,13 +7291,6 @@ var CalculationsGenericMethods = class {
7293
7291
  LINK_TYPES.FS
7294
7292
  );
7295
7293
  }
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
7294
  calculateSF(link, getFromForward = false) {
7304
7295
  let lateFinishSucessor = getFromForward ? this.getEarlyStartFromForwardPath(Number(link.target)).ef : this.getForwardOrBackwardCalculations(Number(link.target)).lf;
7305
7296
  let lsDataForCalculation = -link.lag || 0;
@@ -7313,19 +7304,9 @@ var CalculationsGenericMethods = class {
7313
7304
  LINK_TYPES.SF
7314
7305
  );
7315
7306
  }
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
7307
  getEarlyStartFromForwardPath(link) {
7321
7308
  return this.forwardPathCalculations.get(link);
7322
7309
  }
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
7310
  getValueForSS(link, alap) {
7330
7311
  if (alap) {
7331
7312
  return this.getEarlyStartFromForwardPath(Number(link.target)).es;
@@ -7334,13 +7315,6 @@ var CalculationsGenericMethods = class {
7334
7315
  let sucessor = this.getForwardOrBackwardCalculations(Number(link.target));
7335
7316
  return sucessor[propertyToCalculate];
7336
7317
  }
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
7318
  calculateDate(activityCalendar, date2, duration) {
7345
7319
  let resetedDate = moment_default(date2).clone();
7346
7320
  return addDurationToDate(
@@ -7350,14 +7324,6 @@ var CalculationsGenericMethods = class {
7350
7324
  this.activity
7351
7325
  );
7352
7326
  }
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
7327
  getLastWorkingHour(date2, activityCalendar, dir = "past") {
7362
7328
  const normalizedDate = date2 instanceof Date ? date2 : new Date(date2);
7363
7329
  let resetedDate = moment_default(normalizedDate).clone();
@@ -7372,14 +7338,6 @@ var CalculationsGenericMethods = class {
7372
7338
  });
7373
7339
  return newDate;
7374
7340
  }
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
7341
  isActivityInInitHour(activityCalendar, date2) {
7384
7342
  const normalizedDate = date2 instanceof Date ? date2 : new Date(date2);
7385
7343
  const shifts = activityCalendar.getWorkHours(normalizedDate);
@@ -7398,17 +7356,6 @@ var CalculationsGenericMethods = class {
7398
7356
  }
7399
7357
  return normalizedDate.getUTCHours() === workStartHour;
7400
7358
  }
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
7359
  calculateFsLink({
7413
7360
  lag,
7414
7361
  workTime,
@@ -7461,16 +7408,6 @@ var CalculationsGenericMethods = class {
7461
7408
  }
7462
7409
  return { ls: lsPred, lf: lfPred };
7463
7410
  }
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
7411
  calculateFFLink({
7475
7412
  lag,
7476
7413
  workTime,
@@ -7517,19 +7454,6 @@ var CalculationsGenericMethods = class {
7517
7454
  );
7518
7455
  return { ls: lsPred, lf: lfPred };
7519
7456
  }
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
7457
  calculateSSlink({
7534
7458
  lag,
7535
7459
  workTime,
@@ -7577,17 +7501,6 @@ var CalculationsGenericMethods = class {
7577
7501
  );
7578
7502
  return { ls: lsPred, lf: lfPred };
7579
7503
  }
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
7504
  calculateSFLink({
7592
7505
  lag,
7593
7506
  workTime,
@@ -7634,23 +7547,6 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
7634
7547
  this.parentsThatImpactChildrens = calculationObject.parentsThatImpactChildrens;
7635
7548
  this.projectDates = this.gantt.getSubtaskDates();
7636
7549
  }
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
7550
  calculate() {
7655
7551
  if (this.links.length === 0) {
7656
7552
  return new generic_calculations_default(
@@ -7727,11 +7623,6 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
7727
7623
  minFromLinks: calculation
7728
7624
  };
7729
7625
  }
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
7626
  calculateTheLsAndLfForTheActivity(parentDates = null) {
7736
7627
  try {
7737
7628
  const duration = this.activity.duration;
@@ -7758,12 +7649,6 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
7758
7649
  throw Error(error.message);
7759
7650
  }
7760
7651
  }
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
7652
  SnetSnltMsoMinDate(minCalculatedDateFromLinks) {
7768
7653
  const minDateOfEndOfProjectAndLinks = Math.min(
7769
7654
  minCalculatedDateFromLinks.lf,
@@ -7773,12 +7658,6 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
7773
7658
  Math.max(minDateOfEndOfProjectAndLinks, this.activity.end_date)
7774
7659
  );
7775
7660
  }
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
7661
  calculateLink(linkData) {
7783
7662
  const activityFromLink = this.gantt.getTask(linkData.target);
7784
7663
  if (!activityFromLink) {
@@ -7798,29 +7677,17 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
7798
7677
  };
7799
7678
  return calculationMapping[linkData.type]();
7800
7679
  }
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
7680
  getSpecialCalculationParamForConstraintLink() {
7806
7681
  if (this.constraint === CONSTRAINT_TYPES.ALAP) return CONSTRAINT_TYPES.ALAP;
7807
7682
  if (this.constraint === CONSTRAINT_TYPES.FNET || this.constraint === CONSTRAINT_TYPES.SNET)
7808
7683
  return "snet-fnet";
7809
7684
  if (this.constraint === CONSTRAINT_TYPES.FNLT) return CONSTRAINT_TYPES.FNLT;
7810
7685
  }
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
7686
  getSpecialParamForSf() {
7816
7687
  const constriantThatNeedSpecialParam = [CONSTRAINT_TYPES.ALAP];
7817
7688
  if (constriantThatNeedSpecialParam.includes(this.constraint)) return true;
7818
7689
  return false;
7819
7690
  }
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
7691
  getSpecialParamForFF() {
7825
7692
  const constraintsThatNeedSpecialFFParam = [
7826
7693
  CONSTRAINT_TYPES.MFO,
@@ -7830,11 +7697,6 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
7830
7697
  return true;
7831
7698
  return false;
7832
7699
  }
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
7700
  getMinCalculationLogic(minCalculateFromLinks) {
7839
7701
  if (this.constraint === CONSTRAINT_TYPES.ALAP) {
7840
7702
  return this.getMinDateBasedOnConstraint(minCalculateFromLinks);
@@ -7855,11 +7717,6 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
7855
7717
  return this.getMinDateBasedOnConstraint(minCalculateFromLinks);
7856
7718
  }
7857
7719
  }
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
7720
  getMinDateFromLinks(allLinksCalculations) {
7864
7721
  try {
7865
7722
  if (this.constraint === CONSTRAINT_TYPES.ALAP || this.constraint === CONSTRAINT_TYPES.ASAP) {
@@ -7882,16 +7739,6 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
7882
7739
  (min, activity) => activity.lf < min.lf ? activity : min
7883
7740
  );
7884
7741
  }
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
7742
  getMinDateBasedOnConstraint(minCalculatedDateFromLinks, constraintType = this.constraint) {
7896
7743
  const minDateOfEndOfProjectAndLinks = Math.min(
7897
7744
  minCalculatedDateFromLinks.lf,
@@ -8042,23 +7889,6 @@ var BackwardPath = class extends generic_calculations_default {
8042
7889
  lf: maxLf
8043
7890
  });
8044
7891
  }
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
7892
  calculateStartAndFinishTimes(activitiesToCalculate) {
8063
7893
  activitiesToCalculate.forEach((activityId) => {
8064
7894
  let activityReference = this.gantt.getTask(activityId);
@@ -8136,29 +7966,6 @@ var BackwardPath = class extends generic_calculations_default {
8136
7966
  });
8137
7967
  });
8138
7968
  }
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
7969
  getTheLessLateInBasEsEfConstraint(activity, lfFromLinks, constraintType) {
8163
7970
  let esEfFromConstraint = this.forwardConstraintsMap.get(activity);
8164
7971
  if (!esEfFromConstraint) {
@@ -8177,23 +7984,6 @@ var BackwardPath = class extends generic_calculations_default {
8177
7984
  }
8178
7985
  return { ls: esEfFromConstraint.es, lf: esEfFromConstraint.ef };
8179
7986
  }
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
7987
  allLinkedActivitiesHasProgress(linkedActivities) {
8198
7988
  try {
8199
7989
  let allLinkedHasProgress = true;
@@ -8218,46 +8008,9 @@ var BackwardPath = class extends generic_calculations_default {
8218
8008
  throw new Error(error.message);
8219
8009
  }
8220
8010
  }
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
8011
  setDatesForActivityWithFullProgress(activity) {
8243
8012
  this.setCalculations(activity, activity.start_date, activity.end_date);
8244
8013
  }
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
8014
  setWhenAllLinkedActivitiesHasProgress(activity) {
8262
8015
  const parent = Number(activity.parent);
8263
8016
  let { ls, lf } = this.calculateStartAndFinishOfChainOrigin(
@@ -8274,23 +8027,6 @@ var BackwardPath = class extends generic_calculations_default {
8274
8027
  this.setCalculations(activity, ls, lf);
8275
8028
  return;
8276
8029
  }
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
8030
  setWhenActivitiesHasProgressButLessThanOneHundred(activity, constraintType) {
8295
8031
  if (constraintType === CONSTRAINT_TYPES.MSO) {
8296
8032
  this.setCalculations(activity, activity.start_date, activity.end_date);
@@ -8306,24 +8042,6 @@ var BackwardPath = class extends generic_calculations_default {
8306
8042
  return;
8307
8043
  }
8308
8044
  }
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
8045
  setCalculations(activity, ls, lf) {
8328
8046
  this.calculations.set(activity.id, {
8329
8047
  ls,
@@ -8331,28 +8049,6 @@ var BackwardPath = class extends generic_calculations_default {
8331
8049
  text: activity.text
8332
8050
  });
8333
8051
  }
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
8052
  calculateLfandLsFromLinks(linksWithSucessors, activityReference, constraintType, parentsWithFullProgress, parentsThatImpactChildrens) {
8357
8053
  return new LinksConstraintCalculator_default({
8358
8054
  links: linksWithSucessors,
@@ -8365,23 +8061,6 @@ var BackwardPath = class extends generic_calculations_default {
8365
8061
  ganttInstance: this.gantt
8366
8062
  }).calculate();
8367
8063
  }
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
8064
  recalculateInBaseRestriction(activity, constraintType) {
8386
8065
  try {
8387
8066
  const activityCalendar = this.gantt.getCalendar(activity.calendar_id);
@@ -9429,6 +9108,8 @@ var NON_SCHEDULING_KINDS = /* @__PURE__ */ new Set([
9429
9108
  "selection-toggle",
9430
9109
  "selection-replace",
9431
9110
  "visibility-set",
9111
+ "filter-set",
9112
+ "sort-set",
9432
9113
  "sir-sync",
9433
9114
  "activity-lookahead-sync",
9434
9115
  "persistence-acknowledge",
@@ -9436,6 +9117,16 @@ var NON_SCHEDULING_KINDS = /* @__PURE__ */ new Set([
9436
9117
  "ponderator-criterion-set",
9437
9118
  "status-criteria-set"
9438
9119
  ]);
9120
+ var PURE_VIEW_STATE_KINDS = /* @__PURE__ */ new Set([
9121
+ "selection-toggle",
9122
+ "selection-replace",
9123
+ "visibility-set",
9124
+ "filter-set",
9125
+ "sort-set"
9126
+ ]);
9127
+ function reappliesViewState(action) {
9128
+ return !PURE_VIEW_STATE_KINDS.has(action.kind);
9129
+ }
9439
9130
  var NO_STRUCTURAL_EXEMPTIONS = /* @__PURE__ */ new Set();
9440
9131
  function editsOnlyNonSchedulingColumns(action) {
9441
9132
  if (action.kind === "inline-edit") {
@@ -9744,7 +9435,7 @@ function detectSirAutoReject(beforeSnap, adapter, touchedIds) {
9744
9435
  }
9745
9436
 
9746
9437
  // src/dispatch/shared/change-set.ts
9747
- function assembleChangeSet(adapter, args) {
9438
+ async function assembleChangeSet(adapter, args) {
9748
9439
  const allTouched = collectChangeSetIds(adapter, args);
9749
9440
  const before = new Map(args.beforeSnap);
9750
9441
  const captured = adapter.peekWriteCapture();
@@ -9753,7 +9444,16 @@ function assembleChangeSet(adapter, args) {
9753
9444
  mergeDirtyBeforeImages(adapter, captured, insertedIds, before, allTouched);
9754
9445
  }
9755
9446
  const beforeDiffEffects = args.sirDetection === "before-diff" ? detectSirAutoReject(before, adapter, allTouched) : [];
9756
- const activityChanges = buildActivityChanges(adapter, before, allTouched);
9447
+ const correlativeBefore = buildCorrelativeBeforeMap(
9448
+ args.correlativeShifts,
9449
+ allTouched
9450
+ );
9451
+ const activityChanges = await buildActivityChanges(
9452
+ adapter,
9453
+ before,
9454
+ allTouched,
9455
+ correlativeBefore
9456
+ );
9757
9457
  const effects = args.sirDetection === "after-diff" ? detectSirAutoReject(before, adapter, allTouched) : beforeDiffEffects;
9758
9458
  const warnings = args.warnings ?? [];
9759
9459
  return {
@@ -9761,12 +9461,20 @@ function assembleChangeSet(adapter, args) {
9761
9461
  activities: activityChanges,
9762
9462
  links: args.links ?? [],
9763
9463
  calendars: [],
9764
- // dispatch never mutates calendars
9765
9464
  trackingEvents: args.trackingEvents ?? [],
9766
9465
  ...effects.length > 0 ? { effects } : {},
9767
9466
  ...warnings.length > 0 ? { warnings } : {}
9768
9467
  };
9769
9468
  }
9469
+ function buildCorrelativeBeforeMap(shifts, touched) {
9470
+ if (!shifts || shifts.length === 0) return void 0;
9471
+ const correlativeBefore = /* @__PURE__ */ new Map();
9472
+ for (const shift of shifts) {
9473
+ correlativeBefore.set(shift.activityId, shift.before);
9474
+ touched.add(shift.activityId);
9475
+ }
9476
+ return correlativeBefore;
9477
+ }
9770
9478
  function collectChangeSetIds(adapter, args) {
9771
9479
  const ids = /* @__PURE__ */ new Set();
9772
9480
  for (const id of args.touchedIds) ids.add(id);
@@ -9964,7 +9672,7 @@ async function dispatchInlineEdit(action, options, deps) {
9964
9672
  parsed2.raw
9965
9673
  );
9966
9674
  const touchedIds = collectTouchedIds(action.activityId, changes);
9967
- const beforeSnap = snapshotActivities(adapter, touchedIds);
9675
+ const beforeSnap = await snapshotActivities(adapter, touchedIds);
9968
9676
  const beforeLinkLags = snapshotIncomingLinkLags(
9969
9677
  adapter,
9970
9678
  String(action.activityId)
@@ -10036,7 +9744,7 @@ async function dispatchInlineEdit(action, options, deps) {
10036
9744
  );
10037
9745
  return {
10038
9746
  ok: true,
10039
- changes: assembleChangeSet(adapter, {
9747
+ changes: await assembleChangeSet(adapter, {
10040
9748
  source: action,
10041
9749
  beforeSnap,
10042
9750
  touchedIds,
@@ -10146,7 +9854,10 @@ async function dispatchLinkBatch(operations, source, options, deps, deterministi
10146
9854
  const { adapter, scheduler, sector, linkIdGen } = deps;
10147
9855
  scheduler.invalidateAllCaches();
10148
9856
  const { activityIds: affectedActivityIds, links: beforeLinks } = collectBatchContext(operations, adapter);
10149
- const beforeActivities = snapshotActivities(adapter, affectedActivityIds);
9857
+ const beforeActivities = await snapshotActivities(
9858
+ adapter,
9859
+ affectedActivityIds
9860
+ );
10150
9861
  const applied = applyBatchOperations(
10151
9862
  operations,
10152
9863
  adapter,
@@ -10189,7 +9900,7 @@ async function dispatchLinkBatch(operations, source, options, deps, deterministi
10189
9900
  }
10190
9901
  ),
10191
9902
  __beforeLinks: stringKeyedLinkSnapshots(beforeLinks),
10192
- changes: assembleChangeSet(adapter, {
9903
+ changes: await assembleChangeSet(adapter, {
10193
9904
  source,
10194
9905
  beforeSnap: beforeActivities,
10195
9906
  touchedIds: affectedActivityIds,
@@ -10285,85 +9996,6 @@ var DISPATCH_TRACK_EVENT = {
10285
9996
  ACTIVITY_OUTDENT: "schedule_activity_outdent"
10286
9997
  };
10287
9998
 
10288
- // src/internal/hierarchy/visual-order.ts
10289
- var NOT_SET_SORT_VALUE = Number.MAX_SAFE_INTEGER;
10290
- function getChildrenInVisualOrder(parentId, adapter) {
10291
- const children = collectChildrenSnapshots(parentId, adapter);
10292
- children.sort(compareActivitiesInVisualOrder);
10293
- return children.map((a) => String(a.id));
10294
- }
10295
- function iterateInVisualOrder(adapter) {
10296
- const result = [];
10297
- const visit = (activity) => {
10298
- result.push(activity);
10299
- const childIds = getChildrenInVisualOrder(String(activity.id), adapter);
10300
- for (const childId of childIds) {
10301
- const child = adapter.getActivity(childId);
10302
- if (child) visit(child);
10303
- }
10304
- };
10305
- const rootIds = getChildrenInVisualOrder(ROOT_PARENT_ID, adapter);
10306
- for (const rootId of rootIds) {
10307
- const root = adapter.getActivity(rootId);
10308
- if (root) visit(root);
10309
- }
10310
- return result;
10311
- }
10312
- function findPreviousNonSelectedSibling(taskId, selected, adapter) {
10313
- const activity = adapter.getActivity(taskId);
10314
- if (!activity) return null;
10315
- const parentKey = parentKeyOf(activity);
10316
- const siblings = getChildrenInVisualOrder(parentKey, adapter);
10317
- const idx = siblings.findIndex((id) => String(id) === String(taskId));
10318
- if (idx <= 0) return null;
10319
- for (let i = idx - 1; i >= 0; i--) {
10320
- const candidateId = siblings[i];
10321
- if (candidateId === void 0) continue;
10322
- if (!setHas(selected, candidateId)) return candidateId;
10323
- }
10324
- return null;
10325
- }
10326
- function visualIndexInParent(taskId, adapter) {
10327
- const activity = adapter.getActivity(taskId);
10328
- if (!activity) return -1;
10329
- const parentKey = parentKeyOf(activity);
10330
- const siblings = getChildrenInVisualOrder(parentKey, adapter);
10331
- return siblings.findIndex((id) => String(id) === String(taskId));
10332
- }
10333
- function collectChildrenSnapshots(parentId, adapter) {
10334
- const key = String(parentId);
10335
- if (key === "0") {
10336
- return adapter.getAllActivities().filter((a) => a.parentId === null);
10337
- }
10338
- const childIds = adapter.getChildren(parentId);
10339
- const out = [];
10340
- for (const id of childIds) {
10341
- const snap = adapter.getActivity(id);
10342
- if (snap) out.push(snap);
10343
- }
10344
- return out;
10345
- }
10346
- function compareActivitiesInVisualOrder(a, b) {
10347
- const ac = correlativeIdOf(a);
10348
- const bc = correlativeIdOf(b);
10349
- if (ac !== bc) return ac - bc;
10350
- return String(a.id).localeCompare(String(b.id));
10351
- }
10352
- function correlativeIdOf(activity) {
10353
- const raw = activity.correlativeId;
10354
- const n = typeof raw === "number" ? raw : Number(raw);
10355
- return Number.isFinite(n) ? n : NOT_SET_SORT_VALUE;
10356
- }
10357
- function parentKeyOf(activity) {
10358
- const parentId = activity.parentId;
10359
- if (parentId === null) return "0";
10360
- return parentId;
10361
- }
10362
- function setHas(set, id) {
10363
- if (set.has(id)) return true;
10364
- return set.has(String(id));
10365
- }
10366
-
10367
9999
  // src/internal/hierarchy/recompute-correlative-ids.ts
10368
10000
  function recomputeCorrelativeIds(adapter) {
10369
10001
  adapter.invalidateVisualOrderIds?.();
@@ -10796,7 +10428,7 @@ function computeFractionalCidAtIndex(adapter, parentKey, targetIndex, excludeId)
10796
10428
  }
10797
10429
 
10798
10430
  // src/dispatch/handlers/activity-create.ts
10799
- function createActivityCore(action, deps, opts = {}) {
10431
+ async function createActivityCore(action, deps, opts = {}) {
10800
10432
  const { adapter, scheduler, sector, calendars, activityIdGen, uidGen } = deps;
10801
10433
  scheduler.invalidateAllCaches();
10802
10434
  const target = validateCreateTarget(action, adapter);
@@ -10837,7 +10469,7 @@ function createActivityCore(action, deps, opts = {}) {
10837
10469
  const initialTouched = /* @__PURE__ */ new Set([newId]);
10838
10470
  if (parent) initialTouched.add(parent.id);
10839
10471
  const parentWasLeaf = parent !== null && adapter.getChildren(parent.id).length === 0;
10840
- const beforeSnap = opts.skipBeforeSnap ? /* @__PURE__ */ new Map() : snapshotActivities(adapter, initialTouched);
10472
+ const beforeSnap = opts.skipBeforeSnap ? /* @__PURE__ */ new Map() : await snapshotActivities(adapter, initialTouched);
10841
10473
  adapter.addActivity(newActivity);
10842
10474
  applyParentMutations(
10843
10475
  action,
@@ -10957,7 +10589,7 @@ function recomputeAndFoldCorrelatives(adapter, newId, beforeSnap, initialTouched
10957
10589
  initialTouched
10958
10590
  );
10959
10591
  }
10960
- function buildCreateChangeSet(adapter, action, coreResult, scheduledIds, hoursPerDay) {
10592
+ async function buildCreateChangeSet(adapter, action, coreResult, scheduledIds, hoursPerDay) {
10961
10593
  const { newId, newActivity, beforeSnap, initialTouched } = coreResult;
10962
10594
  const trackingEvent = {
10963
10595
  name: DISPATCH_TRACK_EVENT.ACTIVITY_CREATION,
@@ -10979,7 +10611,7 @@ function buildCreateChangeSet(adapter, action, coreResult, scheduledIds, hoursPe
10979
10611
  }
10980
10612
  async function dispatchActivityCreate(action, options, deps) {
10981
10613
  const { adapter, scheduler, sector } = deps;
10982
- const core = createActivityCore(action, deps);
10614
+ const core = await createActivityCore(action, deps);
10983
10615
  if (!core.ok) return core;
10984
10616
  const { newId } = core;
10985
10617
  const createdAutoScheduling = core.newActivity.autoScheduling;
@@ -11005,7 +10637,7 @@ async function dispatchActivityCreate(action, options, deps) {
11005
10637
  adapter.setActivityField(newId, "autoScheduling", createdAutoScheduling);
11006
10638
  }
11007
10639
  const { scheduledIds } = scheduleOutcome;
11008
- const changeset = buildCreateChangeSet(
10640
+ const changeset = await buildCreateChangeSet(
11009
10641
  adapter,
11010
10642
  action,
11011
10643
  core,
@@ -11055,7 +10687,7 @@ async function dispatchActivityPaste(action, options, deps) {
11055
10687
  const { adapter, scheduler, sector } = deps;
11056
10688
  const rootDest = resolvePasteRootDestination(action.destination, adapter);
11057
10689
  if (!rootDest.ok) return rootDest;
11058
- const beforeSnap = snapshotActivities(adapter, /* @__PURE__ */ new Set());
10690
+ const beforeSnap = await snapshotActivities(adapter, /* @__PURE__ */ new Set());
11059
10691
  const touched = /* @__PURE__ */ new Set();
11060
10692
  const originalToNew = /* @__PURE__ */ new Map();
11061
10693
  const createdIds = [];
@@ -11076,7 +10708,7 @@ async function dispatchActivityPaste(action, options, deps) {
11076
10708
  afterSiblingId = prevRootId;
11077
10709
  }
11078
10710
  }
11079
- const core = createActivityCore(
10711
+ const core = await createActivityCore(
11080
10712
  {
11081
10713
  parentId,
11082
10714
  afterSiblingId,
@@ -11087,16 +10719,8 @@ async function dispatchActivityPaste(action, options, deps) {
11087
10719
  },
11088
10720
  deps,
11089
10721
  {
11090
- // Saltamos el recompute por-create: corre UNA vez tras el loop (abajo).
11091
10722
  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
10723
  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
10724
  ...mappedParent !== void 0 ? {
11101
10725
  customIdReferenceId: action.referenceActivityId,
11102
10726
  preserveParentCustomId: true
@@ -11140,9 +10764,6 @@ async function dispatchActivityPaste(action, options, deps) {
11140
10764
  source: newSource,
11141
10765
  target: newTarget,
11142
10766
  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
10767
  lag: lagDaysToHours(link.lag, sector.hoursPerDay)
11147
10768
  };
11148
10769
  const res = applyLinkOperation(op, {
@@ -11177,7 +10798,7 @@ async function dispatchActivityPaste(action, options, deps) {
11177
10798
  );
11178
10799
  return {
11179
10800
  ok: true,
11180
- changes: assembleChangeSet(adapter, {
10801
+ changes: await assembleChangeSet(adapter, {
11181
10802
  source: action,
11182
10803
  beforeSnap,
11183
10804
  touchedIds: touched,
@@ -11389,6 +11010,7 @@ function buildParentNewActivitiesCleanup(input) {
11389
11010
  }
11390
11011
 
11391
11012
  // src/dispatch/handlers/activity-delete.ts
11013
+ var DELETE_YIELD_EVERY_N = 200;
11392
11014
  async function dispatchActivityDelete(action, options, deps) {
11393
11015
  const { adapter, scheduler, customIdTracker, sector } = deps;
11394
11016
  scheduler.invalidateAllCaches();
@@ -11412,14 +11034,17 @@ async function dispatchActivityDelete(action, options, deps) {
11412
11034
  if (!toDelete.has(parentKey)) parentsToCheck.add(parentKey);
11413
11035
  }
11414
11036
  const touchedIds = /* @__PURE__ */ new Set([...toDelete, ...parentsToCheck]);
11415
- const beforeSnap = snapshotActivities(adapter, touchedIds);
11037
+ const beforeSnap = await snapshotActivities(adapter, touchedIds);
11416
11038
  const beforeLinks = /* @__PURE__ */ new Map();
11417
11039
  for (const linkId of incidentLinkIds) {
11418
11040
  const l = adapter.getLink(linkId);
11419
11041
  if (l) beforeLinks.set(linkId, { ...l });
11420
11042
  }
11421
11043
  const newActivitiesToDelete = /* @__PURE__ */ new Set();
11044
+ let inspected = 0;
11422
11045
  for (const id of toDelete) {
11046
+ inspected += 1;
11047
+ if (inspected % DELETE_YIELD_EVERY_N === 0) await yieldToBrowser();
11423
11048
  const a = adapter.getActivity(id);
11424
11049
  if (!a) continue;
11425
11050
  const parent = isRootParent(a.parentId) ? null : adapter.getActivity(String(a.parentId));
@@ -11436,7 +11061,10 @@ async function dispatchActivityDelete(action, options, deps) {
11436
11061
  adapter.removeLink(linkId);
11437
11062
  }
11438
11063
  const viewStateChanges = captureDeletedViewState(adapter, toDelete);
11064
+ let removed = 0;
11439
11065
  for (const id of toDelete) {
11066
+ removed += 1;
11067
+ if (removed % DELETE_YIELD_EVERY_N === 0) await yieldToBrowser();
11440
11068
  adapter.removeActivity(id);
11441
11069
  }
11442
11070
  for (const parentId of parentsToCheck) {
@@ -11476,15 +11104,6 @@ async function dispatchActivityDelete(action, options, deps) {
11476
11104
  recomputeRollupCascadesForParent(parentId, adapter);
11477
11105
  }
11478
11106
  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
11107
  const { scheduledIds } = await runPostMutation(
11489
11108
  {
11490
11109
  adapter,
@@ -11517,7 +11136,7 @@ async function dispatchActivityDelete(action, options, deps) {
11517
11136
  const snap = beforeSnap.get(String(id));
11518
11137
  if (snap) deletedRowsSnap.set(String(id), snap);
11519
11138
  }
11520
- const changes = assembleChangeSet(adapter, {
11139
+ const changes = await assembleChangeSet(adapter, {
11521
11140
  source: action,
11522
11141
  beforeSnap,
11523
11142
  touchedIds,
@@ -11525,7 +11144,8 @@ async function dispatchActivityDelete(action, options, deps) {
11525
11144
  sirDetection: "after-diff",
11526
11145
  links: buildLinkDeletions(beforeLinks),
11527
11146
  trackingEvents: [trackingEvent],
11528
- hoursPerDay: sector.hoursPerDay
11147
+ hoursPerDay: sector.hoursPerDay,
11148
+ correlativeShifts
11529
11149
  });
11530
11150
  return {
11531
11151
  ok: true,
@@ -11565,8 +11185,6 @@ function buildLinkDeletions(beforeLinks) {
11565
11185
  source: { before: String(before.source), after: void 0 },
11566
11186
  target: { before: String(before.target), after: void 0 },
11567
11187
  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
11188
  lag: { before: Number(before.lag), after: void 0 }
11571
11189
  },
11572
11190
  after: null
@@ -11655,7 +11273,7 @@ async function dispatchActivityMove(action, options, deps) {
11655
11273
  } else {
11656
11274
  if (oldParentKey !== ROOT_PARENT_ID) touched.add(oldParentKey);
11657
11275
  }
11658
- const beforeSnap = snapshotActivities(adapter, touched);
11276
+ const beforeSnap = await snapshotActivities(adapter, touched);
11659
11277
  if (parentChanged) {
11660
11278
  adapter.setActivityField(
11661
11279
  action.activityId,
@@ -11685,8 +11303,6 @@ async function dispatchActivityMove(action, options, deps) {
11685
11303
  newChildId: action.activityId,
11686
11304
  getParent: (id) => adapter.getActivity(id) ?? null,
11687
11305
  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
11306
  promotionSource: "reparent"
11691
11307
  });
11692
11308
  if (promotion) {
@@ -11795,7 +11411,7 @@ async function dispatchActivityMove(action, options, deps) {
11795
11411
  }
11796
11412
  return {
11797
11413
  ok: true,
11798
- changes: assembleChangeSet(adapter, {
11414
+ changes: await assembleChangeSet(adapter, {
11799
11415
  source: action,
11800
11416
  beforeSnap,
11801
11417
  touchedIds: touched,
@@ -11857,7 +11473,7 @@ async function dispatchActivityIndent(action, options, deps) {
11857
11473
  touched.add(targetParentId);
11858
11474
  if (oldParentId !== ROOT_PARENT_ID) touched.add(oldParentId);
11859
11475
  }
11860
- const beforeSnap = snapshotActivities(adapter, touched);
11476
+ const beforeSnap = await snapshotActivities(adapter, touched);
11861
11477
  for (const { activityId, newParentId } of moves) {
11862
11478
  adapter.setActivityField(activityId, ACTIVITY_PROPERTY.PARENT, newParentId);
11863
11479
  adapter.setActivityField(
@@ -11881,8 +11497,6 @@ async function dispatchActivityIndent(action, options, deps) {
11881
11497
  newChildId: activityId,
11882
11498
  getParent: (id) => adapter.getActivity(id) ?? null,
11883
11499
  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
11500
  promotionSource: "reparent"
11887
11501
  });
11888
11502
  if (promotion) {
@@ -11949,33 +11563,8 @@ async function dispatchActivityIndent(action, options, deps) {
11949
11563
  },
11950
11564
  {
11951
11565
  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
11566
  autoscheduleFrom: null,
11969
11567
  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
11568
  now: deps.now,
11980
11569
  options
11981
11570
  }
@@ -12007,7 +11596,7 @@ async function dispatchActivityIndent(action, options, deps) {
12007
11596
  reason: failure.reason
12008
11597
  } : { activityId: String(activityId), ok: true };
12009
11598
  }),
12010
- changes: assembleChangeSet(adapter, {
11599
+ changes: await assembleChangeSet(adapter, {
12011
11600
  source: action,
12012
11601
  beforeSnap,
12013
11602
  touchedIds: touched,
@@ -12105,7 +11694,7 @@ async function dispatchActivityOutdent(action, options, deps) {
12105
11694
  if (grandparentKey !== ROOT_PARENT_ID) touched.add(String(grandparentKey));
12106
11695
  oldParents.add(oldParentKey);
12107
11696
  }
12108
- const beforeSnap = snapshotActivities(adapter, touched);
11697
+ const beforeSnap = await snapshotActivities(adapter, touched);
12109
11698
  for (const plan of planned) {
12110
11699
  adapter.setActivityField(
12111
11700
  plan.activityId,
@@ -12192,12 +11781,9 @@ async function dispatchActivityOutdent(action, options, deps) {
12192
11781
  defaultBaseCalendarId: deps.defaultBaseCalendarId
12193
11782
  },
12194
11783
  {
12195
- // Empty-batch gate: nothing moved → no autoscheduler pass (the
12196
- // unconditional parent-bounds rollup still runs).
12197
11784
  action,
12198
11785
  autoscheduleFrom: succeededIds.length > 0 ? "roots" : null,
12199
11786
  recomputeParentsFrom: succeededIds,
12200
- // activity-outdent is a structural reparent: leaves EP and CP stale.
12201
11787
  now: deps.now,
12202
11788
  options
12203
11789
  }
@@ -12227,7 +11813,7 @@ async function dispatchActivityOutdent(action, options, deps) {
12227
11813
  reason: failure.reason
12228
11814
  } : { activityId: String(activityId), ok: true };
12229
11815
  }),
12230
- changes: assembleChangeSet(adapter, {
11816
+ changes: await assembleChangeSet(adapter, {
12231
11817
  source: action,
12232
11818
  beforeSnap,
12233
11819
  touchedIds: touched,
@@ -12264,7 +11850,7 @@ async function dispatchActivitySetProgress(action, options, deps) {
12264
11850
  action.newValue
12265
11851
  );
12266
11852
  const touchedIds = collectTouchedIds(action.activityId, changes);
12267
- const beforeSnap = snapshotActivities(adapter, touchedIds);
11853
+ const beforeSnap = await snapshotActivities(adapter, touchedIds);
12268
11854
  applyFieldChanges(adapter, action.activityId, changes);
12269
11855
  runPostProcessorsOnAdapter(
12270
11856
  action.activityId,
@@ -12280,7 +11866,6 @@ async function dispatchActivitySetProgress(action, options, deps) {
12280
11866
  },
12281
11867
  {
12282
11868
  action,
12283
- // Pipeline gate: only schedule when the transform asked for it.
12284
11869
  autoscheduleFrom: changes.needsAutoSchedule ? action.activityId : null,
12285
11870
  recomputeParentsFrom: [],
12286
11871
  collectDirty: (sids) => collectDirtyForInlineEdit(action.activityId, touchedIds, sids),
@@ -12294,7 +11879,7 @@ async function dispatchActivitySetProgress(action, options, deps) {
12294
11879
  }));
12295
11880
  return {
12296
11881
  ok: true,
12297
- changes: assembleChangeSet(adapter, {
11882
+ changes: await assembleChangeSet(adapter, {
12298
11883
  source: action,
12299
11884
  beforeSnap,
12300
11885
  touchedIds,
@@ -12323,9 +11908,10 @@ async function dispatchDatesBatch(action, options, deps) {
12323
11908
  mergeBeforeSnapshots(beforeSnap, editTouched, deps);
12324
11909
  for (const id of editTouched) touchedIds.add(id);
12325
11910
  const beforeLinkLags = snapshotIncomingLinkLags(adapter, edit.activityId);
12326
- const preEditSnapshot = snapshotActivities(adapter, /* @__PURE__ */ new Set([String(edit.activityId)])).get(
11911
+ const preEditSnapshot = snapshotSingleActivity(
11912
+ adapter,
12327
11913
  String(edit.activityId)
12328
- ) ?? null;
11914
+ );
12329
11915
  applyFieldChanges(adapter, edit.activityId, outcome.changes);
12330
11916
  runPostProcessorsOnAdapter(
12331
11917
  edit.activityId,
@@ -12367,7 +11953,7 @@ async function dispatchDatesBatch(action, options, deps) {
12367
11953
  return {
12368
11954
  ok: true,
12369
11955
  verdicts,
12370
- changes: assembleChangeSet(adapter, {
11956
+ changes: await assembleChangeSet(adapter, {
12371
11957
  source: action,
12372
11958
  beforeSnap,
12373
11959
  touchedIds,
@@ -12448,8 +12034,11 @@ function mergeBeforeSnapshots(beforeSnap, ids, deps) {
12448
12034
  if (!beforeSnap.has(id)) missing.add(id);
12449
12035
  }
12450
12036
  if (missing.size === 0) return;
12451
- for (const [id, snap] of snapshotActivities(deps.adapter, missing)) {
12452
- beforeSnap.set(id, snap);
12037
+ for (const missingId of missing) {
12038
+ const liveActivity = deps.adapter.getActivity(missingId);
12039
+ if (liveActivity) {
12040
+ beforeSnap.set(missingId, structuredCloneActivity(liveActivity));
12041
+ }
12453
12042
  }
12454
12043
  }
12455
12044
 
@@ -12489,9 +12078,10 @@ async function dispatchBulkEdit(action, options, deps) {
12489
12078
  explicitDateEditActivities.add(String(edit.activityId));
12490
12079
  }
12491
12080
  const beforeLinkLags = snapshotIncomingLinkLags(adapter, edit.activityId);
12492
- const preEditSnapshot = snapshotActivities(adapter, /* @__PURE__ */ new Set([String(edit.activityId)])).get(
12081
+ const preEditSnapshot = snapshotSingleActivity(
12082
+ adapter,
12493
12083
  String(edit.activityId)
12494
- ) ?? null;
12084
+ );
12495
12085
  const customIdBeforeApply = readLiveCustomId(edit, deps);
12496
12086
  const changes = outcome.changes;
12497
12087
  applyFieldChanges(adapter, edit.activityId, changes);
@@ -12555,14 +12145,11 @@ async function dispatchBulkEdit(action, options, deps) {
12555
12145
  return {
12556
12146
  ok: true,
12557
12147
  verdicts,
12558
- changes: assembleChangeSet(adapter, {
12148
+ changes: await assembleChangeSet(adapter, {
12559
12149
  source: action,
12560
12150
  beforeSnap,
12561
12151
  touchedIds,
12562
12152
  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
12153
  sirDetection: "before-diff",
12567
12154
  links: linkChanges,
12568
12155
  trackingEvents,
@@ -12689,11 +12276,11 @@ function mergeBeforeSnapshots2(beforeSnap, ids, deps) {
12689
12276
  if (!beforeSnap.has(candidateId)) missing.add(candidateId);
12690
12277
  }
12691
12278
  if (missing.size === 0) return;
12692
- for (const [snappedId, snapshot] of snapshotActivities(
12693
- deps.adapter,
12694
- missing
12695
- )) {
12696
- beforeSnap.set(snappedId, snapshot);
12279
+ for (const missingId of missing) {
12280
+ const liveActivity = deps.adapter.getActivity(missingId);
12281
+ if (liveActivity) {
12282
+ beforeSnap.set(missingId, structuredCloneActivity(liveActivity));
12283
+ }
12697
12284
  }
12698
12285
  }
12699
12286
 
@@ -13117,8 +12704,8 @@ function activeBaselineSignature(deps) {
13117
12704
  })
13118
12705
  );
13119
12706
  }
13120
- function dispatchBaselineApply(action, deps) {
13121
- const beforeSnap = snapshotActivities(
12707
+ async function dispatchBaselineApply(action, deps) {
12708
+ const beforeSnap = await snapshotActivities(
13122
12709
  deps.adapter,
13123
12710
  new Set(deps.adapter.getAllIds())
13124
12711
  );
@@ -13138,7 +12725,7 @@ function dispatchBaselineApply(action, deps) {
13138
12725
  }
13139
12726
  return {
13140
12727
  ok: true,
13141
- changes: assembleChangeSet(deps.adapter, {
12728
+ changes: await assembleChangeSet(deps.adapter, {
13142
12729
  source: action,
13143
12730
  beforeSnap,
13144
12731
  touchedIds: changedIds,
@@ -13155,15 +12742,15 @@ function assertValidCriterion(value) {
13155
12742
  `ponderator-criterion-set: invalid criterion "${String(value)}"`
13156
12743
  );
13157
12744
  }
13158
- function dispatchPonderatorCriterionSet(action, deps) {
12745
+ async function dispatchPonderatorCriterionSet(action, deps) {
13159
12746
  assertValidCriterion(action.criterion);
13160
12747
  const allIds = new Set(deps.adapter.getAllIds());
13161
- const beforeSnap = snapshotActivities(deps.adapter, allIds);
12748
+ const beforeSnap = await snapshotActivities(deps.adapter, allIds);
13162
12749
  recomputeBaselineWeightedFields(deps, action.criterion);
13163
12750
  deps.sector.activityCreter = action.criterion;
13164
12751
  return {
13165
12752
  ok: true,
13166
- changes: assembleChangeSet(deps.adapter, {
12753
+ changes: await assembleChangeSet(deps.adapter, {
13167
12754
  source: action,
13168
12755
  beforeSnap,
13169
12756
  touchedIds: allIds,
@@ -13174,15 +12761,15 @@ function dispatchPonderatorCriterionSet(action, deps) {
13174
12761
  }
13175
12762
 
13176
12763
  // src/dispatch/handlers/status-criteria-set.ts
13177
- function dispatchStatusCriteriaSet(action, deps) {
12764
+ async function dispatchStatusCriteriaSet(action, deps) {
13178
12765
  const resolved = resolveStatusCriteria(action.criteria);
13179
12766
  const allIds = new Set(deps.adapter.getAllIds());
13180
- const beforeSnap = snapshotActivities(deps.adapter, allIds);
12767
+ const beforeSnap = await snapshotActivities(deps.adapter, allIds);
13181
12768
  const changedIds = applyStatusPass(deps.adapter, resolved);
13182
12769
  deps.sector.statusCriteria = resolved;
13183
12770
  return {
13184
12771
  ok: true,
13185
- changes: assembleChangeSet(deps.adapter, {
12772
+ changes: await assembleChangeSet(deps.adapter, {
13186
12773
  source: action,
13187
12774
  beforeSnap,
13188
12775
  touchedIds: changedIds,
@@ -13248,6 +12835,15 @@ async function dispatch(action, options, deps) {
13248
12835
  if (action.kind === "visibility-set") {
13249
12836
  return dispatchVisibilitySet(action, selectionDeps(deps));
13250
12837
  }
12838
+ if (action.kind === "filter-set") {
12839
+ return dispatchFilterSet(action, {
12840
+ adapter: deps.adapter,
12841
+ hoursPerDay: deps.sector.hoursPerDay
12842
+ });
12843
+ }
12844
+ if (action.kind === "sort-set") {
12845
+ return dispatchSortSet(action, { adapter: deps.adapter });
12846
+ }
13251
12847
  if (action.kind === "sir-sync") {
13252
12848
  return dispatchSirSync(action, deps);
13253
12849
  }
@@ -15770,9 +15366,7 @@ var defaultLocale = {
15770
15366
  function createGanttShim(options = {}) {
15771
15367
  const userConfig = options.config || {};
15772
15368
  const shim = {
15773
- // ------ Config ------
15774
15369
  config: Object.assign({
15775
- // Defaults críticos para calendar
15776
15370
  duration_unit: "hour",
15777
15371
  duration_step: 1,
15778
15372
  work_time: false,
@@ -15783,16 +15377,13 @@ function createGanttShim(options = {}) {
15783
15377
  resource_property: "resource_id",
15784
15378
  resource_calendars: {},
15785
15379
  dynamic_resource_calendars: false,
15786
- // Config date module
15787
15380
  start_on_monday: true,
15788
15381
  server_utc: true,
15789
15382
  csp: "auto",
15790
15383
  show_errors: false
15791
15384
  }, userConfig),
15792
- // ------ Locale + templates ------
15793
15385
  locale: options.locale || defaultLocale,
15794
15386
  templates: options.templates || {},
15795
- // ------ Task resolver (opcional) ------
15796
15387
  getTask: options.getTask || function(id) {
15797
15388
  return null;
15798
15389
  },
@@ -15802,11 +15393,9 @@ function createGanttShim(options = {}) {
15802
15393
  isSummaryTask: options.isSummaryTask || function(task) {
15803
15394
  return false;
15804
15395
  },
15805
- // ------ State (mínimo) ------
15806
15396
  getState: function() {
15807
15397
  return { group_mode: false };
15808
15398
  },
15809
- // ------ Eventable (no-ops por defecto) ------
15810
15399
  callEvent: function(name, args) {
15811
15400
  const handler = options.onEvent;
15812
15401
  if (handler) handler(name, args);
@@ -15820,7 +15409,6 @@ function createGanttShim(options = {}) {
15820
15409
  },
15821
15410
  detachEvent: function() {
15822
15411
  },
15823
- // ------ Utils expuestas en gantt2 ------
15824
15412
  defined,
15825
15413
  mixin,
15826
15414
  copy,
@@ -15830,7 +15418,6 @@ function createGanttShim(options = {}) {
15830
15418
  else if (options.silent !== true) console.error("[calendar]", msg);
15831
15419
  }
15832
15420
  },
15833
- // ------ $services / $ui — stubs minimales para evitar cracks ------
15834
15421
  $services: { getService: function() {
15835
15422
  return null;
15836
15423
  } },
@@ -15851,7 +15438,6 @@ function createGanttShim(options = {}) {
15851
15438
  function createCalendar(options = {}) {
15852
15439
  const shim = createGanttShim(options);
15853
15440
  return {
15854
- // ------ Gestión de calendarios ------
15855
15441
  addCalendar: function(c) {
15856
15442
  return shim.addCalendar(c);
15857
15443
  },
@@ -15873,7 +15459,6 @@ function createCalendar(options = {}) {
15873
15459
  getResourceCalendar: function(r) {
15874
15460
  return shim.getResourceCalendar(r);
15875
15461
  },
15876
- // ------ Cálculo (también disponible en cada Calendar instance) ------
15877
15462
  setWorkTime: function(c) {
15878
15463
  return shim.setWorkTime(c);
15879
15464
  },
@@ -15895,7 +15480,6 @@ function createCalendar(options = {}) {
15895
15480
  calculateEndDate: function() {
15896
15481
  return shim.calculateEndDate.apply(shim, arguments);
15897
15482
  },
15898
- // ------ Para inspección/debug ------
15899
15483
  _internals: shim
15900
15484
  };
15901
15485
  }
@@ -15923,16 +15507,11 @@ function normalizeWorktimeHours(hours) {
15923
15507
  return [`${first}:00-${last + 1}:00`];
15924
15508
  }
15925
15509
  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
15510
  hours: ["8:00-16:00"],
15929
15511
  days: [false, true, true, true, true, true, false]
15930
15512
  };
15931
15513
  var CATALOG_ONLY_CALENDAR_ID = "__main_global__";
15932
15514
  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
15515
  hours: ["8:00-12:00", "13:00-17:00"],
15937
15516
  days: [false, true, true, true, true, true, false]
15938
15517
  };
@@ -16124,7 +15703,6 @@ var WriteCapture = class {
16124
15703
  end() {
16125
15704
  this._journal = null;
16126
15705
  }
16127
- /** Field write on an activity — pre-mutation clone on first write per id. */
16128
15706
  note(key, current) {
16129
15707
  const journal = this._journal;
16130
15708
  if (!journal) return;
@@ -16152,13 +15730,11 @@ var WriteCapture = class {
16152
15730
  before: cloneLink(current)
16153
15731
  });
16154
15732
  }
16155
- /** Pre-sweep correlative_id of an activity the renumbering shifted (first-wins). */
16156
15733
  noteCorrelativeBefore(activityId, before) {
16157
15734
  const journal = this._journal;
16158
15735
  if (!journal || journal.correlativeBefore.has(activityId)) return;
16159
15736
  journal.correlativeBefore.set(activityId, before);
16160
15737
  }
16161
- /** Pre-applyResults clone of an activity the autoscheduler will move (first-wins). */
16162
15738
  noteScheduledBefore(activityId, current) {
16163
15739
  const journal = this._journal;
16164
15740
  if (!journal) return;
@@ -16171,7 +15747,6 @@ var WriteCapture = class {
16171
15747
  }
16172
15748
  journal.dirty.add(activityId);
16173
15749
  }
16174
- /** Field write on a link — pre-mutation clone on first write per link id. */
16175
15750
  noteLinkField(linkId, current) {
16176
15751
  const journal = this._journal;
16177
15752
  if (!journal || journal.linkFieldCaptured.has(linkId)) return;
@@ -16189,17 +15764,11 @@ function cloneLink(link) {
16189
15764
 
16190
15765
  // src/internal/state/calendar-calculator.ts
16191
15766
  var CalendarCalculator = class {
16192
- // In-dispatch calendar API memoization. Lifetime = one scheduler run.
16193
15767
  _cache = {
16194
15768
  closestWorkTime: /* @__PURE__ */ new Map(),
16195
15769
  endDate: /* @__PURE__ */ new Map(),
16196
15770
  duration: /* @__PURE__ */ new Map()
16197
15771
  };
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
15772
  reader;
16204
15773
  constructor(setup) {
16205
15774
  this.reader = setup.reader;
@@ -16242,11 +15811,6 @@ var CalendarCalculator = class {
16242
15811
  )
16243
15812
  );
16244
15813
  }
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
15814
  clearCache() {
16251
15815
  this._cache.closestWorkTime.clear();
16252
15816
  this._cache.endDate.clear();
@@ -16279,16 +15843,7 @@ var HierarchyIndex = class {
16279
15843
  activities;
16280
15844
  _childrenByParent = /* @__PURE__ */ new Map();
16281
15845
  _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
15846
  _dirty = false;
16291
- /** Mark the children index stale; the next `getChildren` rebuilds it once. */
16292
15847
  markDirty() {
16293
15848
  this._dirty = true;
16294
15849
  }
@@ -16332,11 +15887,6 @@ var HierarchyIndex = class {
16332
15887
  getParentId(id) {
16333
15888
  return this.activities.get(id)?.parentId ?? null;
16334
15889
  }
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
15890
  addChild(parentId, id) {
16341
15891
  if (this._dirty) return;
16342
15892
  if (isRootParent(parentId)) {
@@ -16348,7 +15898,6 @@ var HierarchyIndex = class {
16348
15898
  if (arr) arr.push(id);
16349
15899
  else this._childrenByParent.set(key, [id]);
16350
15900
  }
16351
- /** Full rebuild from the activity store. */
16352
15901
  rebuild() {
16353
15902
  this._childrenByParent.clear();
16354
15903
  this._roots = [];
@@ -16381,12 +15930,29 @@ var HierarchyIndex = class {
16381
15930
  var ViewStateStore = class {
16382
15931
  checkedSet = /* @__PURE__ */ new Set();
16383
15932
  hiddenSet = /* @__PURE__ */ new Set();
15933
+ activeFilter = null;
15934
+ activeOrder = null;
16384
15935
  isChecked(activityId) {
16385
15936
  return this.checkedSet.has(activityId);
16386
15937
  }
16387
15938
  isVisible(activityId) {
16388
15939
  return !this.hiddenSet.has(activityId);
16389
15940
  }
15941
+ hiddenIds() {
15942
+ return [...this.hiddenSet];
15943
+ }
15944
+ getActiveFilter() {
15945
+ return this.activeFilter;
15946
+ }
15947
+ setActiveFilter(nextFilter) {
15948
+ this.activeFilter = nextFilter;
15949
+ }
15950
+ getActiveOrder() {
15951
+ return this.activeOrder;
15952
+ }
15953
+ setActiveOrder(nextOrder) {
15954
+ this.activeOrder = nextOrder;
15955
+ }
16390
15956
  checkedIds() {
16391
15957
  return [...this.checkedSet];
16392
15958
  }
@@ -16412,58 +15978,49 @@ var ViewStateStore = class {
16412
15978
  hydrate(seed2) {
16413
15979
  this.checkedSet = new Set(seed2.checkedIds ?? []);
16414
15980
  this.hiddenSet = new Set(seed2.hiddenIds ?? []);
15981
+ this.activeFilter = null;
15982
+ this.activeOrder = null;
16415
15983
  }
16416
15984
  snapshot() {
16417
15985
  return {
16418
15986
  checked: new Set(this.checkedSet),
16419
- hidden: new Set(this.hiddenSet)
15987
+ hidden: new Set(this.hiddenSet),
15988
+ activeFilter: this.activeFilter,
15989
+ activeOrder: this.activeOrder
16420
15990
  };
16421
15991
  }
16422
15992
  restore(snapshot) {
16423
15993
  this.checkedSet = new Set(snapshot.checked);
16424
15994
  this.hiddenSet = new Set(snapshot.hidden);
15995
+ this.activeFilter = snapshot.activeFilter;
15996
+ this.activeOrder = snapshot.activeOrder;
16425
15997
  }
16426
15998
  };
16427
15999
 
16428
16000
  // src/internal/state/schedule-state.ts
16429
16001
  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
16002
  _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
16003
  _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
16004
  _promotionSnapshot = /* @__PURE__ */ new Map();
16446
16005
  _links = /* @__PURE__ */ new Map();
16447
16006
  _outgoing = /* @__PURE__ */ new Map();
16448
16007
  _incoming = /* @__PURE__ */ new Map();
16449
- // Parent → children index. Assigned in the constructor (needs the
16450
- // activities Map reference). See `HierarchyIndex`.
16451
16008
  _hierarchy;
16009
+ _buildOrderComparator;
16452
16010
  _cache = {
16453
16011
  ids: null,
16454
- visualOrderIds: null
16012
+ visualOrderIds: null,
16013
+ orderComparator: null
16455
16014
  };
16456
- // Per-dispatch write journal. See `WriteCapture` / `ActivityWriteCapture`.
16457
16015
  _writeCapture = new WriteCapture();
16458
16016
  _viewState = new ViewStateStore();
16459
16017
  _viewStateBefore = null;
16460
16018
  _lastStartDateBefore = null;
16461
16019
  _promotionSnapshotBefore = null;
16462
- // Calendar arithmetic + in-dispatch memoization. Assigned in the
16463
- // constructor once the calendar reader is built. See `CalendarCalculator`.
16464
16020
  _calendar;
16465
16021
  _flags;
16466
- constructor(snapshot) {
16022
+ constructor(snapshot, buildOrderComparator = () => null) {
16023
+ this._buildOrderComparator = buildOrderComparator;
16467
16024
  for (const activity of snapshot.activities) {
16468
16025
  this._activities.set(activity.id, activity);
16469
16026
  }
@@ -16478,22 +16035,12 @@ var ScheduleState = class {
16478
16035
  this._hierarchy = new HierarchyIndex(this._activities);
16479
16036
  this._hierarchy.rebuild();
16480
16037
  }
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
16038
  getAllActivities() {
16488
16039
  return Array.from(this._activities.values());
16489
16040
  }
16490
16041
  getAllLinks() {
16491
16042
  return Array.from(this._links.values());
16492
16043
  }
16493
- /**
16494
- * Read-only snapshot of every alive activity id. Cached and invalidated
16495
- * lazily on structural mutations (add/remove/parent change).
16496
- */
16497
16044
  getAllIds() {
16498
16045
  if (this._cache.ids) return this._cache.ids;
16499
16046
  this._cache.ids = Array.from(this._activities.keys());
@@ -16502,14 +16049,6 @@ var ScheduleState = class {
16502
16049
  activityCount() {
16503
16050
  return this._activities.size;
16504
16051
  }
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
16052
  getVisualOrderIds() {
16514
16053
  if (this._cache.visualOrderIds) return this._cache.visualOrderIds;
16515
16054
  this._cache.visualOrderIds = iterateInVisualOrder(this).map(
@@ -16517,14 +16056,9 @@ var ScheduleState = class {
16517
16056
  );
16518
16057
  return this._cache.visualOrderIds;
16519
16058
  }
16520
- /** Drops the memoized visual order. See `getVisualOrderIds`. */
16521
16059
  invalidateVisualOrderIds() {
16522
16060
  this._cache.visualOrderIds = null;
16523
16061
  }
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
16062
  forEachActivity(visit) {
16529
16063
  for (const [id, activity] of this._activities) {
16530
16064
  visit(activity, id);
@@ -16577,6 +16111,9 @@ var ScheduleState = class {
16577
16111
  checkedIds() {
16578
16112
  return this._viewState.checkedIds();
16579
16113
  }
16114
+ hiddenIds() {
16115
+ return this._viewState.hiddenIds();
16116
+ }
16580
16117
  setChecked(activityId, nextChecked) {
16581
16118
  this._captureViewStateOnce();
16582
16119
  return this._viewState.setChecked(String(activityId), nextChecked);
@@ -16585,8 +16122,54 @@ var ScheduleState = class {
16585
16122
  this._captureViewStateOnce();
16586
16123
  return this._viewState.setVisible(String(activityId), nextVisible);
16587
16124
  }
16125
+ getActiveFilter() {
16126
+ return this._viewState.getActiveFilter();
16127
+ }
16128
+ setActiveFilter(nextFilter) {
16129
+ this._captureViewStateOnce();
16130
+ this._viewState.setActiveFilter(nextFilter);
16131
+ }
16132
+ getActiveOrder() {
16133
+ return this._viewState.getActiveOrder();
16134
+ }
16135
+ setActiveOrder(nextOrder) {
16136
+ this._captureViewStateOnce();
16137
+ this._viewState.setActiveOrder(nextOrder);
16138
+ this.invalidateDerivedOrder();
16139
+ }
16140
+ /**
16141
+ * Rebuild-on-demand, memoized: at most one build per invalidation, never one
16142
+ * per comparison. getChildrenInVisualOrder asks for this once and then sorts a
16143
+ * whole sibling group with it, and collectBranchOrder walks every branch, so a
16144
+ * build per read would be thousands per dispatch.
16145
+ *
16146
+ * The factory reads hoursPerDay and the collation locale at build time, so a
16147
+ * rebuilt comparator always reflects the current context — that is what keeps
16148
+ * ordering and filtering from seeing two different hoursPerDay.
16149
+ */
16150
+ getOrderComparator() {
16151
+ const activeOrder = this._viewState.getActiveOrder();
16152
+ if (activeOrder === null) {
16153
+ this._cache.orderComparator = null;
16154
+ return null;
16155
+ }
16156
+ if (this._cache.orderComparator) return this._cache.orderComparator;
16157
+ this._cache.orderComparator = this._buildOrderComparator(activeOrder);
16158
+ return this._cache.orderComparator;
16159
+ }
16160
+ /**
16161
+ * Both order caches, always together. The comparator decides the sequence, so
16162
+ * a rebuilt comparator with a surviving sequence would paint the old order.
16163
+ * invalidateVisualOrderIds stays separate on purpose: a structural change
16164
+ * moves rows without touching the rules, so the comparator is still valid.
16165
+ */
16166
+ invalidateDerivedOrder() {
16167
+ this._cache.orderComparator = null;
16168
+ this._cache.visualOrderIds = null;
16169
+ }
16588
16170
  hydrateViewState(seed2) {
16589
16171
  this._viewState.hydrate(seed2);
16172
+ this.invalidateDerivedOrder();
16590
16173
  }
16591
16174
  _captureViewStateOnce() {
16592
16175
  if (this._writeCapture.peek() === null) return;
@@ -16600,7 +16183,6 @@ var ScheduleState = class {
16600
16183
  getIncomingLinkIds(activityId) {
16601
16184
  return this._incoming.get(String(activityId)) ?? EMPTY_LINK_IDS;
16602
16185
  }
16603
- // -- AutoSchedulerPort: hierarchy --------------------------------------------
16604
16186
  getChildren(parentId) {
16605
16187
  return this._hierarchy.getChildren(parentId);
16606
16188
  }
@@ -16616,7 +16198,6 @@ var ScheduleState = class {
16616
16198
  getRootIds() {
16617
16199
  return this._hierarchy.getRootIds();
16618
16200
  }
16619
- // -- AutoSchedulerPort: calendar (snapshot-aware, M-F 08-16 UTC fallback) ---
16620
16201
  getClosestWorkTime(params) {
16621
16202
  return this._calendar.getClosestWorkTime(params);
16622
16203
  }
@@ -16626,66 +16207,44 @@ var ScheduleState = class {
16626
16207
  calculateDuration(params) {
16627
16208
  return this._calendar.calculateDuration(params);
16628
16209
  }
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
16210
  clearCalendarCache() {
16635
16211
  this._calendar.clearCache();
16636
16212
  }
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
16213
  get calendarReader() {
16641
16214
  return this._calendar.reader;
16642
16215
  }
16643
- // -- AutoSchedulerPort: mutations --------------------------------------------
16644
16216
  batchUpdate(runMutations) {
16645
16217
  runMutations();
16646
16218
  }
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
16219
  updateActivity(_id) {
16653
16220
  }
16654
16221
  getLiveActivity(activityId) {
16655
16222
  return this.getActivity(activityId);
16656
16223
  }
16657
- // -- AutoSchedulerPort: flags / config ---------------------------------------
16658
16224
  getFlags() {
16659
16225
  return {
16660
16226
  ...this._flags,
16661
16227
  allCheckedTaskIds: this._viewState.checkedIds()
16662
16228
  };
16663
16229
  }
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
16230
  getProjectEnd() {
16667
16231
  return null;
16668
16232
  }
16669
- // -- Write capture (per-dispatch journal) --------------------------------
16670
- /** Start recording every `setActivityField` write of the current dispatch. */
16671
16233
  beginWriteCapture() {
16672
16234
  this._writeCapture.begin();
16673
16235
  this._viewStateBefore = null;
16674
16236
  this._lastStartDateBefore = null;
16675
16237
  this._promotionSnapshotBefore = null;
16676
16238
  }
16677
- /** The live journal, or null when no capture is active. */
16678
16239
  peekWriteCapture() {
16679
16240
  return this._writeCapture.peek();
16680
16241
  }
16681
- /** Stop and discard the current dispatch's write journal. */
16682
16242
  endWriteCapture() {
16683
16243
  this._writeCapture.end();
16684
16244
  this._viewStateBefore = null;
16685
16245
  this._lastStartDateBefore = null;
16686
16246
  this._promotionSnapshotBefore = null;
16687
16247
  }
16688
- // -- Replay-specific mutators --------------------------------------------
16689
16248
  setActivityField(activityId, field, value) {
16690
16249
  const activity = this.getActivity(activityId);
16691
16250
  if (!activity) return;
@@ -16751,11 +16310,6 @@ var ScheduleState = class {
16751
16310
  this._writeCapture.noteLinkField(String(linkId), link);
16752
16311
  Reflect.set(link, field, value);
16753
16312
  }
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
16313
  setLinkProplannerId(linkId, proplannerId) {
16760
16314
  const link = this.getLink(linkId);
16761
16315
  if (!link) return;
@@ -16795,28 +16349,9 @@ var ScheduleState = class {
16795
16349
  this._cache.visualOrderIds = null;
16796
16350
  this._hierarchy.markDirty();
16797
16351
  }
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
16352
  noteCorrelativeBefore(activityId, before) {
16815
16353
  this._writeCapture.noteCorrelativeBefore(activityId, before);
16816
16354
  }
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
16355
  noteScheduledBefore(activityId, current) {
16821
16356
  this._writeCapture.noteScheduledBefore(activityId, current);
16822
16357
  }
@@ -16834,6 +16369,7 @@ var ScheduleState = class {
16834
16369
  this._restoreActivityFields(before);
16835
16370
  if (this._viewStateBefore !== null) {
16836
16371
  this._viewState.restore(this._viewStateBefore);
16372
+ this.invalidateDerivedOrder();
16837
16373
  }
16838
16374
  if (this._promotionSnapshotBefore !== null) {
16839
16375
  this._promotionSnapshot = this._promotionSnapshotBefore;
@@ -16926,11 +16462,6 @@ function buildFlags(snapshot) {
16926
16462
  };
16927
16463
  }
16928
16464
 
16929
- // src/shared/clone-domain-value.ts
16930
- function cloneDomainValue(value) {
16931
- return structuredClone(value);
16932
- }
16933
-
16934
16465
  // src/init/read-api.ts
16935
16466
  function readActivity(state, id) {
16936
16467
  const activity = state.getActivity(id);
@@ -16964,7 +16495,7 @@ function readChildrenIds(state, parentId) {
16964
16495
  });
16965
16496
  return roots;
16966
16497
  }
16967
- return [...state.getChildren(key)].map(String);
16498
+ return getChildrenInVisualOrder(key, state);
16968
16499
  }
16969
16500
  function readSelectedActivityIds(state) {
16970
16501
  return state.checkedIds().map(String);
@@ -17022,9 +16553,6 @@ function computeProjectWorkHours(calendars) {
17022
16553
  // src/internal/state/pipeline-context.ts
17023
16554
  function buildPipelineContext(adapter, options) {
17024
16555
  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
16556
  calendars: adapter.calendarReader,
17029
16557
  hierarchy: createStateBackedHierarchyReader(adapter),
17030
16558
  activityReader: createStateBackedActivityReader(adapter),
@@ -17041,6 +16569,21 @@ function willRunCriticalPath(action) {
17041
16569
  }
17042
16570
 
17043
16571
  // src/dispatch/undo/undo-entry.ts
16572
+ function buildHistoryChangeSet(changes) {
16573
+ const activitiesWithoutAfter = changes.activities.map((entry) => ({
16574
+ ...entry,
16575
+ after: null
16576
+ }));
16577
+ const linksWithoutAfter = changes.links.map((entry) => ({
16578
+ ...entry,
16579
+ after: null
16580
+ }));
16581
+ return cloneDomainValue({
16582
+ ...changes,
16583
+ activities: activitiesWithoutAfter,
16584
+ links: linksWithoutAfter
16585
+ });
16586
+ }
17044
16587
  function buildUndoEntry(changeSet, beforeSnap, beforeLinks, afterSnap, afterLinks) {
17045
16588
  return { changeSet, beforeSnap, beforeLinks, afterSnap, afterLinks };
17046
16589
  }
@@ -17096,7 +16639,7 @@ function mergeCoalesced(top, next) {
17096
16639
  }
17097
16640
  function getDispatchHistoryPolicy(action) {
17098
16641
  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") {
16642
+ 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" || action.kind === "sort-set") {
17100
16643
  return "skip";
17101
16644
  }
17102
16645
  return "record";
@@ -17338,24 +16881,20 @@ var UndoRecorder = class {
17338
16881
  redoStack = [];
17339
16882
  _lastKey = null;
17340
16883
  _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
16884
  record(entry, coalesceKey = null, now = 0) {
17347
16885
  const top = this.undoStack[this.undoStack.length - 1];
17348
16886
  if (coalesceKey != null && coalesceKey === this._lastKey && now - this._lastTime <= COALESCE_WINDOW_MS && top !== void 0 && canCoalesce(top, entry)) {
17349
16887
  this.undoStack[this.undoStack.length - 1] = mergeCoalesced(top, entry);
17350
16888
  } else {
17351
16889
  this.undoStack.push(entry);
17352
- if (this.undoStack.length > this.maxDepth) this.undoStack.shift();
16890
+ if (this.undoStack.length > this.maxDepth) {
16891
+ this.undoStack.splice(0, this.undoStack.length - this.maxDepth);
16892
+ }
17353
16893
  }
17354
16894
  this._lastKey = coalesceKey;
17355
16895
  this._lastTime = now;
17356
16896
  this.redoStack.length = 0;
17357
16897
  }
17358
- /** Break the coalescing chain (called on undo/redo). */
17359
16898
  resetCoalesce() {
17360
16899
  this._lastKey = null;
17361
16900
  }
@@ -17387,13 +16926,48 @@ var UndoRecorder = class {
17387
16926
  }
17388
16927
  };
17389
16928
 
16929
+ // src/dispatch/shared/resequenced-parents.ts
16930
+ var POSITIONAL_FIELDS = ["parentId", "correlativeId"];
16931
+ function collectResequencedParents(changes, parentOf) {
16932
+ const touched = /* @__PURE__ */ new Set();
16933
+ const addParentOf = (activityId) => {
16934
+ const parentId = parentOf(activityId);
16935
+ touched.add(parentId === null ? ROOT_PARENT_ID : String(parentId));
16936
+ };
16937
+ for (const change of changes.activities) {
16938
+ const activityId = String(change.id);
16939
+ if (change.kind === "created") {
16940
+ addParentOf(activityId);
16941
+ continue;
16942
+ }
16943
+ if (change.kind === "deleted") {
16944
+ const deletedFields = change.fields;
16945
+ if (deletedFields && "parentId" in deletedFields) {
16946
+ touched.add(parentKeyOf2(deletedFields.parentId?.before));
16947
+ }
16948
+ continue;
16949
+ }
16950
+ const fields = change.fields;
16951
+ if (!fields) continue;
16952
+ const movedPositionally = POSITIONAL_FIELDS.some(
16953
+ (field) => field in fields
16954
+ );
16955
+ if (!movedPositionally) continue;
16956
+ addParentOf(activityId);
16957
+ if ("parentId" in fields) {
16958
+ touched.add(parentKeyOf2(fields.parentId?.before));
16959
+ }
16960
+ }
16961
+ return touched;
16962
+ }
16963
+ function parentKeyOf2(parentId) {
16964
+ if (parentId === null || parentId === void 0) return ROOT_PARENT_ID;
16965
+ return String(parentId);
16966
+ }
16967
+
17390
16968
  // src/init/build-state-snapshot.ts
17391
16969
  function buildStoreLink(link) {
17392
16970
  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
16971
  ...link,
17398
16972
  id: String(link.id),
17399
16973
  source: String(link.source),
@@ -17406,11 +16980,6 @@ function serializeWorktime(worktime) {
17406
16980
  return {
17407
16981
  days: worktime.days,
17408
16982
  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
16983
  ...worktime.dates ? { dates: worktime.dates } : {},
17415
16984
  ...worktime.customWeeks ? { customWeeks: worktime.customWeeks } : {}
17416
16985
  };
@@ -17527,13 +17096,11 @@ var SaveTracker = class {
17527
17096
  initialized = false;
17528
17097
  linksAtLastSave = /* @__PURE__ */ new Map();
17529
17098
  activitiesAtLastSave = /* @__PURE__ */ new Map();
17530
- /** Take the initial snapshot once (after the autoscheduler settles). */
17531
17099
  init(activities, links) {
17532
17100
  this.snapshotActivities(activities);
17533
17101
  this.snapshotLinks(links);
17534
17102
  this.initialized = true;
17535
17103
  }
17536
- /** Re-snapshot activities (call after a save persists them). */
17537
17104
  snapshotActivities(activities) {
17538
17105
  this.activitiesAtLastSave.clear();
17539
17106
  for (const activity of activities) {
@@ -17544,7 +17111,6 @@ var SaveTracker = class {
17544
17111
  );
17545
17112
  }
17546
17113
  }
17547
- /** Re-snapshot links (call after a save persists them). */
17548
17114
  snapshotLinks(links) {
17549
17115
  this.linksAtLastSave.clear();
17550
17116
  for (const link of links) {
@@ -17555,7 +17121,6 @@ var SaveTracker = class {
17555
17121
  });
17556
17122
  }
17557
17123
  }
17558
- /** Persisted activities whose value changed since the last snapshot. */
17559
17124
  modifiedActivities(activities) {
17560
17125
  if (!this.initialized) return [];
17561
17126
  return activities.filter((activity) => {
@@ -17566,7 +17131,6 @@ var SaveTracker = class {
17566
17131
  return activityChangedSince(activity, saved);
17567
17132
  });
17568
17133
  }
17569
- /** Persisted links whose `lag`/`type` changed since the last snapshot. */
17570
17134
  modifiedLinks(links) {
17571
17135
  if (!this.initialized) return [];
17572
17136
  return links.filter((link) => {
@@ -17576,7 +17140,6 @@ var SaveTracker = class {
17576
17140
  return link.lag !== saved.lag || link.type !== saved.type;
17577
17141
  });
17578
17142
  }
17579
- /** Drop both mirrors (teardown). */
17580
17143
  clear() {
17581
17144
  this.linksAtLastSave.clear();
17582
17145
  this.activitiesAtLastSave.clear();
@@ -18346,35 +17909,58 @@ function cloneStats(stats) {
18346
17909
  var CustomIdTracker = class {
18347
17910
  prefixMap = /* @__PURE__ */ new Map();
18348
17911
  processedIds = /* @__PURE__ */ new Set();
18349
- _journal = null;
17912
+ _journalPrefixBefore = null;
17913
+ _journalIds = null;
18350
17914
  beginCustomIdTransaction() {
18351
- this._journal = [];
17915
+ this._journalPrefixBefore = /* @__PURE__ */ new Map();
17916
+ this._journalIds = [];
18352
17917
  }
18353
17918
  commitCustomIdTransaction() {
18354
- this._journal = null;
17919
+ this._journalPrefixBefore = null;
17920
+ this._journalIds = null;
18355
17921
  }
18356
17922
  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);
17923
+ const prefixBeforeByPrefix = this._journalPrefixBefore;
17924
+ const journaledIds = this._journalIds;
17925
+ if (prefixBeforeByPrefix === null || journaledIds === null) return;
17926
+ for (const [prefix, statsBefore] of prefixBeforeByPrefix) {
17927
+ if (statsBefore === null) this.prefixMap.delete(prefix);
17928
+ else this.prefixMap.set(prefix, statsBefore);
17929
+ }
17930
+ for (const entry of [...journaledIds].reverse()) {
18363
17931
  if (entry.hadId) this.processedIds.add(entry.customId);
18364
17932
  else this.processedIds.delete(entry.customId);
18365
17933
  }
18366
- this._journal = null;
17934
+ this._journalPrefixBefore = null;
17935
+ this._journalIds = null;
18367
17936
  }
18368
17937
  _noteCustomIdBefore(customId) {
18369
- if (this._journal === null) return;
17938
+ if (this._journalPrefixBefore === null || this._journalIds === null) {
17939
+ return;
17940
+ }
18370
17941
  const { prefix } = this.analyzeCustomId(customId);
18371
- const current = this.prefixMap.get(prefix);
18372
- this._journal.push({
17942
+ if (!this._journalPrefixBefore.has(prefix)) {
17943
+ const current = this.prefixMap.get(prefix);
17944
+ this._journalPrefixBefore.set(
17945
+ prefix,
17946
+ current ? cloneStats(current) : null
17947
+ );
17948
+ }
17949
+ this._journalIds.push({
18373
17950
  customId,
18374
- prefixBefore: current ? cloneStats(current) : null,
18375
17951
  hadId: this.processedIds.has(customId)
18376
17952
  });
18377
17953
  }
17954
+ _ensureFreshBounds(prefix) {
17955
+ const stats = this.prefixMap.get(prefix);
17956
+ if (!stats?.boundsDirty) return;
17957
+ stats.boundsDirty = false;
17958
+ const remaining = Array.from(stats.usedSuffixes);
17959
+ stats.min = minSuffixFromArray(remaining);
17960
+ stats.max = maxSuffixFromArray(remaining);
17961
+ stats.quantity = remaining.length;
17962
+ this._recalculateNext(prefix);
17963
+ }
18378
17964
  defaultPrefix;
18379
17965
  suffixIncrement;
18380
17966
  constructor(options = {}) {
@@ -18394,6 +17980,7 @@ var CustomIdTracker = class {
18394
17980
  };
18395
17981
  }
18396
17982
  _updatePrefixStats(prefix, suffix) {
17983
+ this._ensureFreshBounds(prefix);
18397
17984
  if (!this.prefixMap.has(prefix)) {
18398
17985
  this.prefixMap.set(prefix, {
18399
17986
  min: suffix,
@@ -18420,6 +18007,7 @@ var CustomIdTracker = class {
18420
18007
  stats.next = next ?? this.suffixIncrement;
18421
18008
  }
18422
18009
  getPrefixStats(prefix) {
18010
+ this._ensureFreshBounds(prefix);
18423
18011
  const stats = this.prefixMap.get(prefix);
18424
18012
  if (!stats) return null;
18425
18013
  return {
@@ -18430,6 +18018,7 @@ var CustomIdTracker = class {
18430
18018
  };
18431
18019
  }
18432
18020
  getNextSuffix(prefix) {
18021
+ this._ensureFreshBounds(prefix);
18433
18022
  const stats = this.prefixMap.get(prefix);
18434
18023
  return stats ? stats.next : this.suffixIncrement;
18435
18024
  }
@@ -18443,6 +18032,7 @@ var CustomIdTracker = class {
18443
18032
  const { prefix, suffix } = this.analyzeCustomId(customId);
18444
18033
  if (!prefix && !suffix) return { prefix, suffix };
18445
18034
  this._noteCustomIdBefore(customId);
18035
+ this._ensureFreshBounds(prefix);
18446
18036
  if (this.prefixMap.has(prefix)) {
18447
18037
  const stats = this.prefixMap.get(prefix);
18448
18038
  if (!stats.usedSuffixes.has(suffix)) {
@@ -18473,22 +18063,12 @@ var CustomIdTracker = class {
18473
18063
  this._noteCustomIdBefore(customId);
18474
18064
  const currentStats = this.prefixMap.get(prefix);
18475
18065
  if (currentStats.usedSuffixes.has(suffix)) {
18476
- const newQuantity = currentStats.quantity - 1;
18477
- if (newQuantity === 0) {
18066
+ currentStats.usedSuffixes.delete(suffix);
18067
+ currentStats.quantity -= 1;
18068
+ if (currentStats.usedSuffixes.size === 0) {
18478
18069
  this.prefixMap.delete(prefix);
18479
18070
  } 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
- }
18071
+ currentStats.boundsDirty = true;
18492
18072
  }
18493
18073
  }
18494
18074
  this.processedIds.delete(customId);
@@ -18508,12 +18088,19 @@ var CustomIdTracker = class {
18508
18088
  return customId.length > MAX_CUSTOM_ID_LENGTH;
18509
18089
  }
18510
18090
  _shouldSearchForGaps(prefix) {
18091
+ this._ensureFreshBounds(prefix);
18511
18092
  if (!this.prefixMap.has(prefix)) return false;
18512
18093
  const stats = this.prefixMap.get(prefix);
18513
18094
  const nextWouldBe = `${prefix}${addToSuffix(stats.max, this.suffixIncrement)}`;
18514
18095
  return nextWouldBe.length > MAX_CUSTOM_ID_LENGTH;
18515
18096
  }
18097
+ _suffixForUnknownPrefix(prefix, baseSuffix) {
18098
+ const candidate = baseSuffix && isValidSuffix(baseSuffix) ? baseSuffix : this.suffixIncrement;
18099
+ if (`${prefix}${candidate}`.length > MAX_CUSTOM_ID_LENGTH) return null;
18100
+ return candidate;
18101
+ }
18516
18102
  _findFirstAvailableGap(prefix) {
18103
+ this._ensureFreshBounds(prefix);
18517
18104
  if (!this.prefixMap.has(prefix)) return null;
18518
18105
  const stats = this.prefixMap.get(prefix);
18519
18106
  let candidate = this.suffixIncrement;
@@ -18537,10 +18124,9 @@ var CustomIdTracker = class {
18537
18124
  return `${this.defaultPrefix}${nextSuffix}`;
18538
18125
  }
18539
18126
  getNextAvailableSuffix(prefix, baseSuffix = null) {
18127
+ this._ensureFreshBounds(prefix);
18540
18128
  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;
18129
+ return this._suffixForUnknownPrefix(prefix, baseSuffix);
18544
18130
  }
18545
18131
  const stats = this.prefixMap.get(prefix);
18546
18132
  const step = this.suffixIncrement;
@@ -18581,9 +18167,6 @@ var CustomIdTracker = class {
18581
18167
  }
18582
18168
  return generatedId;
18583
18169
  }
18584
- /**
18585
- * Seed the tracker from an array of activities. Idempotent.
18586
- */
18587
18170
  populateFromActivities(activities) {
18588
18171
  if (!Array.isArray(activities)) return this;
18589
18172
  const uniqueCustomIds = [
@@ -18604,14 +18187,6 @@ var CustomIdTracker = class {
18604
18187
  getDefaults() {
18605
18188
  return { prefix: this.defaultPrefix, increment: this.suffixIncrement };
18606
18189
  }
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
18190
  generateCustomIdForNewChild(params) {
18616
18191
  const { activity, useActivityCustomIdAsReference = false } = params;
18617
18192
  const customId = getCustomIdFromActivity(activity);
@@ -18625,6 +18200,7 @@ var CustomIdTracker = class {
18625
18200
  );
18626
18201
  let capturedNextSuffix = null;
18627
18202
  if (strategyKey === "parentConversion" && this.prefixMap.has(prefix)) {
18203
+ this._ensureFreshBounds(prefix);
18628
18204
  const currentMax = this.prefixMap.get(prefix).max;
18629
18205
  capturedNextSuffix = addToSuffix(currentMax, this.suffixIncrement);
18630
18206
  }
@@ -18655,11 +18231,6 @@ var CustomIdTracker = class {
18655
18231
  return noContextStrategy(this.defaultPrefix);
18656
18232
  }
18657
18233
  }
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
18234
  generateCustomIdForRestoredChild(siblingCustomId = null) {
18664
18235
  if (siblingCustomId) {
18665
18236
  const trimmed = siblingCustomId.trim();
@@ -18695,11 +18266,6 @@ var CustomIdTracker = class {
18695
18266
  hasPrefix(prefix) {
18696
18267
  return this.prefixMap.has(prefix);
18697
18268
  }
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
18269
  isCustomIdInUse(customId, currentCustomId = null) {
18704
18270
  if (!customId || typeof customId !== "string" || !customId.trim()) {
18705
18271
  return false;
@@ -18712,6 +18278,65 @@ var CustomIdTracker = class {
18712
18278
  }
18713
18279
  };
18714
18280
 
18281
+ // src/internal/order/build-comparator.ts
18282
+ var MISSING_LAST = 1;
18283
+ var MISSING_FIRST = -1;
18284
+ function compareMissing(aMissing, bMissing) {
18285
+ if (!aMissing && !bMissing) return null;
18286
+ if (aMissing && bMissing) return 0;
18287
+ return aMissing ? MISSING_LAST : MISSING_FIRST;
18288
+ }
18289
+ function isMissing(value) {
18290
+ return value === null || value === void 0;
18291
+ }
18292
+ function enumRank(value, order) {
18293
+ const index = order.indexOf(String(value));
18294
+ return index === -1 ? order.length : index;
18295
+ }
18296
+ function compareValues(a, b, locale) {
18297
+ if (a instanceof Date && b instanceof Date) {
18298
+ return a.getTime() - b.getTime();
18299
+ }
18300
+ if (typeof a === "number" && typeof b === "number") {
18301
+ return a - b;
18302
+ }
18303
+ if (typeof a === "boolean" && typeof b === "boolean") {
18304
+ return Number(a) - Number(b);
18305
+ }
18306
+ if (Array.isArray(a) && Array.isArray(b)) {
18307
+ return a.length - b.length;
18308
+ }
18309
+ return String(a).localeCompare(String(b), locale, {
18310
+ sensitivity: "base",
18311
+ numeric: true
18312
+ });
18313
+ }
18314
+ function compareByRule(rule, context) {
18315
+ const descriptor = getFieldDescriptor(rule.field);
18316
+ if (descriptor === null) return null;
18317
+ return (a, b) => {
18318
+ const valueA = descriptor.extract(a, context);
18319
+ const valueB = descriptor.extract(b, context);
18320
+ const missing = compareMissing(isMissing(valueA), isMissing(valueB));
18321
+ if (missing !== null) return missing;
18322
+ const result = descriptor.valueKind === "enum" ? enumRank(valueA, descriptor.order) - enumRank(valueB, descriptor.order) : compareValues(valueA, valueB, context.locale);
18323
+ return rule.direction === "desc" ? -result : result;
18324
+ };
18325
+ }
18326
+ function buildComparator(order, context) {
18327
+ const comparators = order.rules.map((rule) => compareByRule(rule, context)).filter(
18328
+ (comparator) => comparator !== null
18329
+ );
18330
+ if (comparators.length === 0) return null;
18331
+ return (a, b) => {
18332
+ for (const comparator of comparators) {
18333
+ const result = comparator(a, b);
18334
+ if (result !== 0) return result;
18335
+ }
18336
+ return 0;
18337
+ };
18338
+ }
18339
+
18715
18340
  // src/internal/post-processors/demote-childless-summaries.ts
18716
18341
  function demoteChildlessSummaries(state) {
18717
18342
  const idsToDemote = [];
@@ -18866,8 +18491,6 @@ function normalizeMilestoneConstraintDatesForDisplay(state) {
18866
18491
  var SCHEDULE_CORE_STATUS = {
18867
18492
  READY: "ready",
18868
18493
  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
18494
  POISONED: "poisoned"
18872
18495
  };
18873
18496
  function initializeCore(input) {
@@ -18894,7 +18517,8 @@ function initializeCore(input) {
18894
18517
  parsed2.calendars,
18895
18518
  baseCalendars
18896
18519
  );
18897
- const state = new ScheduleState(snapshot);
18520
+ const buildOrderComparator = (order) => buildComparator(order, buildFilterContext(sector.hoursPerDay));
18521
+ const state = new ScheduleState(snapshot, buildOrderComparator);
18898
18522
  state.hydrateViewState({ hiddenIds: parsed2.viewStateSeed.hiddenIds });
18899
18523
  const scheduler = new AutoScheduler(state, reporter);
18900
18524
  demoteChildlessSummaries(state);
@@ -18927,9 +18551,6 @@ function initializeCore(input) {
18927
18551
  sector,
18928
18552
  scheduler,
18929
18553
  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
18554
  now: loadNow ?? void 0
18934
18555
  });
18935
18556
  return {
@@ -19045,13 +18666,18 @@ var ScheduleCore = class {
19045
18666
  this.assertReady();
19046
18667
  return readSelectedActivityIds(this.coreRuntime.state);
19047
18668
  }
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
- */
18669
+ getHiddenActivityIds() {
18670
+ this.assertReady();
18671
+ return this.coreRuntime.state.hiddenIds().map(String);
18672
+ }
18673
+ getActiveFilter() {
18674
+ this.assertReady();
18675
+ return this.coreRuntime.state.getActiveFilter();
18676
+ }
18677
+ getActiveOrder() {
18678
+ this.assertReady();
18679
+ return this.coreRuntime.state.getActiveOrder();
18680
+ }
19055
18681
  getVisualOrderIds() {
19056
18682
  this.assertReady();
19057
18683
  return [...this.coreRuntime.state.getVisualOrderIds()];
@@ -19151,7 +18777,7 @@ var ScheduleCore = class {
19151
18777
  );
19152
18778
  this._undo.record(
19153
18779
  buildUndoEntry(
19154
- result.changes,
18780
+ buildHistoryChangeSet(result.changes),
19155
18781
  result.__beforeSnap,
19156
18782
  result.__beforeLinks,
19157
18783
  created.afterSnap,
@@ -19168,19 +18794,13 @@ var ScheduleCore = class {
19168
18794
  this._saveTracker.snapshotLinks(this.getAllLinksView());
19169
18795
  this._undo.clear();
19170
18796
  }
18797
+ result = this._withReappliedViewState(action, result);
19171
18798
  if (!result.ok) return result;
19172
18799
  if (dispatchChangesSchedulingState(action) && changeSetIsSubstantive(result.changes)) {
19173
18800
  this._recordScheduleMutation(options.skipCriticalPath !== true);
19174
18801
  }
19175
- return cloneDomainValue(result);
18802
+ return toPublicDispatchResult(result);
19176
18803
  }
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
18804
  recomputeCriticalPath() {
19185
18805
  const operation = this._enqueue(async () => ({
19186
18806
  job: this._startCriticalPathForCurrentRevision()
@@ -19196,6 +18816,99 @@ var ScheduleCore = class {
19196
18816
  await this.recomputeCriticalPath();
19197
18817
  }
19198
18818
  }
18819
+ _withReappliedViewState(action, result) {
18820
+ if (!result.ok || !reappliesViewState(action)) return result;
18821
+ const merged = this._reapplyViewState(result.changes);
18822
+ return merged === null ? result : { ...result, changes: merged };
18823
+ }
18824
+ /**
18825
+ * The single place the two view-state passes are chained. Dispatch, undo and
18826
+ * redo all route through here: when this existed only inside the dispatch
18827
+ * path, undo and redo reapplied the filter and forgot the order, so an edit
18828
+ * that moved a row and was then undone left the row in its new position.
18829
+ *
18830
+ * The sequence between the passes is indifferent. Filter and order are
18831
+ * orthogonal projections over the same tree — the filter decides which rows
18832
+ * exist on screen and never reads the order; the order sequences every
18833
+ * sibling group from the hierarchy index and never reads visibility. Either
18834
+ * sequence produces the same ChangeSet.
18835
+ *
18836
+ * Both passes answer null while their state is inactive, so an unfiltered,
18837
+ * unsorted schedule pays two property reads.
18838
+ */
18839
+ _reapplyViewState(changes) {
18840
+ const withFilter = this._reapplyActiveFilter(changes);
18841
+ const withOrder = this._reapplyActiveOrder(withFilter ?? changes);
18842
+ const sequenced = this._emitTouchedBranchOrder(
18843
+ withOrder ?? withFilter ?? changes
18844
+ );
18845
+ return sequenced ?? withOrder ?? withFilter;
18846
+ }
18847
+ /**
18848
+ * Emits `order` for the branches this mutation resequenced, when no user order
18849
+ * is active.
18850
+ *
18851
+ * The contract is that `order` reports a CHANGED SEQUENCE, not the presence of
18852
+ * a sort. Tying emission to the cause instead of the effect is what produced
18853
+ * the undo bug and, later, the reparent ones: without an active order a move,
18854
+ * an indent, an outdent or the undo of any of them rearranged rows and said
18855
+ * nothing, so an incremental consumer kept the old sequence. The undo of a
18856
+ * reparent was the worst of them — it carried neither `order` nor a single
18857
+ * correlativeId, so the position was not recoverable by any consumer.
18858
+ *
18859
+ * The touched branches are derived from the ChangeSet rather than accumulated
18860
+ * in the state: an entity whose parentId or correlativeId moved, plus the
18861
+ * parents of created and deleted rows, is exactly the set of branches whose
18862
+ * sequence can differ. That keeps this linear in the blast radius, adds
18863
+ * nothing to the write path, and cannot leak across dispatches.
18864
+ */
18865
+ _emitTouchedBranchOrder(changes) {
18866
+ const adapter = this.coreRuntime.state;
18867
+ if (adapter.getActiveOrder() !== null) return null;
18868
+ const touched = collectResequencedParents(
18869
+ changes,
18870
+ (activityId) => adapter.getParentId(activityId)
18871
+ );
18872
+ if (touched.size === 0) return null;
18873
+ const order = [...touched].map((parentId) => ({
18874
+ parentId,
18875
+ childIds: getChildrenInVisualOrder(parentId, adapter)
18876
+ })).filter((branch) => branch.childIds.length > 1);
18877
+ if (order.length === 0) return null;
18878
+ return { ...changes, order };
18879
+ }
18880
+ /**
18881
+ * Re-sequences the grid after any mutation that could have changed a value the
18882
+ * active order sorts by. Ordering is a view over the data, so an edit that
18883
+ * moves a row past its sibling must move the row, exactly as the filter makes
18884
+ * a no-longer-matching row disappear.
18885
+ *
18886
+ * Production only re-sorts after a bar drag; diverging from that is a
18887
+ * deliberate product decision, not an oversight.
18888
+ */
18889
+ _reapplyActiveOrder(changes) {
18890
+ const adapter = this.coreRuntime.state;
18891
+ if (adapter.getActiveOrder() === null) return null;
18892
+ adapter.invalidateDerivedOrder();
18893
+ return { ...changes, order: collectBranchOrder(adapter) };
18894
+ }
18895
+ _reapplyActiveFilter(changes) {
18896
+ const filter = this.coreRuntime.state.getActiveFilter();
18897
+ if (filter === null) return null;
18898
+ const adapter = this.coreRuntime.state;
18899
+ const visibleIds = evaluateVisibleIds({
18900
+ activities: adapter.getAllActivities(),
18901
+ parentOf: (activityId) => adapter.getParentId(activityId),
18902
+ filter,
18903
+ context: buildFilterContext(this.coreRuntime.sector.hoursPerDay)
18904
+ });
18905
+ const viewState = applyVisibleSet(adapter, visibleIds);
18906
+ if (viewState.length === 0) return null;
18907
+ return {
18908
+ ...changes,
18909
+ viewState: [...changes.viewState ?? [], ...viewState]
18910
+ };
18911
+ }
19199
18912
  _recordScheduleMutation(criticalPathIsFresh) {
19200
18913
  this._scheduleRevision++;
19201
18914
  if (this._activeCriticalPath) {
@@ -19246,7 +18959,7 @@ var ScheduleCore = class {
19246
18959
  for (const [activityId, fields] of fieldsByActivity) {
19247
18960
  this.coreRuntime.state.setActivityFields(activityId, fields);
19248
18961
  }
19249
- changes = assembleChangeSet(this.coreRuntime.state, {
18962
+ changes = await assembleChangeSet(this.coreRuntime.state, {
19250
18963
  source: { kind: "init" },
19251
18964
  beforeSnap: /* @__PURE__ */ new Map(),
19252
18965
  touchedIds: [],
@@ -19273,7 +18986,6 @@ var ScheduleCore = class {
19273
18986
  void promise.then(clearIfActive, clearIfActive);
19274
18987
  return promise;
19275
18988
  }
19276
- // bridge-load artifact: emits HOURS (no duration/lag diff anyway; bridge applies verbatim).
19277
18989
  async _runCriticalPathAndCapture() {
19278
18990
  if (this._status === SCHEDULE_CORE_STATUS.DESTROYED) {
19279
18991
  return {
@@ -19294,7 +19006,7 @@ var ScheduleCore = class {
19294
19006
  this.coreRuntime.state,
19295
19007
  this.coreRuntime.sector.hoursPerDay
19296
19008
  );
19297
- changes = assembleChangeSet(this.coreRuntime.state, {
19009
+ changes = await assembleChangeSet(this.coreRuntime.state, {
19298
19010
  source: { kind: "init" },
19299
19011
  beforeSnap: /* @__PURE__ */ new Map(),
19300
19012
  touchedIds: [],
@@ -19307,11 +19019,6 @@ var ScheduleCore = class {
19307
19019
  }
19308
19020
  return { changes };
19309
19021
  }
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
19022
  _recomputeAfterHistoryRestore() {
19316
19023
  const state = this.coreRuntime.state;
19317
19024
  recomputeAllProgressRollup(state);
@@ -19347,7 +19054,12 @@ var ScheduleCore = class {
19347
19054
  if (needsResync(entry)) this._resyncCustomIdTrackerFromModel();
19348
19055
  this._undo.pushRedo(entry);
19349
19056
  this._undo.resetCoalesce();
19350
- return buildInverseChangeSet(this.coreRuntime.state, entry, "before");
19057
+ const changes = buildInverseChangeSet(
19058
+ this.coreRuntime.state,
19059
+ entry,
19060
+ "before"
19061
+ );
19062
+ return this._reapplyViewState(changes) ?? changes;
19351
19063
  });
19352
19064
  void operation.then(
19353
19065
  (changes) => {
@@ -19375,7 +19087,12 @@ var ScheduleCore = class {
19375
19087
  if (needsResync(entry)) this._resyncCustomIdTrackerFromModel();
19376
19088
  this._undo.pushUndo(entry);
19377
19089
  this._undo.resetCoalesce();
19378
- return buildInverseChangeSet(this.coreRuntime.state, entry, "after");
19090
+ const changes = buildInverseChangeSet(
19091
+ this.coreRuntime.state,
19092
+ entry,
19093
+ "after"
19094
+ );
19095
+ return this._reapplyViewState(changes) ?? changes;
19379
19096
  });
19380
19097
  void operation.then(
19381
19098
  (changes) => {
@@ -19398,11 +19115,6 @@ var ScheduleCore = class {
19398
19115
  canRedo() {
19399
19116
  return this._undo.canRedo();
19400
19117
  }
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
19118
  clearHistory() {
19407
19119
  this._undo.clear();
19408
19120
  }
@@ -19437,13 +19149,6 @@ var ScheduleCore = class {
19437
19149
  );
19438
19150
  }
19439
19151
  }
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
19152
  _rollback() {
19448
19153
  try {
19449
19154
  this.coreRuntime.state.restoreFromCapture();
@@ -19458,6 +19163,14 @@ var ScheduleCore = class {
19458
19163
  }
19459
19164
  }
19460
19165
  };
19166
+ function toPublicDispatchResult(result) {
19167
+ const {
19168
+ __beforeSnap: droppedSnapshots,
19169
+ __beforeLinks: droppedLinks,
19170
+ ...publicResult
19171
+ } = result;
19172
+ return publicResult;
19173
+ }
19461
19174
 
19462
19175
  // src/boundary/save/link-changes.ts
19463
19176
  function checkNoUpdatedLinks(baseline, current) {
@@ -19512,6 +19225,8 @@ var DISPATCH_ACTION_KIND = {
19512
19225
  SELECTION_TOGGLE: "selection-toggle",
19513
19226
  SELECTION_REPLACE: "selection-replace",
19514
19227
  VISIBILITY_SET: "visibility-set",
19228
+ FILTER_SET: "filter-set",
19229
+ SORT_SET: "sort-set",
19515
19230
  SIR_SYNC: "sir-sync",
19516
19231
  ACTIVITY_LOOKAHEAD_SYNC: "activity-lookahead-sync"
19517
19232
  };
@@ -19537,6 +19252,8 @@ var KIND_CATALOG_COVERS_UNION = {
19537
19252
  [DISPATCH_ACTION_KIND.SELECTION_TOGGLE]: true,
19538
19253
  [DISPATCH_ACTION_KIND.SELECTION_REPLACE]: true,
19539
19254
  [DISPATCH_ACTION_KIND.VISIBILITY_SET]: true,
19255
+ [DISPATCH_ACTION_KIND.FILTER_SET]: true,
19256
+ [DISPATCH_ACTION_KIND.SORT_SET]: true,
19540
19257
  [DISPATCH_ACTION_KIND.SIR_SYNC]: true,
19541
19258
  [DISPATCH_ACTION_KIND.ACTIVITY_LOOKAHEAD_SYNC]: true
19542
19259
  };