@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.js CHANGED
@@ -5,14 +5,12 @@ var Queue = class {
5
5
  enqueue(item) {
6
6
  this.items.push(item);
7
7
  }
8
- /** Removes and returns the oldest item, or `undefined` when empty. */
9
8
  dequeue() {
10
9
  if (this.head >= this.items.length) return void 0;
11
10
  const item = this.items[this.head];
12
11
  this.head += 1;
13
12
  return item;
14
13
  }
15
- /** The oldest item without removing it, or `undefined` when empty. */
16
14
  peek() {
17
15
  if (this.head >= this.items.length) return void 0;
18
16
  return this.items[this.head];
@@ -123,33 +121,24 @@ function isFrozen(activity) {
123
121
 
124
122
  // src/dispatch/reasons.ts
125
123
  var REJECTION_REASON = {
126
- // Pipeline-gate fallbacks (used when a gate rejects without a reason).
127
124
  CANNOT_EDIT: "cannot_edit",
128
125
  PARSE_ERROR: "parse_error",
129
126
  INVALID: "invalid",
130
- // Inline-edit / link validation.
131
127
  CUSTOM_ID_DUPLICATE: "custom_id_duplicate",
132
128
  INVALID_LINK_TYPE: "invalid_link_type",
133
129
  INVALID_LINK_LAG: "invalid_link_lag",
134
130
  INVALID_VALUE: "invalid_value",
135
- // Bulk-edit: the column has no registered pipeline (unknown column, or a
136
- // link column like custom_predecessors that dispatches as link intents).
137
131
  NO_PIPELINE_FOR_COLUMN: "no_pipeline_for_column",
138
- // Entity lookups.
139
132
  ACTIVITY_NOT_FOUND: "activity_not_found",
140
133
  PARENT_NOT_FOUND: "parent_not_found",
141
134
  ACTIVITY_IDS_EMPTY: "activity_ids_empty",
142
- // Anchored positioning (create / move).
143
135
  ANCHOR_SIBLING_CONFLICT: "anchor_sibling_conflict",
144
136
  ANCHOR_SIBLING_NOT_FOUND: "anchor_sibling_not_found",
145
137
  ANCHOR_SIBLING_WRONG_PARENT: "anchor_sibling_wrong_parent",
146
- // SIR freeze: cannot add a child under an activity with a pending SIR.
147
138
  PARENT_FROZEN_BY_SIR: "parent_frozen_by_sir",
148
- // Hierarchy rules.
149
139
  CANNOT_MOVE_INTO_OWN_DESCENDANT: "cannot_move_into_own_descendant",
150
140
  INDENT_NO_ELIGIBLE_SIBLING: "indent_no_eligible_sibling",
151
141
  OUTDENT_ROOT_LEVEL_NOT_EDITABLE: "outdent_root_level_not_editable",
152
- // Progress button.
153
142
  INVALID_PROGRESS_VALUE: "invalid_progress_value_must_be_0_or_100"
154
143
  };
155
144
 
@@ -220,14 +209,12 @@ function dispatchSelectionReplace(action, deps) {
220
209
  };
221
210
  }
222
211
 
223
- // src/dispatch/visibility.ts
224
- function dispatchVisibilitySet(action, deps) {
225
- const { adapter } = deps;
226
- const targetVisible = new Set(action.visibleIds.map(String));
212
+ // src/dispatch/shared/apply-visible-set.ts
213
+ function applyVisibleSet(adapter, visibleIds) {
227
214
  const viewState = [];
228
215
  adapter.forEachActivity((_snapshot, activityId) => {
229
216
  const id = String(activityId);
230
- const willBeVisible = targetVisible.has(id);
217
+ const willBeVisible = visibleIds.has(id);
231
218
  const before = adapter.isVisible(id);
232
219
  if (before === willBeVisible) return;
233
220
  adapter.setVisible(id, willBeVisible);
@@ -236,6 +223,390 @@ function dispatchVisibilitySet(action, deps) {
236
223
  visible: { before, after: willBeVisible }
237
224
  });
238
225
  });
226
+ return viewState;
227
+ }
228
+
229
+ // src/dispatch/visibility.ts
230
+ function dispatchVisibilitySet(action, deps) {
231
+ const { adapter } = deps;
232
+ const targetVisible = new Set(action.visibleIds.map(String));
233
+ const viewState = applyVisibleSet(adapter, targetVisible);
234
+ const changes = {
235
+ source: action,
236
+ activities: [],
237
+ links: [],
238
+ calendars: [],
239
+ trackingEvents: [],
240
+ viewState
241
+ };
242
+ return { ok: true, changes };
243
+ }
244
+
245
+ // src/internal/filter/field-registry.ts
246
+ var STATUS_ORDER = [
247
+ "Waiting",
248
+ "Done",
249
+ "Doing",
250
+ "Overdue",
251
+ "Advancement"
252
+ ];
253
+ var CONSTRAINT_TYPE_ORDER = [
254
+ "mfo",
255
+ "mso",
256
+ "snlt",
257
+ "snet",
258
+ "alap",
259
+ "asap",
260
+ "fnet",
261
+ "fnlt"
262
+ ];
263
+ var MILLISECONDS_PER_DAY = 1e3 * 60 * 60 * 24;
264
+ function toDays(hours, hoursPerDay) {
265
+ if (hours === null) return null;
266
+ if (hoursPerDay <= 0) return null;
267
+ return hours / hoursPerDay;
268
+ }
269
+ function calendarDaySpan(startDate, endDate) {
270
+ const elapsed = endDate.getTime() - startDate.getTime();
271
+ return Math.floor(elapsed / MILLISECONDS_PER_DAY) + 1;
272
+ }
273
+ var FIELD_REGISTRY = {
274
+ name: { valueKind: "string", extract: (activity) => activity.name },
275
+ description: {
276
+ valueKind: "string",
277
+ extract: (activity) => activity.description
278
+ },
279
+ customId: { valueKind: "string", extract: (activity) => activity.customId },
280
+ correlativeId: {
281
+ valueKind: "number",
282
+ extract: (activity) => activity.correlativeId
283
+ },
284
+ uniqueCorrelativeId: {
285
+ valueKind: "number",
286
+ extract: (activity) => Number(activity.uniqueCorrelativeId)
287
+ },
288
+ progress: { valueKind: "number", extract: (activity) => activity.progress },
289
+ durationDays: {
290
+ valueKind: "number",
291
+ extract: (activity, context) => toDays(activity.durationHours, context.hoursPerDay)
292
+ },
293
+ calendarDuration: {
294
+ valueKind: "number",
295
+ extract: (activity) => calendarDaySpan(activity.startDate, activity.endDate)
296
+ },
297
+ cost: { valueKind: "number", extract: (activity) => activity.cost },
298
+ usedCost: { valueKind: "number", extract: (activity) => activity.usedCost },
299
+ realCost: { valueKind: "number", extract: (activity) => activity.realCost },
300
+ workHours: { valueKind: "number", extract: (activity) => activity.workHours },
301
+ realWorkHours: {
302
+ valueKind: "number",
303
+ extract: (activity) => activity.realWorkHours
304
+ },
305
+ ponderator: {
306
+ valueKind: "number",
307
+ extract: (activity) => activity.ponderator
308
+ },
309
+ freeSlackDays: {
310
+ valueKind: "number",
311
+ extract: (activity, context) => toDays(activity.freeSlackHours, context.hoursPerDay)
312
+ },
313
+ totalSlackDays: {
314
+ valueKind: "number",
315
+ extract: (activity, context) => toDays(
316
+ activity.criticalPath?.totalSlackHours ?? null,
317
+ context.hoursPerDay
318
+ )
319
+ },
320
+ expectedProgressBaseline: {
321
+ valueKind: "number",
322
+ extract: (activity) => activity.expectedProgressBaseline
323
+ },
324
+ baselineDurationDays: {
325
+ valueKind: "number",
326
+ extract: (activity) => activity.baselineSnapshot?.durationDays ?? null
327
+ },
328
+ baselineCost: {
329
+ valueKind: "number",
330
+ extract: (activity) => activity.baselineSnapshot?.cost ?? null
331
+ },
332
+ baselineWorkHours: {
333
+ valueKind: "number",
334
+ extract: (activity) => activity.baselineSnapshot?.workHours ?? null
335
+ },
336
+ startDate: { valueKind: "date", extract: (activity) => activity.startDate },
337
+ endDate: { valueKind: "date", extract: (activity) => activity.endDate },
338
+ constraintDate: {
339
+ valueKind: "date",
340
+ extract: (activity) => activity.constraintDate
341
+ },
342
+ baselineStartDate: {
343
+ valueKind: "date",
344
+ extract: (activity) => activity.baselineSnapshot?.startDate ?? null
345
+ },
346
+ baselineEndDate: {
347
+ valueKind: "date",
348
+ extract: (activity) => activity.baselineSnapshot?.endDate ?? null
349
+ },
350
+ earlyStart: {
351
+ valueKind: "date",
352
+ extract: (activity) => activity.criticalPath?.earlyStart ?? null
353
+ },
354
+ earlyFinish: {
355
+ valueKind: "date",
356
+ extract: (activity) => activity.criticalPath?.earlyFinish ?? null
357
+ },
358
+ lateStart: {
359
+ valueKind: "date",
360
+ extract: (activity) => activity.criticalPath?.lateStart ?? null
361
+ },
362
+ lateFinish: {
363
+ valueKind: "date",
364
+ extract: (activity) => activity.criticalPath?.lateFinish ?? null
365
+ },
366
+ responsableIds: {
367
+ valueKind: "id-array",
368
+ extract: (activity) => activity.responsableIds
369
+ },
370
+ tagIds: { valueKind: "id-array", extract: (activity) => activity.tagIds },
371
+ status: {
372
+ valueKind: "enum",
373
+ order: STATUS_ORDER,
374
+ extract: (activity) => activity.status
375
+ },
376
+ constraintType: {
377
+ valueKind: "enum",
378
+ order: CONSTRAINT_TYPE_ORDER,
379
+ extract: (activity) => activity.constraintType
380
+ },
381
+ calendarId: {
382
+ valueKind: "reference",
383
+ extract: (activity) => activity.calendarId === null ? null : String(activity.calendarId)
384
+ },
385
+ // Normalized to string like calendarId. It is stored as a number, so it used
386
+ // to reach compareValues through the numeric branch while its sibling
387
+ // reference went through the string one — the same field kind comparing two
388
+ // different ways. localeCompare with numeric:true keeps the digit ordering.
389
+ subcontractId: {
390
+ valueKind: "reference",
391
+ extract: (activity) => activity.subcontractId === null ? null : String(activity.subcontractId)
392
+ },
393
+ // Declared boolean, not enum: it is one, and saying so is what lets the enum
394
+ // branch demand an order without inventing one for true/false.
395
+ isCritical: {
396
+ valueKind: "boolean",
397
+ extract: (activity) => activity.isCritical
398
+ }
399
+ };
400
+ function getFieldDescriptor(field) {
401
+ return FIELD_REGISTRY[field] ?? null;
402
+ }
403
+
404
+ // src/internal/filter/evaluate-filter.ts
405
+ function toTargetDate(value) {
406
+ if (value instanceof Date) return value;
407
+ if (typeof value === "string" || typeof value === "number") {
408
+ return new Date(value);
409
+ }
410
+ return new Date(Number.NaN);
411
+ }
412
+ function matchString(value, target, operator) {
413
+ const isAbsent = value === null;
414
+ if (operator === "includes") {
415
+ return !isAbsent && String(value).toLowerCase().includes(target.toLowerCase());
416
+ }
417
+ if (operator === "notIncludes") {
418
+ return isAbsent || !String(value).toLowerCase().includes(target.toLowerCase());
419
+ }
420
+ if (operator === "is") return !isAbsent && String(value) === target;
421
+ if (operator === "isNot") return isAbsent || String(value) !== target;
422
+ return false;
423
+ }
424
+ function matchNumber(value, target, operator) {
425
+ if (value === null || typeof value !== "number") {
426
+ return operator === "notEquals";
427
+ }
428
+ if (operator === "equals") return value === target;
429
+ if (operator === "notEquals") return value !== target;
430
+ if (operator === "greaterThan") return value > target;
431
+ if (operator === "lessThan") return value < target;
432
+ if (operator === "greaterOrEqual") return value >= target;
433
+ if (operator === "lessOrEqual") return value <= target;
434
+ return false;
435
+ }
436
+ function matchDate(value, target, operator) {
437
+ if (!(value instanceof Date)) return false;
438
+ if (operator === "after") return value.getTime() > target.getTime();
439
+ if (operator === "before") return value.getTime() < target.getTime();
440
+ return false;
441
+ }
442
+ function matchIdArray(value, allowed, operator) {
443
+ const ids = Array.isArray(value) ? value : [];
444
+ const intersects = ids.some((id) => allowed.has(String(id)));
445
+ if (operator === "someOf") return intersects;
446
+ if (operator === "notSomeOf") return !intersects;
447
+ return false;
448
+ }
449
+ function matchEnum(value, allowed, operator) {
450
+ const isMember = value !== null && allowed.has(String(value));
451
+ if (operator === "someOf") return isMember;
452
+ if (operator === "notSomeOf") return !isMember;
453
+ return false;
454
+ }
455
+ function toAllowedSet(value) {
456
+ const items = Array.isArray(value) ? value : [value];
457
+ return new Set(items.map((item) => String(item)));
458
+ }
459
+ function matchCriterion(activity, criterion, context) {
460
+ const descriptor = getFieldDescriptor(criterion.field);
461
+ if (descriptor === null) return false;
462
+ const value = descriptor.extract(activity, context);
463
+ const { operator } = criterion;
464
+ if (descriptor.valueKind === "string") {
465
+ return matchString(value, String(criterion.value), operator);
466
+ }
467
+ if (descriptor.valueKind === "number") {
468
+ return matchNumber(value, Number(criterion.value), operator);
469
+ }
470
+ if (descriptor.valueKind === "date") {
471
+ return matchDate(value, toTargetDate(criterion.value), operator);
472
+ }
473
+ if (descriptor.valueKind === "id-array") {
474
+ return matchIdArray(value, toAllowedSet(criterion.value), operator);
475
+ }
476
+ return matchEnum(value, toAllowedSet(criterion.value), operator);
477
+ }
478
+ function matchesCriteria(activity, filter, context) {
479
+ if (filter.criteria.length === 0) return true;
480
+ if (filter.logic === "or") {
481
+ return filter.criteria.some(
482
+ (criterion) => matchCriterion(activity, criterion, context)
483
+ );
484
+ }
485
+ return filter.criteria.every(
486
+ (criterion) => matchCriterion(activity, criterion, context)
487
+ );
488
+ }
489
+ function overlapsRange(activity, range) {
490
+ const taskStart = activity.startDate.getTime();
491
+ const taskEnd = activity.endDate.getTime();
492
+ const windowStart = range.start.getTime();
493
+ const windowEnd = range.end.getTime();
494
+ const fullyInside = taskStart >= windowStart && taskEnd <= windowEnd;
495
+ const startsInside = taskStart >= windowStart && taskStart <= windowEnd;
496
+ const windowStartsInside = windowStart >= taskStart && windowStart <= taskEnd;
497
+ return fullyInside || startsInside || windowStartsInside;
498
+ }
499
+ function addAncestors(matchedId, parentOf, visibleIds) {
500
+ let ancestorId = parentOf(matchedId);
501
+ while (ancestorId !== null && !visibleIds.has(String(ancestorId))) {
502
+ visibleIds.add(String(ancestorId));
503
+ ancestorId = parentOf(ancestorId);
504
+ }
505
+ }
506
+ function evaluateVisibleIds(input) {
507
+ const { activities, parentOf, filter, context } = input;
508
+ const range = filter.dateRange;
509
+ const visibleIds = /* @__PURE__ */ new Set();
510
+ const matchedIds = [];
511
+ for (const activity of activities) {
512
+ const passesCriteria = matchesCriteria(activity, filter, context);
513
+ const passesRange = range === void 0 || overlapsRange(activity, range);
514
+ if (passesCriteria && passesRange) {
515
+ visibleIds.add(String(activity.id));
516
+ matchedIds.push(activity.id);
517
+ }
518
+ }
519
+ for (const matchedId of matchedIds) {
520
+ addAncestors(matchedId, parentOf, visibleIds);
521
+ }
522
+ return visibleIds;
523
+ }
524
+
525
+ // src/internal/filter/context.ts
526
+ var COLLATION_LOCALE = "en";
527
+ function buildFilterContext(hoursPerDay) {
528
+ return { hoursPerDay, locale: COLLATION_LOCALE };
529
+ }
530
+
531
+ // src/internal/filter/validate.ts
532
+ var OPERATORS_BY_KIND = {
533
+ string: /* @__PURE__ */ new Set(["includes", "notIncludes", "is", "isNot"]),
534
+ number: /* @__PURE__ */ new Set([
535
+ "equals",
536
+ "notEquals",
537
+ "greaterThan",
538
+ "lessThan",
539
+ "greaterOrEqual",
540
+ "lessOrEqual"
541
+ ]),
542
+ date: /* @__PURE__ */ new Set(["after", "before"]),
543
+ "id-array": /* @__PURE__ */ new Set(["someOf", "notSomeOf"]),
544
+ enum: /* @__PURE__ */ new Set(["someOf", "notSomeOf"]),
545
+ // Same membership operators as enum: splitting the kinds was about ordering,
546
+ // not about filtering, and these two filter exactly like an enum.
547
+ boolean: /* @__PURE__ */ new Set(["someOf", "notSomeOf"]),
548
+ reference: /* @__PURE__ */ new Set(["someOf", "notSomeOf"])
549
+ };
550
+ function validateCriterion(criterion) {
551
+ const descriptor = getFieldDescriptor(criterion.field);
552
+ if (descriptor === null) return "unknown_field";
553
+ if (!OPERATORS_BY_KIND[descriptor.valueKind].has(criterion.operator)) {
554
+ return "unknown_operator";
555
+ }
556
+ return validateValueForKind(criterion, descriptor.valueKind);
557
+ }
558
+ function validateValueForKind(criterion, valueKind) {
559
+ const { value } = criterion;
560
+ if (valueKind === "id-array" || valueKind === "enum") {
561
+ return Array.isArray(value) ? null : "invalid_value";
562
+ }
563
+ if (Array.isArray(value)) return "invalid_value";
564
+ if (valueKind === "number") {
565
+ return Number.isFinite(Number(value)) ? null : "invalid_value";
566
+ }
567
+ if (valueKind === "date") {
568
+ return isValidDateValue(value) ? null : "invalid_value";
569
+ }
570
+ return null;
571
+ }
572
+ function isValidDateValue(value) {
573
+ if (value instanceof Date) return true;
574
+ if (typeof value === "string" || typeof value === "number") {
575
+ return !Number.isNaN(new Date(value).getTime());
576
+ }
577
+ return false;
578
+ }
579
+
580
+ // src/dispatch/filter.ts
581
+ function isEmptyFilter(filter) {
582
+ return filter.criteria.length === 0 && filter.dateRange === void 0;
583
+ }
584
+ function resolveVisibleIds(adapter, filter, hoursPerDay) {
585
+ const activities = adapter.getAllActivities();
586
+ if (isEmptyFilter(filter)) {
587
+ return new Set(activities.map((activity) => String(activity.id)));
588
+ }
589
+ return evaluateVisibleIds({
590
+ activities,
591
+ parentOf: (activityId) => adapter.getParentId(activityId),
592
+ filter,
593
+ context: buildFilterContext(hoursPerDay)
594
+ });
595
+ }
596
+ function dispatchFilterSet(action, deps) {
597
+ const { adapter, hoursPerDay } = deps;
598
+ for (const criterion of action.criteria) {
599
+ const rejection = validateCriterion(criterion);
600
+ if (rejection !== null) return { ok: false, reason: rejection };
601
+ }
602
+ const filter = action.dateRange === void 0 ? { criteria: action.criteria, logic: action.logic } : {
603
+ criteria: action.criteria,
604
+ logic: action.logic,
605
+ dateRange: action.dateRange
606
+ };
607
+ adapter.setActiveFilter(isEmptyFilter(filter) ? null : filter);
608
+ const visibleIds = resolveVisibleIds(adapter, filter, hoursPerDay);
609
+ const viewState = applyVisibleSet(adapter, visibleIds);
239
610
  const changes = {
240
611
  source: action,
241
612
  activities: [],
@@ -247,6 +618,140 @@ function dispatchVisibilitySet(action, deps) {
247
618
  return { ok: true, changes };
248
619
  }
249
620
 
621
+ // src/internal/hierarchy/root-parent.ts
622
+ var ROOT_PARENT_ID = "0";
623
+ function isRootParent(parent) {
624
+ return parent == null || parent === 0 || parent === ROOT_PARENT_ID;
625
+ }
626
+ function normalizeParentKey(parent) {
627
+ return isRootParent(parent) ? ROOT_PARENT_ID : String(parent);
628
+ }
629
+
630
+ // src/internal/hierarchy/visual-order.ts
631
+ var NOT_SET_SORT_VALUE = Number.MAX_SAFE_INTEGER;
632
+ function getChildrenInVisualOrder(parentId, adapter) {
633
+ const children = collectChildrenSnapshots(parentId, adapter);
634
+ const userOrder = adapter.getOrderComparator?.() ?? null;
635
+ children.sort(
636
+ userOrder === null ? compareActivitiesInVisualOrder : (a, b) => userOrder(a, b) || compareActivitiesInVisualOrder(a, b)
637
+ );
638
+ return children.map((a) => String(a.id));
639
+ }
640
+ function iterateInVisualOrder(adapter) {
641
+ const result = [];
642
+ const visit = (activity) => {
643
+ result.push(activity);
644
+ const childIds = getChildrenInVisualOrder(String(activity.id), adapter);
645
+ for (const childId of childIds) {
646
+ const child = adapter.getActivity(childId);
647
+ if (child) visit(child);
648
+ }
649
+ };
650
+ const rootIds = getChildrenInVisualOrder(ROOT_PARENT_ID, adapter);
651
+ for (const rootId of rootIds) {
652
+ const root = adapter.getActivity(rootId);
653
+ if (root) visit(root);
654
+ }
655
+ return result;
656
+ }
657
+ function findPreviousNonSelectedSibling(taskId, selected, adapter) {
658
+ const activity = adapter.getActivity(taskId);
659
+ if (!activity) return null;
660
+ const parentKey = parentKeyOf(activity);
661
+ const siblings = getChildrenInVisualOrder(parentKey, adapter);
662
+ const idx = siblings.findIndex((id) => String(id) === String(taskId));
663
+ if (idx <= 0) return null;
664
+ for (let i = idx - 1; i >= 0; i--) {
665
+ const candidateId = siblings[i];
666
+ if (candidateId === void 0) continue;
667
+ if (!setHas(selected, candidateId)) return candidateId;
668
+ }
669
+ return null;
670
+ }
671
+ function visualIndexInParent(taskId, adapter) {
672
+ const activity = adapter.getActivity(taskId);
673
+ if (!activity) return -1;
674
+ const parentKey = parentKeyOf(activity);
675
+ const siblings = getChildrenInVisualOrder(parentKey, adapter);
676
+ return siblings.findIndex((id) => String(id) === String(taskId));
677
+ }
678
+ function collectChildrenSnapshots(parentId, adapter) {
679
+ const key = String(parentId);
680
+ if (key === "0") {
681
+ return adapter.getAllActivities().filter((a) => a.parentId === null);
682
+ }
683
+ const childIds = adapter.getChildren(parentId);
684
+ const out = [];
685
+ for (const id of childIds) {
686
+ const snap = adapter.getActivity(id);
687
+ if (snap) out.push(snap);
688
+ }
689
+ return out;
690
+ }
691
+ function compareActivitiesInVisualOrder(a, b) {
692
+ const ac = correlativeIdOf(a);
693
+ const bc = correlativeIdOf(b);
694
+ if (ac !== bc) return ac - bc;
695
+ return String(a.id).localeCompare(String(b.id));
696
+ }
697
+ function correlativeIdOf(activity) {
698
+ const raw = activity.correlativeId;
699
+ const n = typeof raw === "number" ? raw : Number(raw);
700
+ return Number.isFinite(n) ? n : NOT_SET_SORT_VALUE;
701
+ }
702
+ function parentKeyOf(activity) {
703
+ const parentId = activity.parentId;
704
+ if (parentId === null) return "0";
705
+ return parentId;
706
+ }
707
+ function setHas(set, id) {
708
+ if (set.has(id)) return true;
709
+ return set.has(String(id));
710
+ }
711
+
712
+ // src/dispatch/shared/collect-branch-order.ts
713
+ function collectBranchOrder(adapter) {
714
+ const branches = [];
715
+ const visit = (parentId) => {
716
+ const childIds = getChildrenInVisualOrder(parentId, adapter);
717
+ if (childIds.length > 1) {
718
+ branches.push({ parentId, childIds });
719
+ }
720
+ for (const childId of childIds) {
721
+ visit(childId);
722
+ }
723
+ };
724
+ visit(ROOT_PARENT_ID);
725
+ return branches;
726
+ }
727
+
728
+ // src/dispatch/order.ts
729
+ function validateRule(rule) {
730
+ if (getFieldDescriptor(rule.field) === null) return "unknown_field";
731
+ if (rule.direction !== "asc" && rule.direction !== "desc") {
732
+ return "unknown_operator";
733
+ }
734
+ return null;
735
+ }
736
+ function dispatchSortSet(action, deps) {
737
+ const { adapter } = deps;
738
+ for (const rule of action.rules) {
739
+ const rejection = validateRule(rule);
740
+ if (rejection !== null) return { ok: false, reason: rejection };
741
+ }
742
+ const order = action.rules.length === 0 ? null : { rules: action.rules };
743
+ adapter.setActiveOrder(order);
744
+ const changes = {
745
+ source: action,
746
+ activities: [],
747
+ links: [],
748
+ calendars: [],
749
+ trackingEvents: [],
750
+ order: collectBranchOrder(adapter)
751
+ };
752
+ return { ok: true, changes };
753
+ }
754
+
250
755
  // src/columns/text/constants.ts
251
756
  var TEXT = "text";
252
757
 
@@ -628,19 +1133,22 @@ var ACTIVITY_TYPE = {
628
1133
  MILESTONE: "milestone"
629
1134
  };
630
1135
  var TIMING = {
631
- // 16ms = full frame budget; 8ms = yield twice per frame so the
632
- // browser still has half a frame to paint and handle input.
633
1136
  YIELD_SLICE_MS: 8
634
1137
  };
635
1138
 
636
1139
  // src/shared/timing.ts
637
1140
  var isNode = typeof window === "undefined";
638
- var channel = !isNode && typeof MessageChannel !== "undefined" ? new MessageChannel() : null;
1141
+ var hasMessageChannel = !isNode && typeof MessageChannel !== "undefined";
639
1142
  function yieldToBrowser() {
640
- if (isNode || !channel) return Promise.resolve();
1143
+ if (!hasMessageChannel) return Promise.resolve();
641
1144
  return new Promise((resolve) => {
642
- channel.port1.onmessage = () => resolve();
643
- channel.port2.postMessage(null);
1145
+ const oneShotChannel = new MessageChannel();
1146
+ oneShotChannel.port1.onmessage = () => {
1147
+ oneShotChannel.port1.close();
1148
+ oneShotChannel.port2.close();
1149
+ resolve();
1150
+ };
1151
+ oneShotChannel.port2.postMessage(null);
644
1152
  });
645
1153
  }
646
1154
 
@@ -1248,7 +1756,6 @@ function calculateSuccessorStartFromLink(predecessor, successor, link, adapter)
1248
1756
  startDate: date2,
1249
1757
  durationHours: sourceLag,
1250
1758
  task: predecessor
1251
- // sourceLag always on predecessor calendar
1252
1759
  });
1253
1760
  }
1254
1761
  if (targetLag !== 0) {
@@ -1256,7 +1763,6 @@ function calculateSuccessorStartFromLink(predecessor, successor, link, adapter)
1256
1763
  startDate: date2,
1257
1764
  durationHours: targetLag,
1258
1765
  task: successor
1259
- // targetLag always on successor calendar
1260
1766
  });
1261
1767
  }
1262
1768
  if (trueLag !== 0) {
@@ -1264,7 +1770,6 @@ function calculateSuccessorStartFromLink(predecessor, successor, link, adapter)
1264
1770
  startDate: date2,
1265
1771
  durationHours: trueLag,
1266
1772
  task: successor
1267
- // trueLag always on successor calendar
1268
1773
  });
1269
1774
  }
1270
1775
  if (successor.durationHours === 0) {
@@ -1553,15 +2058,6 @@ function isSummaryActivity(activity, adapter) {
1553
2058
  return isSummary(activity.type, adapter.getChildren(activity.id).length > 0);
1554
2059
  }
1555
2060
 
1556
- // src/internal/hierarchy/root-parent.ts
1557
- var ROOT_PARENT_ID = "0";
1558
- function isRootParent(parent) {
1559
- return parent == null || parent === 0 || parent === ROOT_PARENT_ID;
1560
- }
1561
- function normalizeParentKey(parent) {
1562
- return isRootParent(parent) ? ROOT_PARENT_ID : String(parent);
1563
- }
1564
-
1565
2061
  // src/autoscheduler/engine/alap-pass.ts
1566
2062
  async function alapPass(reversedIds, links, asapPlans, adapter, _options, isCurrent) {
1567
2063
  const plans = new Map(asapPlans);
@@ -1914,8 +2410,6 @@ function parseEntry(entry) {
1914
2410
  lag = sign === "-" ? -value : value;
1915
2411
  }
1916
2412
  return {
1917
- // frozen logic: invariant guaranteed by ENTRY_RE — capture group 1 `(\d+)`
1918
- // is non-optional, so a successful match always defines correlativeId
1919
2413
  correlativeId,
1920
2414
  type,
1921
2415
  lag
@@ -2022,36 +2516,6 @@ function lagDaysToHours(lagDays, hoursPerDay) {
2022
2516
 
2023
2517
  // src/autoscheduler/date-math/impl-current.ts
2024
2518
  var currentImpl = {
2025
- /**
2026
- * Legacy rule observed empirically from 4 fixtures:
2027
- *
2028
- * midnight = setHours(0, 0, 0, 0) on a copy of rawDate (local TZ)
2029
- * if (midnight.getTime() === rawDate.getTime())
2030
- * return calendar.getClosestWorkTime(raw, 'future') // snap forward
2031
- * else
2032
- * return midnight // preserve day
2033
- *
2034
- * Rationale (inferred): when the user types/picks a date AT local
2035
- * midnight (e.g., Saturday 00:00 local = "just Saturday"), legacy
2036
- * interprets it as "start of the week/day" and snaps to the next
2037
- * working hour. When they pick a time WITHIN a day (e.g., Sunday
2038
- * 08:00 local), legacy treats it as "this specific day" and preserves
2039
- * the day at local midnight, even if the day is non-working.
2040
- *
2041
- * Fixture evidence:
2042
- * - test3: raw=Apr 26 06:00Z (Sun 08:00 CEST) → Apr 25 22:00Z (Sun 00:00 CEST)
2043
- * - create-rename-drag: raw=Apr 23 22:00Z (Fri 00:00 CEST) → Apr 24 06:00Z (snap)
2044
- * - create-rename-drag: raw=Apr 25 22:00Z (Sun 00:00 CEST) → Apr 27 06:00Z (snap)
2045
- *
2046
- * UTC contract: `setUTCHours(0)` makes the normalization deterministic
2047
- * regardless of the runtime's local TZ. The work-calendar package (and
2048
- * any future strict-UTC calendar engine) requires UTC-keyed inputs, so
2049
- * the day boundary must be computed in UTC too. Legacy fixtures
2050
- * recorded under local-TZ midnight may need their `metadata.tz` honored
2051
- * upstream — `pipeline-context.ts` plumbs that field but this function
2052
- * does not yet consume it (its caller supplies a raw Date with the
2053
- * recorded instant intact).
2054
- */
2055
2519
  rawInputToConstraintDate(rawDate, calendar) {
2056
2520
  const midnight = new Date(rawDate);
2057
2521
  midnight.setUTCHours(0, 0, 0, 0);
@@ -2067,16 +2531,6 @@ var currentImpl = {
2067
2531
  }
2068
2532
  return midnight;
2069
2533
  },
2070
- /**
2071
- * Legacy behavior replicated (from `modifyLagCustom.js:29-35`):
2072
- * `calendar.calculateDuration(sourceDate, targetDate)`
2073
- *
2074
- * Returns working hours between the two dates according to the task's
2075
- * calendar (working days + working hours range). Positive when
2076
- * targetDate > sourceDate, zero when aligned. Negative branch
2077
- * exists in calendar.calculateDuration (reverse walk) but our
2078
- * current usage always has target after source post-move.
2079
- */
2080
2534
  computeLagBetweenTasks(sourceDate, targetDate, calendar) {
2081
2535
  return calendar.calculateDuration(sourceDate, targetDate);
2082
2536
  }
@@ -2113,36 +2567,16 @@ var AutoScheduler = class {
2113
2567
  getCurrentCalculationId() {
2114
2568
  return this.currentCalculationId;
2115
2569
  }
2116
- /**
2117
- * Invalidates the cached full-graph topological order. Call after any
2118
- * structural mutation: link create/delete, activity create/delete,
2119
- * activity reparent (indent/outdent/move).
2120
- */
2121
2570
  invalidateTopoCache() {
2122
2571
  this.topoCache.invalidate();
2123
2572
  }
2124
- /**
2125
- * Invalidates the cached expanded parent-link set. Call on link create /
2126
- * delete, activity reparent, activity create / delete, and on the rare
2127
- * field edits that affect chain-pruning (`duration`, `auto_scheduling`).
2128
- */
2129
2573
  invalidateExpandedLinksCache() {
2130
2574
  this.expandedLinksCache.invalidate();
2131
2575
  }
2132
- /**
2133
- * Convenience: invalidate every cache held by the scheduler.
2134
- */
2135
2576
  invalidateAllCaches() {
2136
2577
  this.topoCache.invalidate();
2137
2578
  this.expandedLinksCache.invalidate();
2138
2579
  }
2139
- /**
2140
- * Main entry point. Runs the full scheduling algorithm.
2141
- *
2142
- * Returns a ScheduleResult with the plans, updated IDs, and status.
2143
- * The caller (integration layer) is responsible for applying the results
2144
- * back to gantt.
2145
- */
2146
2580
  async schedule(options = {}) {
2147
2581
  const calculationId = ++this.currentCalculationId;
2148
2582
  const isCurrent = createIsCurrent(
@@ -2511,16 +2945,6 @@ function sortDeepestFirst(ids, depths) {
2511
2945
  // src/internal/post-processors/runner.ts
2512
2946
  var POST_PROCESSORS = {
2513
2947
  updateActivityDuration: runUpdateActivityDuration,
2514
- // `updateMilestoneData` eliminado del registro (2026-06-10, MIL-B2):
2515
- // post-processor fantasma — ninguna pipeline lo emitía. Su garantía
2516
- // (duration=0, end_date=start_date al convertir a milestone) vive en
2517
- // durationPipeline (fix MIL-B1) + calculateEndDate(start, 0) === start
2518
- // (test en calendar/adapter.test.ts). Ver BUGS_milestones_2026-06-10.md
2519
- // (vault).
2520
- // `executeFixForConstraints` (legacy) se reimplementa fuera de este registro
2521
- // como `revertNoOpConstraintEdit` (post-pass del dispatch de constraint, tras
2522
- // la cascada) — NO como post-processor por-pipeline. `recordLastStartDate`
2523
- // guarda el baseline del gesto (start al editar duración) que ese revert lee.
2524
2948
  updateTaskTiming: runNoOp("updateTaskTiming"),
2525
2949
  adjustLinkLagOnTaskMove,
2526
2950
  recordLastStartDate: runRecordLastStartDate
@@ -2943,7 +3367,6 @@ function buildDescendantCascade(activity, newValue, autoScheduling, hierarchy, r
2943
3367
  const descendants = hierarchy.getDescendantIds(activity.id);
2944
3368
  return descendants.map((id) => ({
2945
3369
  activityId: id,
2946
- // Descendants of a recursive progress change inherit the primary value.
2947
3370
  fields: descendantFields(
2948
3371
  newValue,
2949
3372
  autoScheduling,
@@ -3256,7 +3679,6 @@ var startDatePipeline = {
3256
3679
  {
3257
3680
  startDate: finalStart,
3258
3681
  ...setEndDate(finalEnd),
3259
- // Sanea la duration de un milestone corrupto en el mismo move.
3260
3682
  ...milestoneActivity ? setDuration(0) : {},
3261
3683
  ...setConstraintTypeImplied(),
3262
3684
  ...setConstraintDate(constraintDate)
@@ -3535,9 +3957,11 @@ var calendarIdPipeline = {
3535
3957
  if (isEmpty(value)) return parseError("empty_calendar");
3536
3958
  return parsed(value);
3537
3959
  },
3538
- validate(activity, _oldValue, newValue) {
3960
+ validate(activity, _oldValue, newValue, ctx) {
3539
3961
  if (isUnchangedCalendar(activity.calendarId, newValue))
3540
3962
  return invalid("unchanged");
3963
+ if (!ctx.calendars.getCalendar(newValue))
3964
+ return invalid("unknown_calendar");
3541
3965
  return valid();
3542
3966
  },
3543
3967
  transform(activity, newValue, ctx) {
@@ -3752,9 +4176,6 @@ var COLUMN_PIPELINES = /* @__PURE__ */ new Map([
3752
4176
  [COLUMN.CONSTRAINT_DATE, constraintDatePipeline],
3753
4177
  [COLUMN.CALENDAR_ID, calendarIdPipeline],
3754
4178
  [COLUMN.CUSTOM_ID, customIdPipeline],
3755
- // Naming exception: `subcontractId` stays camelCase for parity with
3756
- // production (backend BD + legacy column + `BackendActivityInput.subcontractId`).
3757
- // Snake-case unification deferred to a global pass.
3758
4179
  [COLUMN.SUBCONTRACT_ID, subcontractIdPipeline],
3759
4180
  [COLUMN.RESPONSABLES, responsablesPipeline],
3760
4181
  [COLUMN.TAGS, tagsPipeline]
@@ -3879,7 +4300,13 @@ function cloneCriticalPath(value) {
3879
4300
  };
3880
4301
  }
3881
4302
 
4303
+ // src/shared/clone-domain-value.ts
4304
+ function cloneDomainValue(value) {
4305
+ return structuredClone(value);
4306
+ }
4307
+
3882
4308
  // src/dispatch/shared/snapshots.ts
4309
+ var YIELD_EVERY_N_ENTRIES = 200;
3883
4310
  function collectTouchedIds(primary, changes) {
3884
4311
  const ids = /* @__PURE__ */ new Set([String(primary)]);
3885
4312
  for (const mutation of changes.cascadeMutations ?? []) {
@@ -3887,9 +4314,12 @@ function collectTouchedIds(primary, changes) {
3887
4314
  }
3888
4315
  return ids;
3889
4316
  }
3890
- function snapshotActivities(adapter, ids) {
4317
+ async function snapshotActivities(adapter, ids) {
3891
4318
  const out = /* @__PURE__ */ new Map();
4319
+ let processed = 0;
3892
4320
  for (const id of ids) {
4321
+ processed += 1;
4322
+ if (processed % YIELD_EVERY_N_ENTRIES === 0) await yieldToBrowser();
3893
4323
  const a = adapter.getActivity(id);
3894
4324
  if (a) out.set(id, structuredCloneActivity(a));
3895
4325
  }
@@ -3898,6 +4328,10 @@ function snapshotActivities(adapter, ids) {
3898
4328
  function structuredCloneActivity(activity) {
3899
4329
  return cloneCoreActivity(activity);
3900
4330
  }
4331
+ function snapshotSingleActivity(adapter, activityId) {
4332
+ const liveActivity = adapter.getActivity(activityId);
4333
+ return liveActivity ? cloneCoreActivity(liveActivity) : null;
4334
+ }
3901
4335
  function applyFieldChanges(adapter, activityId, changes) {
3902
4336
  applyCanonicalPatch(adapter, activityId, changes.patch);
3903
4337
  for (const mutation of changes.cascadeMutations ?? []) {
@@ -3914,35 +4348,69 @@ function applyCanonicalPatch(adapter, activityId, patch) {
3914
4348
  setActivityFieldDynamic(adapter, activityId, key, value);
3915
4349
  }
3916
4350
  }
3917
- function buildActivityChanges(adapter, before, touched) {
4351
+ async function buildActivityChanges(adapter, before, touched, correlativeBefore) {
3918
4352
  const out = [];
4353
+ let processed = 0;
3919
4354
  for (const id of touched) {
3920
- const afterSnap = adapter.getActivity(id);
3921
- if (!afterSnap) {
3922
- out.push({ id, kind: "deleted", after: null });
3923
- continue;
3924
- }
3925
- const beforeSnap = before.get(id);
3926
- const diff = diffActivity(beforeSnap, afterSnap);
3927
- if (beforeSnap && Object.keys(diff).length === 0) continue;
3928
- if (!beforeSnap) {
3929
- out.push({
3930
- id,
3931
- kind: "created",
3932
- fields: diff,
3933
- after: structuredCloneActivity(afterSnap)
3934
- });
3935
- } else {
3936
- out.push({
3937
- id,
3938
- kind: "updated",
3939
- fields: diff,
3940
- after: structuredCloneActivity(afterSnap)
3941
- });
3942
- }
4355
+ processed += 1;
4356
+ if (processed % YIELD_EVERY_N_ENTRIES === 0) await yieldToBrowser();
4357
+ const entry = buildEntryForTouchedId(
4358
+ adapter,
4359
+ before,
4360
+ id,
4361
+ correlativeBefore
4362
+ );
4363
+ if (entry) out.push(entry);
3943
4364
  }
3944
4365
  return out;
3945
4366
  }
4367
+ function buildEntryForTouchedId(adapter, before, activityId, correlativeBefore) {
4368
+ const afterSnap = adapter.getActivity(activityId);
4369
+ if (!afterSnap) {
4370
+ return { id: activityId, kind: "deleted", after: null };
4371
+ }
4372
+ const beforeSnap = before.get(activityId);
4373
+ if (!beforeSnap && correlativeBefore?.has(activityId)) {
4374
+ return buildCorrelativeOnlyEntry(
4375
+ activityId,
4376
+ correlativeBefore.get(activityId),
4377
+ afterSnap
4378
+ );
4379
+ }
4380
+ const diff = diffActivity(beforeSnap, afterSnap);
4381
+ mergeCorrelativeShiftIntoDiff(diff, correlativeBefore, activityId, afterSnap);
4382
+ if (beforeSnap && Object.keys(diff).length === 0) return null;
4383
+ return {
4384
+ id: activityId,
4385
+ kind: beforeSnap ? "updated" : "created",
4386
+ fields: diff,
4387
+ after: structuredCloneActivity(afterSnap)
4388
+ };
4389
+ }
4390
+ function buildCorrelativeOnlyEntry(activityId, correlativeIdBefore, liveActivity) {
4391
+ if (correlativeIdBefore === liveActivity.correlativeId) return null;
4392
+ return {
4393
+ id: activityId,
4394
+ kind: "updated",
4395
+ fields: {
4396
+ correlativeId: {
4397
+ before: correlativeIdBefore,
4398
+ after: liveActivity.correlativeId
4399
+ }
4400
+ },
4401
+ after: structuredCloneActivity(liveActivity)
4402
+ };
4403
+ }
4404
+ function mergeCorrelativeShiftIntoDiff(diff, correlativeBefore, activityId, liveActivity) {
4405
+ if (!correlativeBefore?.has(activityId)) return;
4406
+ if (Object.hasOwn(diff, "correlativeId")) return;
4407
+ const shiftedFrom = correlativeBefore.get(activityId);
4408
+ if (shiftedFrom === liveActivity.correlativeId) return;
4409
+ diff.correlativeId = {
4410
+ before: shiftedFrom,
4411
+ after: liveActivity.correlativeId
4412
+ };
4413
+ }
3946
4414
  function diffActivity(before, after) {
3947
4415
  const fields = {};
3948
4416
  const beforeRec = before ?? {};
@@ -3950,11 +4418,19 @@ function diffActivity(before, after) {
3950
4418
  const keys = /* @__PURE__ */ new Set([...Object.keys(beforeRec), ...Object.keys(afterRec)]);
3951
4419
  for (const k of keys) {
3952
4420
  if (Object.hasOwn(beforeRec, k) !== Object.hasOwn(afterRec, k) || !fieldValueEqual(beforeRec[k], afterRec[k])) {
3953
- fields[k] = { before: beforeRec[k], after: afterRec[k] };
4421
+ fields[k] = {
4422
+ before: cloneFieldValue(beforeRec[k]),
4423
+ after: cloneFieldValue(afterRec[k])
4424
+ };
3954
4425
  }
3955
4426
  }
3956
4427
  return fields;
3957
4428
  }
4429
+ function cloneFieldValue(value) {
4430
+ const isPrimitive = value === null || typeof value !== "object";
4431
+ if (isPrimitive) return value;
4432
+ return cloneDomainValue(value);
4433
+ }
3958
4434
  function fieldValueEqual(left, right) {
3959
4435
  if (Object.is(left, right)) return true;
3960
4436
  if (left instanceof Date && right instanceof Date) {
@@ -4631,12 +5107,6 @@ function mutateTheDateToFutureOrPastInBaseRestriction(dateBaseToCalculate, restr
4631
5107
 
4632
5108
  // src/critical-path/legacy/base/parents-calculations/forward.js
4633
5109
  var CalculateForwardParentsWithLinks = class {
4634
- /**
4635
- * Initializes the calculator with linked activities, the current activity, and the gantt instance.
4636
- * @param {Array<Object>} linkedActivitiesData - Array of linked activities data.
4637
- * @param {Object} activity - The current activity object.
4638
- * @param {Object} gantt - The gantt instance.
4639
- */
4640
5110
  constructor(linkedActivitiesData, activity, gantt) {
4641
5111
  this.linkedActivitiesData = linkedActivitiesData;
4642
5112
  this.activity = activity;
@@ -4648,10 +5118,6 @@ var CalculateForwardParentsWithLinks = class {
4648
5118
  );
4649
5119
  }
4650
5120
  }
4651
- /**
4652
- * Main method to perform the calculation.
4653
- * @returns {Object} The calculation result.
4654
- */
4655
5121
  calculate() {
4656
5122
  const calculationsFromLinks = this.calculateLinks();
4657
5123
  const maxEfFromLinks = getMaxEarlyStartSet(calculationsFromLinks);
@@ -4664,10 +5130,6 @@ var CalculateForwardParentsWithLinks = class {
4664
5130
  }
4665
5131
  return maxEfFromLinks;
4666
5132
  }
4667
- /**
4668
- * Calculates the dates based on the linked activities.
4669
- * @returns {Array<Object>} Array of calculation results from links.
4670
- */
4671
5133
  calculateLinks() {
4672
5134
  const calculations = [];
4673
5135
  for (const linkedActivity of this.linkedActivitiesData) {
@@ -4698,11 +5160,6 @@ var CalculateForwardParentsWithLinks = class {
4698
5160
  }
4699
5161
  return calculations;
4700
5162
  }
4701
- /**
4702
- * Handles the 'Start No Earlier Than' (SNET) constraint.
4703
- * @param {Object|null} maxEfFromLinks - The maximum early finish from links.
4704
- * @returns {Object} The calculation result considering the constraint.
4705
- */
4706
5163
  handleSNETConstraint(maxEfFromLinks) {
4707
5164
  const restriction = calculateRestrictionSnet({
4708
5165
  duration: this.activity.duration,
@@ -4715,11 +5172,6 @@ var CalculateForwardParentsWithLinks = class {
4715
5172
  }
4716
5173
  return maxEfFromLinks.ef > restriction.ef ? maxEfFromLinks : restriction;
4717
5174
  }
4718
- /**
4719
- * Handles the 'Finish No Later Than' (FNLT) constraint.
4720
- * @param {Object|null} maxEfFromLinks - The maximum early finish from links.
4721
- * @returns {Object} The calculation result considering the constraint.
4722
- */
4723
5175
  handleFNLTConstraint(maxEfFromLinks) {
4724
5176
  const restriction = calculateRestriction({
4725
5177
  duration: -this.activity.duration,
@@ -4732,11 +5184,6 @@ var CalculateForwardParentsWithLinks = class {
4732
5184
  }
4733
5185
  return maxEfFromLinks.ef > restriction.ef ? restriction : maxEfFromLinks;
4734
5186
  }
4735
- /**
4736
- * Calculates dates for 'Start to Start' (SS) link type.
4737
- * @param {Object} params - Parameters containing lag and predecessor early start.
4738
- * @returns {Object} The calculation result.
4739
- */
4740
5187
  calculateSSLink({ lag, predecessorEs }) {
4741
5188
  const esLinked = mutateDate({
4742
5189
  linkType: "ss",
@@ -4767,11 +5214,6 @@ var CalculateForwardParentsWithLinks = class {
4767
5214
  );
4768
5215
  return { es, ef };
4769
5216
  }
4770
- /**
4771
- * Calculates dates for 'Finish to Finish' (FF) link type.
4772
- * @param {Object} params - Parameters containing lag and predecessor early finish.
4773
- * @returns {Object} The calculation result.
4774
- */
4775
5217
  calculateFFLink({ lag, predecessorEf }) {
4776
5218
  const efLinked = mutateDate({
4777
5219
  linkType: "ff",
@@ -4802,11 +5244,6 @@ var CalculateForwardParentsWithLinks = class {
4802
5244
  }
4803
5245
  return { es, ef };
4804
5246
  }
4805
- /**
4806
- * Calculates dates for 'Finish to Start' (FS) link type.
4807
- * @param {Object} params - Parameters containing lag and predecessor early finish.
4808
- * @returns {Object} The calculation result.
4809
- */
4810
5247
  calculateFSLink({ lag, predecessorEf }) {
4811
5248
  let efLinked = predecessorEf;
4812
5249
  if (lag === 0) {
@@ -4831,11 +5268,6 @@ var CalculateForwardParentsWithLinks = class {
4831
5268
  );
4832
5269
  return { es, ef };
4833
5270
  }
4834
- /**
4835
- * Calculates dates for 'Start to Finish' (SF) link type.
4836
- * @param {Object} params - Parameters containing lag, predecessor early start, and finish.
4837
- * @returns {Object} The calculation result.
4838
- */
4839
5271
  calculateSFLink({ lag, predecessorEs }) {
4840
5272
  const ef = addDurationToDate(
4841
5273
  this.activityCalendar,
@@ -5141,14 +5573,6 @@ var CalculateBackwardParentsLinks = class {
5141
5573
  });
5142
5574
  return newDate;
5143
5575
  }
5144
- /**
5145
- * Determines if a given date corresponds to the initial work hour of an activity as defined in the activity calendar.
5146
- * This function retrieves the first work interval from the activity calendar and compares the hour portion
5147
- * of the input date to the start hour of the work interval.
5148
- * @param {object} activityCalendar - The calendar object containing work hours and scheduling information for the activity.
5149
- * @param {Date} date - The date to check against the activity's start hour.
5150
- * @returns {boolean} True if the hour of the input date matches the initial work hour of the activity; otherwise, false.
5151
- */
5152
5576
  isActivityInInitHour(activityCalendar, date2) {
5153
5577
  const normalizedDate = date2 instanceof Date ? date2 : new Date(date2);
5154
5578
  const shifts = activityCalendar.getWorkHours(normalizedDate);
@@ -5489,22 +5913,12 @@ var calculation_of_parent_default = CalculationOfParent;
5489
5913
 
5490
5914
  // src/critical-path/legacy/base/third-level-activities/index.js
5491
5915
  var ThirdLevelActivityIdentifier = class {
5492
- /**
5493
- * Constructs the ThirdLevelActivityIdentifier class.
5494
- * @param {Object} params - The parameters object.
5495
- * @param {Object} params.gantt - The Gantt chart instance.
5496
- * @param {Object} params.filters - Filters for tasks.
5497
- * @param {string} params.linkProperty - The property name for links.
5498
- */
5499
5916
  constructor({ gantt, linkProperty }) {
5500
5917
  this.gantt = gantt;
5501
5918
  this.linkProperty = linkProperty;
5502
5919
  this.structureOfParents = /* @__PURE__ */ new Map();
5503
5920
  this.singleParents = /* @__PURE__ */ new Map();
5504
5921
  }
5505
- /**
5506
- * Identifies third-level activities and populates the structureOfParents map.
5507
- */
5508
5922
  identifyThirdLevelActivities() {
5509
5923
  try {
5510
5924
  const parents = this.getFirstLevelParents();
@@ -5529,18 +5943,9 @@ var ThirdLevelActivityIdentifier = class {
5529
5943
  throw e;
5530
5944
  }
5531
5945
  }
5532
- /**
5533
- * Retrieves the first-level parent tasks.
5534
- * @returns {Array<Object>} Array of parent tasks.
5535
- */
5536
5946
  getFirstLevelParents() {
5537
5947
  return this.gantt.getTaskByTime().filter(filters_default.byFirstLevel).filter(filters_default.filterByParentType);
5538
5948
  }
5539
- /**
5540
- * Processes each activity under a parent task.
5541
- * @param {Object} parentActivity - The parent activity to process.
5542
- * @returns {Object} Processed data including parentsIds, allTasks, activitiesByLevel.
5543
- */
5544
5949
  processEachActivity(parentActivity) {
5545
5950
  const parentsIds = /* @__PURE__ */ new Set();
5546
5951
  const allTasks = /* @__PURE__ */ new Set();
@@ -5555,10 +5960,6 @@ var ThirdLevelActivityIdentifier = class {
5555
5960
  activitiesByLevel
5556
5961
  };
5557
5962
  }
5558
- /**
5559
- * Initializes the parent activity in singleParents map.
5560
- * @param {Object} parentActivity - The parent activity.
5561
- */
5562
5963
  initializeParent(parentActivity) {
5563
5964
  const parentId = Number(parentActivity.id);
5564
5965
  const hasLink = Boolean(parentActivity[this.linkProperty]?.length);
@@ -5569,13 +5970,6 @@ var ThirdLevelActivityIdentifier = class {
5569
5970
  childrens: []
5570
5971
  });
5571
5972
  }
5572
- /**
5573
- * Processes a single activity.
5574
- * @param {Object} activity - The activity to process.
5575
- * @param {Set<number>} parentsIds - Set of parent IDs.
5576
- * @param {Set<number>} allTasks - Set of all task IDs.
5577
- * @param {Map<number, Map<number, Array<Object>>>} activitiesByLevel - Activities grouped by level.
5578
- */
5579
5973
  processActivity(activity, parentsIds, allTasks, activitiesByLevel) {
5580
5974
  const activityId = Number(activity.id);
5581
5975
  const parentId = Number(activity.parent);
@@ -5590,27 +5984,12 @@ var ThirdLevelActivityIdentifier = class {
5590
5984
  }
5591
5985
  this.addActivityToLevel(activity, activitiesByLevel);
5592
5986
  }
5593
- /**
5594
- * Checks if an activity is a project (parent activity).
5595
- * @param {Object} activity - The activity to check.
5596
- * @returns {boolean} True if the activity is a project.
5597
- */
5598
5987
  isProjectActivity(activity) {
5599
5988
  return activity.type === "project";
5600
5989
  }
5601
- /**
5602
- * Checks if an activity has a link.
5603
- * @param {Object} activity - The activity to check.
5604
- * @returns {boolean} True if the activity has a link.
5605
- */
5606
5990
  hasLink(activity) {
5607
5991
  return Boolean(activity[this.linkProperty]?.length);
5608
5992
  }
5609
- /**
5610
- * Adds parent information to singleParents map.
5611
- * @param {Object} activity - The parent activity.
5612
- * @param {Set<number>} parentsIds - Set of parent IDs.
5613
- */
5614
5993
  addParentInfo(activity, parentsIds) {
5615
5994
  const parentId = Number(activity.id);
5616
5995
  const level = activity["$level"];
@@ -5623,27 +6002,12 @@ var ThirdLevelActivityIdentifier = class {
5623
6002
  parentsIds.add(parentId);
5624
6003
  this.singleParents.set(parentId, parentInfo);
5625
6004
  }
5626
- /**
5627
- * Checks if a parent exists in singleParents map.
5628
- * @param {number} parentId - The parent ID to check.
5629
- * @returns {boolean} True if the parent exists.
5630
- */
5631
6005
  doesParentExist(parentId) {
5632
6006
  return this.singleParents.has(parentId);
5633
6007
  }
5634
- /**
5635
- * Adds a child activity to its parent in singleParents map.
5636
- * @param {number} parentId - The parent ID.
5637
- * @param {number} activityId - The child activity ID.
5638
- */
5639
6008
  addChildToParent(parentId, activityId) {
5640
6009
  this.singleParents.get(parentId).childrens.push(activityId);
5641
6010
  }
5642
- /**
5643
- * Adds an activity to the activitiesByLevel map.
5644
- * @param {Object} activity - The activity to add.
5645
- * @param {Map<number, Map<number, Array<Object>>>} activitiesByLevel - Activities grouped by level.
5646
- */
5647
6011
  addActivityToLevel(activity, activitiesByLevel) {
5648
6012
  const levelKey = activity["$level"];
5649
6013
  const parentKey = Number(activity.parent);
@@ -5660,33 +6024,15 @@ var ThirdLevelActivityIdentifier = class {
5660
6024
  calculated: false
5661
6025
  });
5662
6026
  }
5663
- /**
5664
- * Retrieves all levels from activitiesByLevel map.
5665
- * @param {Map<number, Map<number, Array<Object>>>} activitiesByLevel - Activities grouped by level.
5666
- * @returns {Set<number>} Set of all levels.
5667
- */
5668
6027
  getAllLevels(activitiesByLevel) {
5669
6028
  return new Set(activitiesByLevel.keys());
5670
6029
  }
5671
- /**
5672
- * Determines the deepest level from a set of levels.
5673
- * @param {Set<number>} allLevels - Set of all levels.
5674
- * @returns {number} The deepest level.
5675
- */
5676
6030
  getDeepestLevel(allLevels) {
5677
6031
  if (allLevels.size === 0) {
5678
6032
  return 0;
5679
6033
  }
5680
6034
  return Math.max(...allLevels);
5681
6035
  }
5682
- /**
5683
- * Creates the result object for a parent activity.
5684
- * @param {Object} parent - The parent activity.
5685
- * @param {Object} processPayload - The processed data.
5686
- * @param {number} deepestLevel - The deepest level found.
5687
- * @param {Set<number>} allLevels - Set of all levels.
5688
- * @returns {Object} The result object.
5689
- */
5690
6036
  createResult(parent, processPayload, deepestLevel, allLevels) {
5691
6037
  const { activitiesByLevel, parentsIds, allTasks } = processPayload;
5692
6038
  return {
@@ -5852,22 +6198,6 @@ var CriticalPathHelpers = class {
5852
6198
  throw e;
5853
6199
  }
5854
6200
  }
5855
- /**
5856
- * Identifies and sets the initial activities for the chain based on the specified direction.
5857
- *
5858
- * This function determines the starting activities of a chain by filtering activities from
5859
- * the Gantt chart. The filtering is based on the specified direction (`forward` or `backward`).
5860
- * - For `forward` direction, activities with an empty `$target` property are selected.
5861
- * - For `backward` direction, activities with an empty `$source` property are selected.
5862
- *
5863
- * The function excludes activities of type `project` from the results.
5864
- * The resulting activity IDs are stored in the `chainStartActivities` property.
5865
- *
5866
- * If an error occurs during the process, `chainStartActivities` is set to an empty array,
5867
- * and the error is rethrown.
5868
- *
5869
- * @throws {Error} If an error occurs during the identification process.
5870
- */
5871
6201
  identifyInitialActivities() {
5872
6202
  try {
5873
6203
  const {
@@ -5978,27 +6308,6 @@ var CriticalPathHelpers = class {
5978
6308
  }
5979
6309
  return sorted.reverse();
5980
6310
  }
5981
- /**
5982
- * Calculates the start and finish dates for the origin of a chain activity.
5983
- *
5984
- * This function calculates the start and finish dates for an activity based on the provided direction
5985
- * (`forward` or `backward`). For forward direction, it calculates the earliest start (ES) and earliest
5986
- * finish (EF). For backward direction, it calculates the latest start (LS) and latest finish (LF),
5987
- * handling different progress states (0%, 100%, and between 0% and 100%).
5988
- *
5989
- * @param {Object} [activityFromLink=null] - The activity object to calculate dates for.
5990
- * @param {string} [customDirection=null] - The direction for the calculation (`forward` or `backward`).
5991
- * @returns {Object} An object containing the calculated dates (ES, EF, LS, LF) based on the direction and progress.
5992
- *
5993
- * @example
5994
- * // Assuming activity is an object with start_date, end_date, progress, and calendar_id properties
5995
- * // and direction is 'forward'
5996
- * const dates = calculateStartAndFinishOfChainOrigin(activity, 'forward');
5997
- * console.log()
5998
- // { es: activity.start_date, ef: activity.end_date }
5999
- *
6000
- * @throws {Error} If the activity's calendar cannot be retrieved or other errors occur during calculation.
6001
- */
6002
6311
  calculateStartAndFinishOfChainOrigin(activityFromLink = null, customDirection = null) {
6003
6312
  try {
6004
6313
  let activity = activityFromLink;
@@ -6044,25 +6353,6 @@ var CriticalPathHelpers = class {
6044
6353
  throw e;
6045
6354
  }
6046
6355
  }
6047
- /**
6048
- * Calculates the latest start (LS) and latest finish (LF) dates for an activity with zero progress.
6049
- *
6050
- * This function determines the LS and LF dates based on the activity's constraint type and duration,
6051
- * using the provided calendar. It handles different types of constraints, adjusting the start and finish
6052
- * dates accordingly.
6053
- *
6054
- * @param {Object} activity - The activity object to calculate dates for, which should include start_date, end_date, duration, and constraint_type.
6055
- * @param {Object} calendar - The calendar object used to adjust dates based on working days and hours.
6056
- * @returns {Object} An object containing the calculated latest start (LS) and latest finish (LF) dates.
6057
- *
6058
- * @example
6059
- * // Assuming activity is an object with the required properties and a calendar object is provided
6060
- * const dates = calculateBackwardWhenZeroProgress(activity, calendar);
6061
- * console.log()
6062
- // { ls: moment(...), lf: moment(...) }
6063
- *
6064
- * @throws {Error} If an error occurs during the calculation.
6065
- */
6066
6356
  calculateBackwardWhenZeroProgress(activity, calendar) {
6067
6357
  let lateStart = moment_default(activity.start_date).clone();
6068
6358
  let lateFinish = moment_default(activity.end_date).clone();
@@ -6099,23 +6389,6 @@ var CriticalPathHelpers = class {
6099
6389
  lf: lateFinish
6100
6390
  };
6101
6391
  }
6102
- /**
6103
- * Calculates the latest start (LS) and latest finish (LF) dates for an activity with progress between 0% and 100%.
6104
- *
6105
- * This function determines the LS and LF dates based on the activity's constraint type and progress,
6106
- * considering the end date of the project and various constraints.
6107
- *
6108
- * @param {Object} activity - The activity object to calculate dates for, which should include start_date, end_date, and constraint_type.
6109
- * @returns {Object} An object containing the calculated latest start (LS) and latest finish (LF) dates.
6110
- *
6111
- * @example
6112
- * // Assuming activity is an object with the required properties
6113
- * const dates = calculateWhenProgressIsBetweenZeroAndOneHundred(activity);
6114
- * console.log()
6115
- // { ls: activity.start_date, lf: calculatedLateFinish }
6116
- *
6117
- * @throws {Error} If an error occurs during the calculation.
6118
- */
6119
6392
  calculateWhenProgressIsBetweenZeroAndOneHundred(activity) {
6120
6393
  let lateStart = activity.start_date;
6121
6394
  let lateFinish = null;
@@ -6176,7 +6449,6 @@ var CriticalPathHelpers = class {
6176
6449
  throw e;
6177
6450
  }
6178
6451
  }
6179
- // Main function
6180
6452
  doCalculationForParentType(activity) {
6181
6453
  const calculationOfParent = new calculation_of_parent_default({
6182
6454
  activity,
@@ -6254,22 +6526,6 @@ var LinksRulesCalculationsMethods = class {
6254
6526
  this.parentsCalculations = calculationObject.parentsCalculations;
6255
6527
  this.gantt = calculationObject.ganttInstance;
6256
6528
  }
6257
- /**
6258
- * Retrieves the earliest start (ES) and earliest finish (EF) dates for a given activity from previously calculated activities.
6259
- *
6260
- * This function checks if the activity exists in the `alapMap`. If it does, it returns the data from `alapMap`.
6261
- * If the activity is not found in `alapMap`, it retrieves and returns the data from `calculatedActivities`.
6262
- *
6263
- * @param {string|number} activity - The ID of the activity for which to retrieve ES and EF dates.
6264
- * @returns {Object|null} The ES and EF dates for the activity, or null if not found.
6265
- *
6266
- * @example
6267
- * // Assuming alapMap and calculatedActivities are Maps with activity data
6268
- * const esEf = getEsAndEfFromPreviousCalculatedActivities(1);
6269
- // { es: ..., ef: ..., text: ... } or null
6270
- *
6271
- * @throws {Error} If an error occurs during the retrieval process.
6272
- */
6273
6529
  getEsAndEfFromPreviousCalculatedActivities(activity) {
6274
6530
  const isAlap = this.alapMap.has(activity);
6275
6531
  if (isAlap) {
@@ -6277,29 +6533,6 @@ var LinksRulesCalculationsMethods = class {
6277
6533
  }
6278
6534
  return this.calculatedActivities.get(Number(activity));
6279
6535
  }
6280
- /**
6281
- * Calculates the earliest start (ES) and earliest finish (EF) times for a successor activity.
6282
- *
6283
- * This function calculates the ES and EF times for a successor activity based on the provided predecessor time,
6284
- * data calculations for ES and EF, lag time, and the type of link restriction. It adjusts the dates according
6285
- * to the activity's calendar and the specified restrictions.
6286
- *
6287
- * @param {Date} predecessorTime - The time of the predecessor activity.
6288
- * @param {number} esDataCalculation - The amount of time to add to the predecessor time to calculate the earliest start.
6289
- * @param {number} [efDataCalculation=0] - The amount of time to add to calculate the earliest finish.
6290
- * @param {number} lag - The lag time between the predecessor and successor activities.
6291
- * @param {string} [restrictionOfLink='fs'] - The type of link restriction between the activities.
6292
- * @returns {Object} An object containing the calculated earliest start (ES) and earliest finish (EF) times.
6293
- * @property {Date} es - The earliest start time.
6294
- * @property {Date} ef - The earliest finish time.
6295
- *
6296
- * @example
6297
- * // Assuming predecessorTime is a Date object, esDataCalculation is 5, efDataCalculation is 10, lag is 2, and restrictionOfLink is 'fs'
6298
- * const result = calculateSucessorTimes(new Date(), 5, 10, 2, 'fs');
6299
- // { es: Date, ef: Date }
6300
- *
6301
- * @throws {Error} If an error occurs during the calculation process.
6302
- */
6303
6536
  calculateSucessorTimes(predecessorTime, esDataCalculation, efDataCalculation = 0, lag, restrictionOfLink = LINK_TYPES.FS) {
6304
6537
  const activityCalendar = this.gantt.getCalendar(
6305
6538
  this.referenceActivity.calendar_id
@@ -6372,27 +6605,6 @@ var LinksRulesCalculationsMethods = class {
6372
6605
  }
6373
6606
  return { es, ef };
6374
6607
  }
6375
- /**
6376
- * Calculates the earliest start (ES) and earliest finish (EF) times for a Start-to-Start (SS) relationship.
6377
- *
6378
- * This function calculates the ES and EF times for a successor activity based on a Start-to-Start (SS) relationship
6379
- * with the predecessor activity. It uses the predecessor's ES time and adjusts it based on the link's lag and the
6380
- * activity's duration.
6381
- *
6382
- * @param {Object} link - The link object representing the relationship between the predecessor and successor activities.
6383
- * @param {number} link.source - The ID of the predecessor activity.
6384
- * @param {number} [link.lag=0] - The lag time between the predecessor and successor activities.
6385
- * @returns {Object} An object containing the calculated earliest start (ES) and earliest finish (EF) times.
6386
- * @property {Date} es - The earliest start time.
6387
- * @property {Date} ef - The earliest finish time.
6388
- *
6389
- * @example
6390
- * // Assuming link is an object with a source property (predecessor ID) and an optional lag property
6391
- * const result = calculateSS({ source: 1, lag: 2 });
6392
- // { es: Date, ef: Date }
6393
- *
6394
- * @throws {Error} If an error occurs during the calculation process.
6395
- */
6396
6608
  calculateSS(link) {
6397
6609
  const predecessorCalculatedEsAndEf = this.getEsAndEfFromPreviousCalculatedActivities(Number(link.source));
6398
6610
  const esDataCalculation = link.lag || 0;
@@ -6407,27 +6619,6 @@ var LinksRulesCalculationsMethods = class {
6407
6619
  LINK_TYPES.SS
6408
6620
  );
6409
6621
  }
6410
- /**
6411
- * Calculates the earliest start (ES) and earliest finish (EF) times for a Finish-to-Finish (FF) relationship.
6412
- *
6413
- * This function calculates the ES and EF times for a successor activity based on a Finish-to-Finish (FF) relationship
6414
- * with the predecessor activity. It uses the predecessor's EF time and adjusts it based on the link's lag and the
6415
- * activity's duration.
6416
- *
6417
- * @param {Object} link - The link object representing the relationship between the predecessor and successor activities.
6418
- * @param {number} link.source - The ID of the predecessor activity.
6419
- * @param {number} [link.lag=0] - The lag time between the predecessor and successor activities.
6420
- * @returns {Object} An object containing the calculated earliest start (ES) and earliest finish (EF) times.
6421
- * @property {Date} es - The earliest start time.
6422
- * @property {Date} ef - The earliest finish time.
6423
- *
6424
- * @example
6425
- * // Assuming link is an object with a source property (predecessor ID) and an optional lag property
6426
- * const result = calculateFF({ source: 1, lag: 2 });
6427
- // { es: Date, ef: Date }
6428
- *
6429
- * @throws {Error} If an error occurs during the calculation process.
6430
- */
6431
6622
  calculateFF(link) {
6432
6623
  const predecessorCalculatedEsAndEf = this.getEsAndEfFromPreviousCalculatedActivities(Number(link.source));
6433
6624
  const duration = this.referenceActivity.duration;
@@ -6442,27 +6633,6 @@ var LinksRulesCalculationsMethods = class {
6442
6633
  LINK_TYPES.FF
6443
6634
  );
6444
6635
  }
6445
- /**
6446
- * Calculates the earliest start (ES) and earliest finish (EF) times for a Finish-to-Start (FS) relationship.
6447
- *
6448
- * This function calculates the ES and EF times for a successor activity based on a Finish-to-Start (FS) relationship
6449
- * with the predecessor activity. It uses the predecessor's EF time and adjusts it based on the link's lag and the
6450
- * activity's duration.
6451
- *
6452
- * @param {Object} link - The link object representing the relationship between the predecessor and successor activities.
6453
- * @param {number} link.source - The ID of the predecessor activity.
6454
- * @param {number} [link.lag=0] - The lag time between the predecessor and successor activities.
6455
- * @returns {Object} An object containing the calculated earliest start (ES) and earliest finish (EF) times.
6456
- * @property {Date} es - The earliest start time.
6457
- * @property {Date} ef - The earliest finish time.
6458
- *
6459
- * @example
6460
- * // Assuming link is an object with a source property (predecessor ID) and an optional lag property
6461
- * const result = calculateFS({ source: 1, lag: 2 });
6462
- // { es: Date, ef: Date }
6463
- *
6464
- * @throws {Error} If an error occurs during the calculation process.
6465
- */
6466
6636
  calculateFS(link) {
6467
6637
  const predecessorCalculatedEsAndEf = this.getEsAndEfFromPreviousCalculatedActivities(Number(link.source));
6468
6638
  const esDataCalculation = link.lag || 0;
@@ -6477,27 +6647,6 @@ var LinksRulesCalculationsMethods = class {
6477
6647
  LINK_TYPES.FS
6478
6648
  );
6479
6649
  }
6480
- /**
6481
- * Calculates the earliest start (ES) and earliest finish (EF) times for a Start-to-Finish (SF) relationship.
6482
- *
6483
- * This function calculates the ES and EF times for a successor activity based on a Start-to-Finish (SF) relationship
6484
- * with the predecessor activity. It uses the predecessor's EF time and adjusts it based on the link's lag and the
6485
- * activity's duration.
6486
- *
6487
- * @param {Object} link - The link object representing the relationship between the predecessor and successor activities.
6488
- * @param {number} link.source - The ID of the predecessor activity.
6489
- * @param {number} [link.lag=0] - The lag time between the predecessor and successor activities.
6490
- * @returns {Object} An object containing the calculated earliest start (ES) and earliest finish (EF) times.
6491
- * @property {Date} es - The earliest start time.
6492
- * @property {Date} ef - The earliest finish time.
6493
- *
6494
- * @example
6495
- * // Assuming link is an object with a source property (predecessor ID) and an optional lag property
6496
- * const result = calculateSF({ source: 1, lag: 2 });
6497
- // { es: Date, ef: Date }
6498
- *
6499
- * @throws {Error} If an error occurs during the calculation process.
6500
- */
6501
6650
  calculateSF(link) {
6502
6651
  const predecessorCalculatedEsAndEf = this.getEsAndEfFromPreviousCalculatedActivities(Number(link.source));
6503
6652
  const duration = this.referenceActivity.duration;
@@ -6512,24 +6661,6 @@ var LinksRulesCalculationsMethods = class {
6512
6661
  LINK_TYPES.SF
6513
6662
  );
6514
6663
  }
6515
- /**
6516
- * Adjusts a date to the next working hour based on the type of link restriction and the activity's calendar.
6517
- *
6518
- * This function adjusts the provided date either to a future or past working hour based on the specified link restriction.
6519
- * It uses the activity's calendar to determine the working hours and calculates the appropriate date.
6520
- *
6521
- * @param {Date} dateBaseToCalculate - The initial date that needs to be adjusted.
6522
- * @param {string} restrictionOfLink - The type of link restriction (e.g., 'fs', 'ss', 'ff').
6523
- * @param {Object} activityCalendar - The calendar associated with the activity, used to determine working hours.
6524
- * @returns {Date} The adjusted date based on the link restriction and activity calendar.
6525
- *
6526
- * @example
6527
- * // Assuming dateBaseToCalculate is a Date object, restrictionOfLink is 'fs', and activityCalendar is a valid calendar object
6528
- * const adjustedDate = mutateTheDateToFutureOrPastInBaseRestriction(new Date(), 'fs', activityCalendar);
6529
- // The date adjusted to the next working hour in the future
6530
- *
6531
- * @throws {Error} If an error occurs during the date adjustment process.
6532
- */
6533
6664
  mutateTheDateToFutureOrPastInBaseRestriction(dateBaseToCalculate, restrictionOfLink, activityCalendar) {
6534
6665
  if (![LINK_TYPES.FS, LINK_TYPES.SS, LINK_TYPES.FF].includes(restrictionOfLink)) {
6535
6666
  return dateBaseToCalculate;
@@ -6553,22 +6684,6 @@ var LinksConstraintCalculator = class extends LinksRulesCalculationsMethods_defa
6553
6684
  constructor(calculationObject) {
6554
6685
  super(calculationObject);
6555
6686
  }
6556
- /**
6557
- * Calculates the earliest start dates for all links and returns the maximum early start set.
6558
- *
6559
- * This function processes each link in the `links` array, retrieves the necessary link data, and calculates
6560
- * the earliest start dates using the `calculateLink` method. It then returns the maximum early start set
6561
- * by calling `getMaxEarlyStartSet`.
6562
- *
6563
- * @returns {Object} The maximum early start set calculated from all links.
6564
- *
6565
- * @example
6566
- * // Assuming links is an array of link IDs [1, 2, 3]
6567
- * // and gantt.getLink(id) returns link data for each ID
6568
- * const result = calculate();
6569
- *
6570
- * @throws {Error} If an error occurs during the calculation process.
6571
- */
6572
6687
  calculate() {
6573
6688
  if (this.links.length === 0) {
6574
6689
  return new generic_calculations_default(
@@ -6599,23 +6714,6 @@ var LinksConstraintCalculator = class extends LinksRulesCalculationsMethods_defa
6599
6714
  }
6600
6715
  return getMaxEarlyStartSet(allLinksCalculations);
6601
6716
  }
6602
- /**
6603
- * Calculates the link based on its type.
6604
- *
6605
- * This function determines the appropriate calculation method for the link based on its type and executes it.
6606
- * The link type is mapped to specific calculation methods: Finish-to-Start (FS), Start-to-Start (SS),
6607
- * Finish-to-Finish (FF), and Start-to-Finish (SF).
6608
- *
6609
- * @param {Object} linkData - The data of the link to be calculated. It should include a `type` property that indicates the type of link.
6610
- * @returns {*} The result of the calculation based on the link type.
6611
- *
6612
- * @example
6613
- * // Assuming linkData is an object with a type property
6614
- * const result = calculateLink({ type: 0, ...otherLinkProperties });
6615
- * // This will call the calculateFS method with the linkData and return the result
6616
- *
6617
- * @throws {Error} If the link type is not recognized.
6618
- */
6619
6717
  calculateLink(linkData) {
6620
6718
  const calculationMapping = {
6621
6719
  0: () => this.calculateFS(linkData),
@@ -6641,11 +6739,6 @@ var ActivityCalculator = class {
6641
6739
  this.linkProperty = options.linkProperty;
6642
6740
  this.linkDirection = options.linkDirection;
6643
6741
  }
6644
- /**
6645
- * Checks which activities can now be calculated based on their dependencies.
6646
- * @param {Set<number>} pendingToCalculate - Set of activity IDs pending calculation.
6647
- * @returns {Object} An object containing activities that can be calculated and remaining pending activities.
6648
- */
6649
6742
  checkActivitiesThatNowCanBeCalculated(pendingToCalculate) {
6650
6743
  const activitiesThatCanBeCalculated = /* @__PURE__ */ new Set();
6651
6744
  const pendingActivities = new Set(pendingToCalculate);
@@ -6672,9 +6765,6 @@ var ActivityCalculator = class {
6672
6765
  pendingActivities
6673
6766
  };
6674
6767
  }
6675
- /**
6676
- * Handles logic for project-type activities.
6677
- */
6678
6768
  handleProjectActivity(activityId, activityData, activitiesThatCanBeCalculated, pendingActivities) {
6679
6769
  const isPendingParentWithNoLinks = this.pendingParentsWithNoLinks.has(activityId);
6680
6770
  const isPendingParentWithLinks = this.pendingParentsWithLinks.has(activityId);
@@ -6715,9 +6805,6 @@ var ActivityCalculator = class {
6715
6805
  }
6716
6806
  }
6717
6807
  }
6718
- /**
6719
- * Determines if a parent activity can be calculated.
6720
- */
6721
6808
  canCalculateParentActivity(activityData) {
6722
6809
  const hasNoLinks = (activityData[this.linkProperty] || []).length === 0;
6723
6810
  const constraintType = activityData.constraint_type;
@@ -6732,9 +6819,6 @@ var ActivityCalculator = class {
6732
6819
  (activityId) => this.calculations.has(activityId)
6733
6820
  );
6734
6821
  }
6735
- /**
6736
- * Handles logic for non-project activities.
6737
- */
6738
6822
  handleNonProjectActivity(activityId, activityData, activitiesThatCanBeCalculated, pendingActivities) {
6739
6823
  const parentId = Number(activityData.parent);
6740
6824
  const isParentPendingWithLinks = this.pendingParentsWithLinks.has(parentId);
@@ -6772,9 +6856,6 @@ var ActivityCalculator = class {
6772
6856
  pendingActivities.delete(activityId);
6773
6857
  }
6774
6858
  }
6775
- /**
6776
- * Retrieves linked activities based on link property.
6777
- */
6778
6859
  getLinkedActivities(predecessors) {
6779
6860
  if (!Array.isArray(predecessors)) {
6780
6861
  return [];
@@ -6793,9 +6874,6 @@ var ActivityCalculator = class {
6793
6874
  }
6794
6875
  return linkedActivities;
6795
6876
  }
6796
- /**
6797
- * Retrieves an array of linked activity IDs.
6798
- */
6799
6877
  getArrayOfLinkedActivities(links) {
6800
6878
  if (!Array.isArray(links)) {
6801
6879
  return [];
@@ -6817,8 +6895,7 @@ var get_activities_to_calculate_default = ActivityCalculator;
6817
6895
  var createIsCurrent2 = (calculationId, getCurrentId) => () => getCurrentId() === calculationId;
6818
6896
 
6819
6897
  // src/critical-path/legacy/utils/validation.js
6820
- var shouldAbortCalculation = (gantt) => !gantt?.fullyParsed || // environment guard: en el core no hay `window` (el bridge en react_client sí).
6821
- typeof window !== "undefined" && window.to_use_react_gantt?.conversionMode?.isActive;
6898
+ var shouldAbortCalculation = (gantt) => !gantt?.fullyParsed || typeof window !== "undefined" && window.to_use_react_gantt?.conversionMode?.isActive;
6822
6899
 
6823
6900
  // src/critical-path/legacy/utils/timing.js
6824
6901
  var TIME_BUDGET_MS = 16;
@@ -6930,24 +7007,6 @@ var ForwardPath = class extends generic_calculations_default {
6930
7007
  isCurrent
6931
7008
  });
6932
7009
  }
6933
- /**
6934
- * Calculates the earliest start (ES) and earliest finish (EF) dates for a list of activities.
6935
- *
6936
- * This function processes each activity in the `activitiesToCalculate` list, retrieves the necessary
6937
- * information, and calculates the ES and EF dates based on the activity's progress and constraint type.
6938
- * It handles various constraints and updates the calculations accordingly.
6939
- * It also do calculation according to the activities links
6940
- *
6941
- * @param {Array<string|number>} activitiesToCalculate - A list of activity IDs for which to calculate ES and EF dates.
6942
- * @returns {void} This function does not return a value.
6943
- *
6944
- * @example
6945
- * // Assuming activitiesToCalculate is an array containing activity IDs [1, 2, 3]
6946
- * calculateStartAndFinishTimes([1, 2, 3]);
6947
- * // This will calculate the ES and EF dates for the activities and update the internal calculations map.
6948
- *
6949
- * @throws {Error} If an error occurs during the process.
6950
- */
6951
7010
  calculateStartAndFinishTimes(activitiesToCalculate) {
6952
7011
  activitiesToCalculate.forEach((activity) => {
6953
7012
  const activityReference = this.gantt.getTask(activity);
@@ -7068,13 +7127,6 @@ var ForwardPath = class extends generic_calculations_default {
7068
7127
  this.activitiesWaitingForCalculation.delete(activity);
7069
7128
  });
7070
7129
  }
7071
- /**
7072
- * Gets the greatest date between a restriction and a link calculation.
7073
- * @param {Object} restriction - The restriction object.
7074
- * @param {Object} linkCalculation - The link calculation object.
7075
- * @param {string} [comparisonType='greater'] - The type of comparison ('greater' or 'less').
7076
- * @returns {Object} - The object with the greatest date.
7077
- */
7078
7130
  getTheGreatesDateBetweenRestrictionAndEsEf(restriction, linkCalculation, comparisonType = "greater") {
7079
7131
  if (comparisonType === "greater") {
7080
7132
  return linkCalculation.ef > restriction.ef ? linkCalculation : restriction;
@@ -7083,34 +7135,18 @@ var ForwardPath = class extends generic_calculations_default {
7083
7135
  return linkCalculation.ef < restriction.ef ? linkCalculation : restriction;
7084
7136
  }
7085
7137
  }
7086
- /**
7087
- * Set ES and EF dates for an activity with full progress.
7088
- * @param {Object} activity - The activity object.
7089
- */
7090
7138
  setDatesForActivityWithFullProgress(activity) {
7091
7139
  this.calculations.set(activity.id, {
7092
7140
  es: activity.start_date,
7093
7141
  ef: activity.end_date
7094
7142
  });
7095
7143
  }
7096
- /**
7097
- * Calculates ES and EF dates for an activity with progress greater than zero.
7098
- * @param {Object} activity - The activity object.
7099
- * @returns {Object} - The calculated ES and EF dates.
7100
- */
7101
7144
  getDatesForActivityWithZeroProgress(activity) {
7102
7145
  return {
7103
7146
  es: activity.start_date,
7104
7147
  ef: activity.end_date
7105
7148
  };
7106
7149
  }
7107
- /**
7108
- * Recalculates ES and EF dates based on a constraint.
7109
- * @param {string} constraintType - The type of constraint.
7110
- * @param {Object} calculatedRestriction - The calculated restriction object.
7111
- * @param {Object} calculatedEsEf - The calculated ES and EF object.
7112
- * @returns {Object} - The recalculated ES and EF dates.
7113
- */
7114
7150
  recalculateInBaseConstraint(constraintType, calculatedRestriction, calculatedEsEf) {
7115
7151
  const comparisontype = [
7116
7152
  CONSTRAINT_TYPES.SNET,
@@ -7150,30 +7186,12 @@ var CalculationsGenericMethods = class {
7150
7186
  this.forwardPathCalculations = calculationObject.calculatedForwardActivitiesMap;
7151
7187
  this.gantt = calculationObject.ganttInstance;
7152
7188
  }
7153
- /**
7154
- * Retrieves the late start (LS) and late finish (lf) dates for a given activity from previously calculated activities.
7155
- *
7156
- * @param {string|number} activity - The ID of the activity for which to retrieve LS and lf dates.
7157
- * @param {string} [constraint=null] - The constraint type to use for the calculation (e.g., 'alap').
7158
- * @returns {Object|null} The LS and lf dates for the activity, or null if not found.
7159
- * @throws {Error} If an error occurs during the retrieval process.
7160
- */
7161
7189
  getForwardOrBackwardCalculations(activity, constraint = null) {
7162
7190
  if (constraint === CONSTRAINT_TYPES.ALAP) {
7163
7191
  return this.forwardPathCalculations.get(activity);
7164
7192
  }
7165
7193
  return this.calculatedActivities.get(activity);
7166
7194
  }
7167
- /**
7168
- * Calculates the LS (Latest Start) and LF (Latest Finish) times for the successor activity.
7169
- * @param {Date} successorTime - The time of the successor activity.
7170
- * @param {number} lsDataCalculation - The duration for LS calculation.
7171
- * @param {number} [lfDataCalculation=0] - The duration for LF calculation, default is 0.
7172
- * @param {number} lag - The lag time.
7173
- * @param {string} [type='FS'] - The type of link ('FS', 'FF', 'SS', 'SF'), default is 'FS'.
7174
- * @returns {Object} Returns an object containing the LS and LF times for the successor activity.
7175
- * @throws Will throw an error if there's an issue with the calculation.
7176
- */
7177
7195
  calculateSuccessorTimes(sucessorTime, lsDataCalculation, lfDataCalculation = 0, lag, type = LINK_TYPES.FS) {
7178
7196
  let activityCalendar = this.gantt.getCalendar(this.activity.calendar_id);
7179
7197
  if (!activityCalendar) {
@@ -7223,13 +7241,6 @@ var CalculationsGenericMethods = class {
7223
7241
  return { ls, lf };
7224
7242
  }
7225
7243
  }
7226
- /**
7227
- * Calculates the LS (Latest Start) and LF (Latest Finish) times for the successor activity in a SS (Start-to-Start) link.
7228
- * @param {Object} link - The link object containing information about the relationship.
7229
- * @param {boolean} [alap=false] - Indicates whether to calculate based on ALAP (As Late As Possible) constraint, default is false.
7230
- * @returns {Object} Returns an object containing the calculated LS and LF times for the successor activity.
7231
- * @throws Will throw an error if there's an issue with the calculation.
7232
- */
7233
7244
  calculateSS(link, alap = false) {
7234
7245
  let lsSuc = this.getValueForSS(link, alap);
7235
7246
  let lsDataForCalculation = -link.lag || 0;
@@ -7243,12 +7254,6 @@ var CalculationsGenericMethods = class {
7243
7254
  LINK_TYPES.SS
7244
7255
  );
7245
7256
  }
7246
- /**
7247
- * Calculates the LS (Latest Start) and LF (Latest Finish) times for the successor activity in a FF (Finish-to-Finish) link.
7248
- * @param {Object} link - The link object containing information about the relationship.
7249
- * @returns {Object} Returns an object containing the calculated LS and LF times for the successor activity.
7250
- * @throws Will throw an error if there's an issue with the calculation.
7251
- */
7252
7257
  calculateFF(link, constraint) {
7253
7258
  const succesorDate = this.getForwardOrBackwardCalculations(
7254
7259
  Number(link.target)
@@ -7266,13 +7271,6 @@ var CalculationsGenericMethods = class {
7266
7271
  LINK_TYPES.FF
7267
7272
  );
7268
7273
  }
7269
- /**
7270
- * Calculates the LS (Latest Start) and LF (Latest Finish) times for the successor activity in a FS (Finish-to-Start) link.
7271
- * @param {Object} link - The link object containing information about the relationship.
7272
- * @param {string} constraint - The constraint type.
7273
- * @returns {Object} Returns an object containing the calculated LS and LF times for the successor activity.
7274
- * @throws Will throw an error if there's an issue with the calculation.
7275
- */
7276
7274
  calculateFS(link, constraint) {
7277
7275
  let propertyToCalculate = "ls";
7278
7276
  propertyToCalculate = constraint === CONSTRAINT_TYPES.ALAP ? "es" : "ls";
@@ -7291,13 +7289,6 @@ var CalculationsGenericMethods = class {
7291
7289
  LINK_TYPES.FS
7292
7290
  );
7293
7291
  }
7294
- /**
7295
- * Calculates the LS (Latest Start) and LF (Latest Finish) times for the successor activity in a SF (Start-to-Finish) link.
7296
- * @param {Object} link - The link object containing information about the relationship.
7297
- * @param {boolean} getFromForward - Whether to calculate LS using the early start from the forward path.
7298
- * @returns {Object} Returns an object containing the calculated LS and LF times for the successor activity.
7299
- * @throws Will throw an error if there's an issue with the calculation.
7300
- */
7301
7292
  calculateSF(link, getFromForward = false) {
7302
7293
  let lateFinishSucessor = getFromForward ? this.getEarlyStartFromForwardPath(Number(link.target)).ef : this.getForwardOrBackwardCalculations(Number(link.target)).lf;
7303
7294
  let lsDataForCalculation = -link.lag || 0;
@@ -7311,19 +7302,9 @@ var CalculationsGenericMethods = class {
7311
7302
  LINK_TYPES.SF
7312
7303
  );
7313
7304
  }
7314
- /**
7315
- * Retrieves the early start time from the forward path calculations for the current activity.
7316
- * @returns {number} The early start time for the activity.
7317
- */
7318
7305
  getEarlyStartFromForwardPath(link) {
7319
7306
  return this.forwardPathCalculations.get(link);
7320
7307
  }
7321
- /**
7322
- * Retrieves the value for the specified scheduling state (SS).
7323
- * @param {object} link - The link object representing the dependency.
7324
- * @param {boolean} alap - Flag indicating if the scheduling state is As Late As Possible (ALAP).
7325
- * @returns {number} The value representing the specified scheduling state.
7326
- */
7327
7308
  getValueForSS(link, alap) {
7328
7309
  if (alap) {
7329
7310
  return this.getEarlyStartFromForwardPath(Number(link.target)).es;
@@ -7332,13 +7313,6 @@ var CalculationsGenericMethods = class {
7332
7313
  let sucessor = this.getForwardOrBackwardCalculations(Number(link.target));
7333
7314
  return sucessor[propertyToCalculate];
7334
7315
  }
7335
- /**
7336
- * Calculates the end date based on the provided activity calendar, starting date, and duration.
7337
- * @param {object} activityCalendar - The calendar object containing activity scheduling information.
7338
- * @param {Date} date - The starting date for the activity.
7339
- * @param {number} duration - The duration of the activity in days.
7340
- * @returns {Date} The end date of the activity.
7341
- */
7342
7316
  calculateDate(activityCalendar, date2, duration) {
7343
7317
  let resetedDate = moment_default(date2).clone();
7344
7318
  return addDurationToDate(
@@ -7348,14 +7322,6 @@ var CalculationsGenericMethods = class {
7348
7322
  this.activity
7349
7323
  );
7350
7324
  }
7351
- /**
7352
- * Retrieves the last working hour based on the provided date and activity calendar.
7353
- * @param {Date} date - The date for which to find the last working hour.
7354
- * @param {object} activityCalendar - The calendar object containing activity scheduling information.
7355
- * @param {string} [dir='past'] - The direction in which to search for the last working hour. Default is 'past'.
7356
- * @throws {Error} Throws an error if the provided date is not valid.
7357
- * @returns {Date} The last working hour relative to the provided date.
7358
- */
7359
7325
  getLastWorkingHour(date2, activityCalendar, dir = "past") {
7360
7326
  const normalizedDate = date2 instanceof Date ? date2 : new Date(date2);
7361
7327
  let resetedDate = moment_default(normalizedDate).clone();
@@ -7370,14 +7336,6 @@ var CalculationsGenericMethods = class {
7370
7336
  });
7371
7337
  return newDate;
7372
7338
  }
7373
- /**
7374
- * Determines if a given date corresponds to the initial work hour of an activity as defined in the activity calendar.
7375
- * This function retrieves the first work interval from the activity calendar and compares the hour portion
7376
- * of the input date to the start hour of the work interval.
7377
- * @param {object} activityCalendar - The calendar object containing work hours and scheduling information for the activity.
7378
- * @param {Date} date - The date to check against the activity's start hour.
7379
- * @returns {boolean} True if the hour of the input date matches the initial work hour of the activity; otherwise, false.
7380
- */
7381
7339
  isActivityInInitHour(activityCalendar, date2) {
7382
7340
  const normalizedDate = date2 instanceof Date ? date2 : new Date(date2);
7383
7341
  const shifts = activityCalendar.getWorkHours(normalizedDate);
@@ -7396,17 +7354,6 @@ var CalculationsGenericMethods = class {
7396
7354
  }
7397
7355
  return normalizedDate.getUTCHours() === workStartHour;
7398
7356
  }
7399
- /**
7400
- * Calculates the forward start (FS) and forward finish (FF) dates based on the provided parameters.
7401
- * @param {object} options - An object containing the necessary parameters for the calculation.
7402
- * @param {number} options.lag - The lag duration for the calculation.
7403
- * @param {Date} options.workTime - The starting work time for the calculation.
7404
- * @param {object} options.activityCalendar - The calendar object containing activity scheduling information.
7405
- * @param {number} options.lsDataCalculation - The duration for calculating the forward start date.
7406
- * @param {number} options.lfDataCalculation - The duration for calculating the forward finish date.
7407
- * @param {boolean} [options.isMilestone=false] - Flag indicating if the activity is a milestone. Default is false.
7408
- * @returns {object} An object containing the forward start (FS) and forward finish (FF) dates.
7409
- */
7410
7357
  calculateFsLink({
7411
7358
  lag,
7412
7359
  workTime,
@@ -7459,16 +7406,6 @@ var CalculationsGenericMethods = class {
7459
7406
  }
7460
7407
  return { ls: lsPred, lf: lfPred };
7461
7408
  }
7462
- /**
7463
- * Calculates the forward finish (FF) dates based on the provided parameters.
7464
- * @param {object} options - An object containing the necessary parameters for the calculation.
7465
- * @param {number} options.lag - The lag duration for the calculation.
7466
- * @param {Date} options.workTime - The starting work time for the calculation.
7467
- * @param {object} options.activityCalendar - The calendar object containing activity scheduling information.
7468
- * @param {number} options.lsDataCalculation - The duration for calculating the forward start date.
7469
- * @param {number} options.lfDataCalculation - The duration for calculating the forward finish date.
7470
- * @returns {object} An object containing the forward start (FS) and forward finish (FF) dates.
7471
- */
7472
7409
  calculateFFLink({
7473
7410
  lag,
7474
7411
  workTime,
@@ -7515,19 +7452,6 @@ var CalculationsGenericMethods = class {
7515
7452
  );
7516
7453
  return { ls: lsPred, lf: lfPred };
7517
7454
  }
7518
- /**
7519
- * Calculates the start and finish times for an activity based on the specified lag and work time.
7520
- * If the lag is zero, the function directly calculates the times using the provided work time.
7521
- * If the lag is negative and the activity is not a milestone, it adjusts the work time based on future working hours.
7522
- * @param {object} options - Configuration object containing parameters needed for the calculation.
7523
- * @param {number} options.lay - The lag time affecting the start and finish calculations.
7524
- * @param {Date} options.workTime - The reference time from which calculations begin.
7525
- * @param {object} options.activityCalendar - The calendar used to check work hours and holidays.
7526
- * @param {number} options.lsDataCalculation - Duration to calculate the start time from the reference point.
7527
- * @param {number} options.lfDataCalculation - Duration to calculate the finish time from the calculated start time.
7528
- * @param {boolean} [options.isMilestone=false] - Indicates whether the current activity is a milestone.
7529
- * @returns {object} An object with properties `ls` (start time) and `lf` (finish time).
7530
- */
7531
7455
  calculateSSlink({
7532
7456
  lag,
7533
7457
  workTime,
@@ -7575,17 +7499,6 @@ var CalculationsGenericMethods = class {
7575
7499
  );
7576
7500
  return { ls: lsPred, lf: lfPred };
7577
7501
  }
7578
- /**
7579
- * Calculates the start (SF) and finish (LF) times for an activity based on the specified lag and work time.
7580
- * This function handles both cases where lag is zero and when it's not, calculating times based on the given work time.
7581
- * @param {object} options - Configuration object containing the necessary parameters for the calculation.
7582
- * @param {number} options.lag - The lag time that influences the scheduling.
7583
- * @param {Date} options.workBlock - The reference time from which scheduling starts.
7584
- * @param {object} options.activityCalendar - The calendar object containing activity scheduling information.
7585
- * @param {number} options.lsDataCalculation - The duration to calculate the start time.
7586
- * @param {number} options.lfDataCalculation - The duration to calculate the finish time.
7587
- * @returns {object} An object containing the start (ls) and finish (lf) times of the activity.
7588
- */
7589
7502
  calculateSFLink({
7590
7503
  lag,
7591
7504
  workTime,
@@ -7632,23 +7545,6 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
7632
7545
  this.parentsThatImpactChildrens = calculationObject.parentsThatImpactChildrens;
7633
7546
  this.projectDates = this.gantt.getSubtaskDates();
7634
7547
  }
7635
- /**
7636
- * Calculates the latest start (LS) and latest finish (LF) times for an activity.
7637
- *
7638
- * This function calculates the LS and LF times for an activity based on its progress and the links associated with it.
7639
- * It takes into account various conditions and constraints to determine the final LS and LF times.
7640
- *
7641
- * @returns {Object} An object containing the calculated latest start (LS) and latest finish (LF) times.
7642
- * @property {Date} ls - The calculated latest start time.
7643
- * @property {Date} lf - The calculated latest finish time.
7644
- *
7645
- * @example
7646
- * // Assuming this function is part of a class with access to the required properties and methods
7647
- * const result = calculate();
7648
- // { ls: Date, lf: Date }
7649
- *
7650
- * @throws {Error} If an error occurs during the calculation process.
7651
- */
7652
7548
  calculate() {
7653
7549
  if (this.links.length === 0) {
7654
7550
  return new generic_calculations_default(
@@ -7725,11 +7621,6 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
7725
7621
  minFromLinks: calculation
7726
7622
  };
7727
7623
  }
7728
- /**
7729
- * Calculates the Late Start (LS) and Late Finish (LF) for the current activity.
7730
- * @returns {Object} An object containing the Late Start (LS) and Late Finish (LF) dates.
7731
- * @throws {Error} If there's an issue with retrieving the calendar or calculating the dates.
7732
- */
7733
7624
  calculateTheLsAndLfForTheActivity(parentDates = null) {
7734
7625
  try {
7735
7626
  const duration = this.activity.duration;
@@ -7756,12 +7647,6 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
7756
7647
  throw Error(error.message);
7757
7648
  }
7758
7649
  }
7759
- /**
7760
- * Calculates the minimum between the minimum date from links and the end date of the project
7761
- * or the end date of the activity, depending on the constraint type.
7762
- * @param {Object} minCalculatedDateFromLinks - The minimum calculated date from links.
7763
- * @returns {Date} The minimum date between the calculated date from links and the end date.
7764
- */
7765
7650
  SnetSnltMsoMinDate(minCalculatedDateFromLinks) {
7766
7651
  const minDateOfEndOfProjectAndLinks = Math.min(
7767
7652
  minCalculatedDateFromLinks.lf,
@@ -7771,12 +7656,6 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
7771
7656
  Math.max(minDateOfEndOfProjectAndLinks, this.activity.end_date)
7772
7657
  );
7773
7658
  }
7774
- /**
7775
- * Calculates the successor and/or predecessor times based on the link type and constraints.
7776
- * @param {Object} linkData - The link data object containing information about the link.
7777
- * @returns {void} Returns nothing if the calculation is avoided based on the progress of the target activity.
7778
- * @throws {Error} Throws an error if activity data is not found or if an error occurs during calculation.
7779
- */
7780
7659
  calculateLink(linkData) {
7781
7660
  const activityFromLink = this.gantt.getTask(linkData.target);
7782
7661
  if (!activityFromLink) {
@@ -7796,29 +7675,17 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
7796
7675
  };
7797
7676
  return calculationMapping[linkData.type]();
7798
7677
  }
7799
- /**
7800
- * Determines the special calculation parameter based on the constraint type.
7801
- * @returns {string|undefined} Returns a special parameter for specific constraint types, or undefined if no special parameter is needed.
7802
- */
7803
7678
  getSpecialCalculationParamForConstraintLink() {
7804
7679
  if (this.constraint === CONSTRAINT_TYPES.ALAP) return CONSTRAINT_TYPES.ALAP;
7805
7680
  if (this.constraint === CONSTRAINT_TYPES.FNET || this.constraint === CONSTRAINT_TYPES.SNET)
7806
7681
  return "snet-fnet";
7807
7682
  if (this.constraint === CONSTRAINT_TYPES.FNLT) return CONSTRAINT_TYPES.FNLT;
7808
7683
  }
7809
- /**
7810
- * Determines the special calculation parameter based on the constraint type.
7811
- * @returns {string|undefined} Returns a special parameter for specific constraint types, or undefined if no special parameter is needed.
7812
- */
7813
7684
  getSpecialParamForSf() {
7814
7685
  const constriantThatNeedSpecialParam = [CONSTRAINT_TYPES.ALAP];
7815
7686
  if (constriantThatNeedSpecialParam.includes(this.constraint)) return true;
7816
7687
  return false;
7817
7688
  }
7818
- /**
7819
- * Determines the special calculation parameter based on the constraint type.
7820
- * @returns {string|undefined} Returns a special parameter for specific constraint types, or undefined if no special parameter is needed.
7821
- */
7822
7689
  getSpecialParamForFF() {
7823
7690
  const constraintsThatNeedSpecialFFParam = [
7824
7691
  CONSTRAINT_TYPES.MFO,
@@ -7828,11 +7695,6 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
7828
7695
  return true;
7829
7696
  return false;
7830
7697
  }
7831
- /**
7832
- * Determines the minimum calculation logic based on the constraint type.
7833
- * @param {Object} minCalculateFromLinks - The minimum calculation data from links.
7834
- * @returns {Date} Returns the minimum calculation date based on the constraint type.
7835
- */
7836
7698
  getMinCalculationLogic(minCalculateFromLinks) {
7837
7699
  if (this.constraint === CONSTRAINT_TYPES.ALAP) {
7838
7700
  return this.getMinDateBasedOnConstraint(minCalculateFromLinks);
@@ -7853,11 +7715,6 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
7853
7715
  return this.getMinDateBasedOnConstraint(minCalculateFromLinks);
7854
7716
  }
7855
7717
  }
7856
- /**
7857
- * Calculates the minimum date from the list of link calculations based on the constraint type.
7858
- * @param {Array} allLinksCalculations - The list of all link calculations.
7859
- * @returns {Object} Returns the minimum date from the link calculations.
7860
- */
7861
7718
  getMinDateFromLinks(allLinksCalculations) {
7862
7719
  try {
7863
7720
  if (this.constraint === CONSTRAINT_TYPES.ALAP || this.constraint === CONSTRAINT_TYPES.ASAP) {
@@ -7880,16 +7737,6 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
7880
7737
  (min, activity) => activity.lf < min.lf ? activity : min
7881
7738
  );
7882
7739
  }
7883
- /**
7884
- * Gets the minimum date between the links' minimum date and the end of the project based on the constraint type.
7885
- *
7886
- * @param {Object} minCalculatedDateFromLinks - The minimum calculated date from links.
7887
- * @param {Date} minCalculatedDateFromLinks.lf - The latest finish date from links.
7888
- * @param {string} constraintType - The constraint type of the activity.
7889
- * @returns {Date} The calculated minimum date based on the constraint type.
7890
- *
7891
- * @throws {Error} If an error occurs during the calculation process.
7892
- */
7893
7740
  getMinDateBasedOnConstraint(minCalculatedDateFromLinks, constraintType = this.constraint) {
7894
7741
  const minDateOfEndOfProjectAndLinks = Math.min(
7895
7742
  minCalculatedDateFromLinks.lf,
@@ -8040,23 +7887,6 @@ var BackwardPath = class extends generic_calculations_default {
8040
7887
  lf: maxLf
8041
7888
  });
8042
7889
  }
8043
- /**
8044
- * Calculates the latest start (LS) and latest finish (LF) times for a list of activities.
8045
- *
8046
- * This function processes each activity in the `activitiesToCalculate` list, retrieves the necessary
8047
- * information, and calculates the LS and LF times based on the activity's progress and constraint type.
8048
- * It handles various constraints and updates the calculations accordingly.
8049
- *
8050
- * @param {Array<string|number>} activitiesToCalculate - A list of activity IDs for which to calculate LS and LF times.
8051
- * @returns {void} This function does not return a value.
8052
- *
8053
- * @example
8054
- * // Assuming activitiesToCalculate is an array containing activity IDs [1, 2, 3]
8055
- * calculateStartAndFinishTimes([1, 2, 3]);
8056
- * // This will calculate the LS and LF times for the activities and update the internal calculations map.
8057
- *
8058
- * @throws {Error} If an error occurs during the process.
8059
- */
8060
7890
  calculateStartAndFinishTimes(activitiesToCalculate) {
8061
7891
  activitiesToCalculate.forEach((activityId) => {
8062
7892
  let activityReference = this.gantt.getTask(activityId);
@@ -8134,29 +7964,6 @@ var BackwardPath = class extends generic_calculations_default {
8134
7964
  });
8135
7965
  });
8136
7966
  }
8137
- /**
8138
- * Determines the least late time for an activity based on ES and EF constraints.
8139
- *
8140
- * This function compares the latest finish (LF) time from links with the earliest finish (EF) constraint
8141
- * for the activity. If the LF from links is less than the EF constraint, it returns the LF from links.
8142
- * Otherwise, it returns the ES and EF constraints.
8143
- *
8144
- * @param {string|number} activity - The ID of the activity.
8145
- * @param {Object} lfFromLinks - An object containing LS (latest start) and LF (latest finish) times from links.
8146
- * @param {Date} lfFromLinks.ls - The latest start time from links.
8147
- * @param {Date} lfFromLinks.lf - The latest finish time from links.
8148
- * @returns {Object} An object containing the least late LS and LF times.
8149
- * @property {Date} ls - The least late latest start time.
8150
- * @property {Date} lf - The least late latest finish time.
8151
- *
8152
- * @example
8153
- * // Assuming forwardConstraintsMap contains the ES and EF constraints for the activity
8154
- * const result = getTheLessLateInBasEsEfConstraint(1, { ls: new Date(), lf: new Date() });
8155
- * console.log()
8156
- // { ls: Date, lf: Date }
8157
- *
8158
- * @throws {Error} If an error occurs during the process.
8159
- */
8160
7967
  getTheLessLateInBasEsEfConstraint(activity, lfFromLinks, constraintType) {
8161
7968
  let esEfFromConstraint = this.forwardConstraintsMap.get(activity);
8162
7969
  if (!esEfFromConstraint) {
@@ -8175,23 +7982,6 @@ var BackwardPath = class extends generic_calculations_default {
8175
7982
  }
8176
7983
  return { ls: esEfFromConstraint.es, lf: esEfFromConstraint.ef };
8177
7984
  }
8178
- /**
8179
- * Checks whether all activities linked to the given set of activities have progress greater than 0.
8180
- *
8181
- * This function iterates over the linked activities, retrieves their data, and checks if all of them have progress greater than 0.
8182
- * If any linked activity has 0 progress, the function returns false. If all linked activities have progress, it returns true.
8183
- *
8184
- * @param {Array<string|number>} linkedActivities - An array of linked activity IDs.
8185
- * @returns {boolean} True if all linked activities have progress greater than 0, otherwise false.
8186
- *
8187
- * @example
8188
- * // Assuming linkedActivities is an array containing linked activity IDs [1, 2, 3]
8189
- * const allHaveProgress = allLinkedActivitiesHasProgress([1, 2, 3]);
8190
- * console.log()
8191
- // true or false based on the progress of the linked activities
8192
- *
8193
- * @throws {Error} If an error occurs during the process, such as missing link data or activity data.
8194
- */
8195
7985
  allLinkedActivitiesHasProgress(linkedActivities) {
8196
7986
  try {
8197
7987
  let allLinkedHasProgress = true;
@@ -8216,46 +8006,9 @@ var BackwardPath = class extends generic_calculations_default {
8216
8006
  throw new Error(error.message);
8217
8007
  }
8218
8008
  }
8219
- /**
8220
- * Sets the calculations for an activity that has 100% progress.
8221
- *
8222
- * This function uses the activity's start and end dates to set the calculations for the activity.
8223
- * It is assumed that the activity has 100% progress.
8224
- *
8225
- * @param {Object} activity - The activity object containing the details of the activity.
8226
- * @param {Date} activity.start_date - The start date of the activity.
8227
- * @param {Date} activity.end_date - The end date of the activity.
8228
- * @returns {void} This function does not return a value.
8229
- *
8230
- * @example
8231
- * // Assuming activity is an object with start_date and end_date properties
8232
- * setDatesForActivityWithFullProgress({
8233
- * start_date: new Date('2023-01-01'),
8234
- * end_date: new Date('2023-01-10')
8235
- * });
8236
- * // This will set the calculations for the activity using its start and end dates.
8237
- *
8238
- * @throws {Error} If an error occurs during the calculation process.
8239
- */
8240
8009
  setDatesForActivityWithFullProgress(activity) {
8241
8010
  this.setCalculations(activity, activity.start_date, activity.end_date);
8242
8011
  }
8243
- /**
8244
- * Sets the calculations for an activity when all its linked activities have progress.
8245
- *
8246
- * This function calculates the latest start (LS) and latest finish (LF) times for the activity using a backward direction,
8247
- * and sets these values in the internal calculations.
8248
- *
8249
- * @param {Object} activity - The activity object containing the details of the activity.
8250
- * @returns {void} This function does not return a value.
8251
- *
8252
- * @example
8253
- * // Assuming activity is an object with necessary properties for calculation
8254
- * setWhenAllLinkedActivitiesHasProgress(activity);
8255
- * // This will calculate LS and LF for the activity and set these values in the internal calculations.
8256
- *
8257
- * @throws {Error} If an error occurs during the calculation process.
8258
- */
8259
8012
  setWhenAllLinkedActivitiesHasProgress(activity) {
8260
8013
  const parent = Number(activity.parent);
8261
8014
  let { ls, lf } = this.calculateStartAndFinishOfChainOrigin(
@@ -8272,23 +8025,6 @@ var BackwardPath = class extends generic_calculations_default {
8272
8025
  this.setCalculations(activity, ls, lf);
8273
8026
  return;
8274
8027
  }
8275
- /**
8276
- * Sets the calculations for an activity with progress greater than 0% but less than 100%.
8277
- *
8278
- * This function handles activities based on their constraint type when the progress is between 0% and 100%.
8279
- * It sets the calculations accordingly using the activity's start and end dates, or the constraint dates.
8280
- *
8281
- * @param {Object} activity - The activity object containing the details of the activity.
8282
- * @param {string} constraintType - The constraint type of the activity, such as 'mso' or 'mfo'.
8283
- * @returns {void} This function does not return a value.
8284
- *
8285
- * @example
8286
- * // Assuming activity is an object with start_date, end_date, and constraint_date properties, and constraintType is 'mso'
8287
- * setWhenActivitiesHasProgressButLessThanOneHundred(activity, 'mso');
8288
- * // This will set the calculations for the activity using its start and end dates.
8289
- *
8290
- * @throws {Error} If an error occurs during the calculation process.
8291
- */
8292
8028
  setWhenActivitiesHasProgressButLessThanOneHundred(activity, constraintType) {
8293
8029
  if (constraintType === CONSTRAINT_TYPES.MSO) {
8294
8030
  this.setCalculations(activity, activity.start_date, activity.end_date);
@@ -8304,24 +8040,6 @@ var BackwardPath = class extends generic_calculations_default {
8304
8040
  return;
8305
8041
  }
8306
8042
  }
8307
- /**
8308
- * Sets the latest start (LS) and latest finish (LF) times for a given activity in the internal calculations map.
8309
- *
8310
- * This function stores the LS and LF times, along with the activity's text, in the internal `calculations` map
8311
- * using the activity's ID as the key.
8312
- *
8313
- * @param {Object} activity - The activity object containing the details of the activity.
8314
- * @param {Date} ls - The latest start time for the activity.
8315
- * @param {Date} lf - The latest finish time for the activity.
8316
- * @returns {void} This function does not return a value.
8317
- *
8318
- * @example
8319
- * // Assuming activity is an object with id and text properties, and ls and lf are Date objects
8320
- * setCalculations(activity, new Date('2023-01-01'), new Date('2023-01-10'));
8321
- * // This will store the LS and LF times in the calculations map for the given activity.
8322
- *
8323
- * @throws {Error} If an error occurs during the calculation process.
8324
- */
8325
8043
  setCalculations(activity, ls, lf) {
8326
8044
  this.calculations.set(activity.id, {
8327
8045
  ls,
@@ -8329,28 +8047,6 @@ var BackwardPath = class extends generic_calculations_default {
8329
8047
  text: activity.text
8330
8048
  });
8331
8049
  }
8332
- /**
8333
- * Calculates the latest start (LS) and latest finish (LF) times for an activity based on its links with successors and the given constraint type.
8334
- *
8335
- * This function creates a new instance of the `LinksConstraintCalculator` class with the provided parameters and calls its `calculate` method
8336
- * to determine the LS and LF times for the activity.
8337
- *
8338
- * @param {Array<string|number>} linksWithSucessors - An array of links to successor activities.
8339
- * @param {Object} activityReference - The activity object for which to calculate LS and LF times.
8340
- * @param {string} constraintType - The constraint type of the activity.
8341
- * @returns {Object} An object containing the calculated latest start (LS) and latest finish (LF) times.
8342
- * @property {Date} ls - The calculated latest start time.
8343
- * @property {Date} lf - The calculated latest finish time.
8344
- *
8345
- * @example
8346
- * // Assuming linksWithSucessors is an array of link IDs, activityReference is an activity object,
8347
- * // and constraintType is a string representing the constraint type
8348
- * const result = calculateLfandLsFromLinks([1, 2, 3], activityReference, 'mso');
8349
- * console.log()
8350
- // { ls: Date, lf: Date }
8351
- *
8352
- * @throws {Error} If an error occurs during the calculation process.
8353
- */
8354
8050
  calculateLfandLsFromLinks(linksWithSucessors, activityReference, constraintType, parentsWithFullProgress, parentsThatImpactChildrens) {
8355
8051
  return new LinksConstraintCalculator_default({
8356
8052
  links: linksWithSucessors,
@@ -8363,23 +8059,6 @@ var BackwardPath = class extends generic_calculations_default {
8363
8059
  ganttInstance: this.gantt
8364
8060
  }).calculate();
8365
8061
  }
8366
- /**
8367
- * Recalculates the latest start (LS) and latest finish (LF) times for an activity based on its constraint type.
8368
- *
8369
- * This function fetches the activity's calendar, calculates the restriction based on the constraint type,
8370
- * updates the constraint map, and sets the new calculations for the activity.
8371
- *
8372
- * @param {Object} activity - The activity object containing the details of the activity.
8373
- * @param {string} constraintType - The constraint type of the activity.
8374
- * @returns {void} This function does not return a value.
8375
- *
8376
- * @example
8377
- * // Assuming activity is an object with calendar_id property, and constraintType is 'mso'
8378
- * recalculateInBaseRestriction(activity, 'mso');
8379
- * // This will recalculate the LS and LF times for the activity based on the constraint type and update the internal calculations.
8380
- *
8381
- * @throws {Error} If an error occurs during the calculation process, such as missing calendar data.
8382
- */
8383
8062
  recalculateInBaseRestriction(activity, constraintType) {
8384
8063
  try {
8385
8064
  const activityCalendar = this.gantt.getCalendar(activity.calendar_id);
@@ -9427,6 +9106,8 @@ var NON_SCHEDULING_KINDS = /* @__PURE__ */ new Set([
9427
9106
  "selection-toggle",
9428
9107
  "selection-replace",
9429
9108
  "visibility-set",
9109
+ "filter-set",
9110
+ "sort-set",
9430
9111
  "sir-sync",
9431
9112
  "activity-lookahead-sync",
9432
9113
  "persistence-acknowledge",
@@ -9434,6 +9115,16 @@ var NON_SCHEDULING_KINDS = /* @__PURE__ */ new Set([
9434
9115
  "ponderator-criterion-set",
9435
9116
  "status-criteria-set"
9436
9117
  ]);
9118
+ var PURE_VIEW_STATE_KINDS = /* @__PURE__ */ new Set([
9119
+ "selection-toggle",
9120
+ "selection-replace",
9121
+ "visibility-set",
9122
+ "filter-set",
9123
+ "sort-set"
9124
+ ]);
9125
+ function reappliesViewState(action) {
9126
+ return !PURE_VIEW_STATE_KINDS.has(action.kind);
9127
+ }
9437
9128
  var NO_STRUCTURAL_EXEMPTIONS = /* @__PURE__ */ new Set();
9438
9129
  function editsOnlyNonSchedulingColumns(action) {
9439
9130
  if (action.kind === "inline-edit") {
@@ -9742,7 +9433,7 @@ function detectSirAutoReject(beforeSnap, adapter, touchedIds) {
9742
9433
  }
9743
9434
 
9744
9435
  // src/dispatch/shared/change-set.ts
9745
- function assembleChangeSet(adapter, args) {
9436
+ async function assembleChangeSet(adapter, args) {
9746
9437
  const allTouched = collectChangeSetIds(adapter, args);
9747
9438
  const before = new Map(args.beforeSnap);
9748
9439
  const captured = adapter.peekWriteCapture();
@@ -9751,7 +9442,16 @@ function assembleChangeSet(adapter, args) {
9751
9442
  mergeDirtyBeforeImages(adapter, captured, insertedIds, before, allTouched);
9752
9443
  }
9753
9444
  const beforeDiffEffects = args.sirDetection === "before-diff" ? detectSirAutoReject(before, adapter, allTouched) : [];
9754
- const activityChanges = buildActivityChanges(adapter, before, allTouched);
9445
+ const correlativeBefore = buildCorrelativeBeforeMap(
9446
+ args.correlativeShifts,
9447
+ allTouched
9448
+ );
9449
+ const activityChanges = await buildActivityChanges(
9450
+ adapter,
9451
+ before,
9452
+ allTouched,
9453
+ correlativeBefore
9454
+ );
9755
9455
  const effects = args.sirDetection === "after-diff" ? detectSirAutoReject(before, adapter, allTouched) : beforeDiffEffects;
9756
9456
  const warnings = args.warnings ?? [];
9757
9457
  return {
@@ -9759,12 +9459,20 @@ function assembleChangeSet(adapter, args) {
9759
9459
  activities: activityChanges,
9760
9460
  links: args.links ?? [],
9761
9461
  calendars: [],
9762
- // dispatch never mutates calendars
9763
9462
  trackingEvents: args.trackingEvents ?? [],
9764
9463
  ...effects.length > 0 ? { effects } : {},
9765
9464
  ...warnings.length > 0 ? { warnings } : {}
9766
9465
  };
9767
9466
  }
9467
+ function buildCorrelativeBeforeMap(shifts, touched) {
9468
+ if (!shifts || shifts.length === 0) return void 0;
9469
+ const correlativeBefore = /* @__PURE__ */ new Map();
9470
+ for (const shift of shifts) {
9471
+ correlativeBefore.set(shift.activityId, shift.before);
9472
+ touched.add(shift.activityId);
9473
+ }
9474
+ return correlativeBefore;
9475
+ }
9768
9476
  function collectChangeSetIds(adapter, args) {
9769
9477
  const ids = /* @__PURE__ */ new Set();
9770
9478
  for (const id of args.touchedIds) ids.add(id);
@@ -9962,7 +9670,7 @@ async function dispatchInlineEdit(action, options, deps) {
9962
9670
  parsed2.raw
9963
9671
  );
9964
9672
  const touchedIds = collectTouchedIds(action.activityId, changes);
9965
- const beforeSnap = snapshotActivities(adapter, touchedIds);
9673
+ const beforeSnap = await snapshotActivities(adapter, touchedIds);
9966
9674
  const beforeLinkLags = snapshotIncomingLinkLags(
9967
9675
  adapter,
9968
9676
  String(action.activityId)
@@ -10034,7 +9742,7 @@ async function dispatchInlineEdit(action, options, deps) {
10034
9742
  );
10035
9743
  return {
10036
9744
  ok: true,
10037
- changes: assembleChangeSet(adapter, {
9745
+ changes: await assembleChangeSet(adapter, {
10038
9746
  source: action,
10039
9747
  beforeSnap,
10040
9748
  touchedIds,
@@ -10144,7 +9852,10 @@ async function dispatchLinkBatch(operations, source, options, deps, deterministi
10144
9852
  const { adapter, scheduler, sector, linkIdGen } = deps;
10145
9853
  scheduler.invalidateAllCaches();
10146
9854
  const { activityIds: affectedActivityIds, links: beforeLinks } = collectBatchContext(operations, adapter);
10147
- const beforeActivities = snapshotActivities(adapter, affectedActivityIds);
9855
+ const beforeActivities = await snapshotActivities(
9856
+ adapter,
9857
+ affectedActivityIds
9858
+ );
10148
9859
  const applied = applyBatchOperations(
10149
9860
  operations,
10150
9861
  adapter,
@@ -10187,7 +9898,7 @@ async function dispatchLinkBatch(operations, source, options, deps, deterministi
10187
9898
  }
10188
9899
  ),
10189
9900
  __beforeLinks: stringKeyedLinkSnapshots(beforeLinks),
10190
- changes: assembleChangeSet(adapter, {
9901
+ changes: await assembleChangeSet(adapter, {
10191
9902
  source,
10192
9903
  beforeSnap: beforeActivities,
10193
9904
  touchedIds: affectedActivityIds,
@@ -10283,85 +9994,6 @@ var DISPATCH_TRACK_EVENT = {
10283
9994
  ACTIVITY_OUTDENT: "schedule_activity_outdent"
10284
9995
  };
10285
9996
 
10286
- // src/internal/hierarchy/visual-order.ts
10287
- var NOT_SET_SORT_VALUE = Number.MAX_SAFE_INTEGER;
10288
- function getChildrenInVisualOrder(parentId, adapter) {
10289
- const children = collectChildrenSnapshots(parentId, adapter);
10290
- children.sort(compareActivitiesInVisualOrder);
10291
- return children.map((a) => String(a.id));
10292
- }
10293
- function iterateInVisualOrder(adapter) {
10294
- const result = [];
10295
- const visit = (activity) => {
10296
- result.push(activity);
10297
- const childIds = getChildrenInVisualOrder(String(activity.id), adapter);
10298
- for (const childId of childIds) {
10299
- const child = adapter.getActivity(childId);
10300
- if (child) visit(child);
10301
- }
10302
- };
10303
- const rootIds = getChildrenInVisualOrder(ROOT_PARENT_ID, adapter);
10304
- for (const rootId of rootIds) {
10305
- const root = adapter.getActivity(rootId);
10306
- if (root) visit(root);
10307
- }
10308
- return result;
10309
- }
10310
- function findPreviousNonSelectedSibling(taskId, selected, adapter) {
10311
- const activity = adapter.getActivity(taskId);
10312
- if (!activity) return null;
10313
- const parentKey = parentKeyOf(activity);
10314
- const siblings = getChildrenInVisualOrder(parentKey, adapter);
10315
- const idx = siblings.findIndex((id) => String(id) === String(taskId));
10316
- if (idx <= 0) return null;
10317
- for (let i = idx - 1; i >= 0; i--) {
10318
- const candidateId = siblings[i];
10319
- if (candidateId === void 0) continue;
10320
- if (!setHas(selected, candidateId)) return candidateId;
10321
- }
10322
- return null;
10323
- }
10324
- function visualIndexInParent(taskId, adapter) {
10325
- const activity = adapter.getActivity(taskId);
10326
- if (!activity) return -1;
10327
- const parentKey = parentKeyOf(activity);
10328
- const siblings = getChildrenInVisualOrder(parentKey, adapter);
10329
- return siblings.findIndex((id) => String(id) === String(taskId));
10330
- }
10331
- function collectChildrenSnapshots(parentId, adapter) {
10332
- const key = String(parentId);
10333
- if (key === "0") {
10334
- return adapter.getAllActivities().filter((a) => a.parentId === null);
10335
- }
10336
- const childIds = adapter.getChildren(parentId);
10337
- const out = [];
10338
- for (const id of childIds) {
10339
- const snap = adapter.getActivity(id);
10340
- if (snap) out.push(snap);
10341
- }
10342
- return out;
10343
- }
10344
- function compareActivitiesInVisualOrder(a, b) {
10345
- const ac = correlativeIdOf(a);
10346
- const bc = correlativeIdOf(b);
10347
- if (ac !== bc) return ac - bc;
10348
- return String(a.id).localeCompare(String(b.id));
10349
- }
10350
- function correlativeIdOf(activity) {
10351
- const raw = activity.correlativeId;
10352
- const n = typeof raw === "number" ? raw : Number(raw);
10353
- return Number.isFinite(n) ? n : NOT_SET_SORT_VALUE;
10354
- }
10355
- function parentKeyOf(activity) {
10356
- const parentId = activity.parentId;
10357
- if (parentId === null) return "0";
10358
- return parentId;
10359
- }
10360
- function setHas(set, id) {
10361
- if (set.has(id)) return true;
10362
- return set.has(String(id));
10363
- }
10364
-
10365
9997
  // src/internal/hierarchy/recompute-correlative-ids.ts
10366
9998
  function recomputeCorrelativeIds(adapter) {
10367
9999
  adapter.invalidateVisualOrderIds?.();
@@ -10794,7 +10426,7 @@ function computeFractionalCidAtIndex(adapter, parentKey, targetIndex, excludeId)
10794
10426
  }
10795
10427
 
10796
10428
  // src/dispatch/handlers/activity-create.ts
10797
- function createActivityCore(action, deps, opts = {}) {
10429
+ async function createActivityCore(action, deps, opts = {}) {
10798
10430
  const { adapter, scheduler, sector, calendars, activityIdGen, uidGen } = deps;
10799
10431
  scheduler.invalidateAllCaches();
10800
10432
  const target = validateCreateTarget(action, adapter);
@@ -10835,7 +10467,7 @@ function createActivityCore(action, deps, opts = {}) {
10835
10467
  const initialTouched = /* @__PURE__ */ new Set([newId]);
10836
10468
  if (parent) initialTouched.add(parent.id);
10837
10469
  const parentWasLeaf = parent !== null && adapter.getChildren(parent.id).length === 0;
10838
- const beforeSnap = opts.skipBeforeSnap ? /* @__PURE__ */ new Map() : snapshotActivities(adapter, initialTouched);
10470
+ const beforeSnap = opts.skipBeforeSnap ? /* @__PURE__ */ new Map() : await snapshotActivities(adapter, initialTouched);
10839
10471
  adapter.addActivity(newActivity);
10840
10472
  applyParentMutations(
10841
10473
  action,
@@ -10955,7 +10587,7 @@ function recomputeAndFoldCorrelatives(adapter, newId, beforeSnap, initialTouched
10955
10587
  initialTouched
10956
10588
  );
10957
10589
  }
10958
- function buildCreateChangeSet(adapter, action, coreResult, scheduledIds, hoursPerDay) {
10590
+ async function buildCreateChangeSet(adapter, action, coreResult, scheduledIds, hoursPerDay) {
10959
10591
  const { newId, newActivity, beforeSnap, initialTouched } = coreResult;
10960
10592
  const trackingEvent = {
10961
10593
  name: DISPATCH_TRACK_EVENT.ACTIVITY_CREATION,
@@ -10977,7 +10609,7 @@ function buildCreateChangeSet(adapter, action, coreResult, scheduledIds, hoursPe
10977
10609
  }
10978
10610
  async function dispatchActivityCreate(action, options, deps) {
10979
10611
  const { adapter, scheduler, sector } = deps;
10980
- const core = createActivityCore(action, deps);
10612
+ const core = await createActivityCore(action, deps);
10981
10613
  if (!core.ok) return core;
10982
10614
  const { newId } = core;
10983
10615
  const createdAutoScheduling = core.newActivity.autoScheduling;
@@ -11003,7 +10635,7 @@ async function dispatchActivityCreate(action, options, deps) {
11003
10635
  adapter.setActivityField(newId, "autoScheduling", createdAutoScheduling);
11004
10636
  }
11005
10637
  const { scheduledIds } = scheduleOutcome;
11006
- const changeset = buildCreateChangeSet(
10638
+ const changeset = await buildCreateChangeSet(
11007
10639
  adapter,
11008
10640
  action,
11009
10641
  core,
@@ -11053,7 +10685,7 @@ async function dispatchActivityPaste(action, options, deps) {
11053
10685
  const { adapter, scheduler, sector } = deps;
11054
10686
  const rootDest = resolvePasteRootDestination(action.destination, adapter);
11055
10687
  if (!rootDest.ok) return rootDest;
11056
- const beforeSnap = snapshotActivities(adapter, /* @__PURE__ */ new Set());
10688
+ const beforeSnap = await snapshotActivities(adapter, /* @__PURE__ */ new Set());
11057
10689
  const touched = /* @__PURE__ */ new Set();
11058
10690
  const originalToNew = /* @__PURE__ */ new Map();
11059
10691
  const createdIds = [];
@@ -11074,7 +10706,7 @@ async function dispatchActivityPaste(action, options, deps) {
11074
10706
  afterSiblingId = prevRootId;
11075
10707
  }
11076
10708
  }
11077
- const core = createActivityCore(
10709
+ const core = await createActivityCore(
11078
10710
  {
11079
10711
  parentId,
11080
10712
  afterSiblingId,
@@ -11085,16 +10717,8 @@ async function dispatchActivityPaste(action, options, deps) {
11085
10717
  },
11086
10718
  deps,
11087
10719
  {
11088
- // Saltamos el recompute por-create: corre UNA vez tras el loop (abajo).
11089
10720
  skipCorrelativeRecompute: true,
11090
- // Saltamos el snapshot per-create: el paste ya capturó `beforeSnap` del
11091
- // árbol completo antes del loop (O(N²) de clones puros si no).
11092
10721
  skipBeforeSnap: true,
11093
- // custom_id (paridad legacy): TODAS las pegadas derivan del ancla de
11094
- // pegado. Los roots ya lo logran vía `afterSiblingId`; los HIJOS
11095
- // (mappedParent) no tienen sibling anchor → les pasamos el ancla como
11096
- // `customIdReferenceId`, y preservamos el custom_id de su parent pegado
11097
- // (que si no, `buildParentMutations` limpiaría al adjuntar el hijo).
11098
10722
  ...mappedParent !== void 0 ? {
11099
10723
  customIdReferenceId: action.referenceActivityId,
11100
10724
  preserveParentCustomId: true
@@ -11138,9 +10762,6 @@ async function dispatchActivityPaste(action, options, deps) {
11138
10762
  source: newSource,
11139
10763
  target: newTarget,
11140
10764
  type: link.type,
11141
- // El clipboard trae `lag` en DÍAS (getLink/getAllLinks → lagHoursToDays);
11142
- // el motor lo almacena en HORAS LABORALES. Convertir acá, igual que
11143
- // `duration` arriba y que `link-create`/`link-update` — el borde de entrada.
11144
10765
  lag: lagDaysToHours(link.lag, sector.hoursPerDay)
11145
10766
  };
11146
10767
  const res = applyLinkOperation(op, {
@@ -11175,7 +10796,7 @@ async function dispatchActivityPaste(action, options, deps) {
11175
10796
  );
11176
10797
  return {
11177
10798
  ok: true,
11178
- changes: assembleChangeSet(adapter, {
10799
+ changes: await assembleChangeSet(adapter, {
11179
10800
  source: action,
11180
10801
  beforeSnap,
11181
10802
  touchedIds: touched,
@@ -11387,6 +11008,7 @@ function buildParentNewActivitiesCleanup(input) {
11387
11008
  }
11388
11009
 
11389
11010
  // src/dispatch/handlers/activity-delete.ts
11011
+ var DELETE_YIELD_EVERY_N = 200;
11390
11012
  async function dispatchActivityDelete(action, options, deps) {
11391
11013
  const { adapter, scheduler, customIdTracker, sector } = deps;
11392
11014
  scheduler.invalidateAllCaches();
@@ -11410,14 +11032,17 @@ async function dispatchActivityDelete(action, options, deps) {
11410
11032
  if (!toDelete.has(parentKey)) parentsToCheck.add(parentKey);
11411
11033
  }
11412
11034
  const touchedIds = /* @__PURE__ */ new Set([...toDelete, ...parentsToCheck]);
11413
- const beforeSnap = snapshotActivities(adapter, touchedIds);
11035
+ const beforeSnap = await snapshotActivities(adapter, touchedIds);
11414
11036
  const beforeLinks = /* @__PURE__ */ new Map();
11415
11037
  for (const linkId of incidentLinkIds) {
11416
11038
  const l = adapter.getLink(linkId);
11417
11039
  if (l) beforeLinks.set(linkId, { ...l });
11418
11040
  }
11419
11041
  const newActivitiesToDelete = /* @__PURE__ */ new Set();
11042
+ let inspected = 0;
11420
11043
  for (const id of toDelete) {
11044
+ inspected += 1;
11045
+ if (inspected % DELETE_YIELD_EVERY_N === 0) await yieldToBrowser();
11421
11046
  const a = adapter.getActivity(id);
11422
11047
  if (!a) continue;
11423
11048
  const parent = isRootParent(a.parentId) ? null : adapter.getActivity(String(a.parentId));
@@ -11434,7 +11059,10 @@ async function dispatchActivityDelete(action, options, deps) {
11434
11059
  adapter.removeLink(linkId);
11435
11060
  }
11436
11061
  const viewStateChanges = captureDeletedViewState(adapter, toDelete);
11062
+ let removed = 0;
11437
11063
  for (const id of toDelete) {
11064
+ removed += 1;
11065
+ if (removed % DELETE_YIELD_EVERY_N === 0) await yieldToBrowser();
11438
11066
  adapter.removeActivity(id);
11439
11067
  }
11440
11068
  for (const parentId of parentsToCheck) {
@@ -11474,15 +11102,6 @@ async function dispatchActivityDelete(action, options, deps) {
11474
11102
  recomputeRollupCascadesForParent(parentId, adapter);
11475
11103
  }
11476
11104
  const correlativeShifts = recomputeCorrelativeIds(adapter);
11477
- for (const shift of correlativeShifts) {
11478
- touchedIds.add(shift.activityId);
11479
- if (beforeSnap.has(shift.activityId)) continue;
11480
- const liveActivity = adapter.getActivity(shift.activityId);
11481
- if (!liveActivity) continue;
11482
- const beforeImage = structuredCloneActivity(liveActivity);
11483
- if (shift.before !== void 0) beforeImage.correlativeId = shift.before;
11484
- beforeSnap.set(shift.activityId, beforeImage);
11485
- }
11486
11105
  const { scheduledIds } = await runPostMutation(
11487
11106
  {
11488
11107
  adapter,
@@ -11515,7 +11134,7 @@ async function dispatchActivityDelete(action, options, deps) {
11515
11134
  const snap = beforeSnap.get(String(id));
11516
11135
  if (snap) deletedRowsSnap.set(String(id), snap);
11517
11136
  }
11518
- const changes = assembleChangeSet(adapter, {
11137
+ const changes = await assembleChangeSet(adapter, {
11519
11138
  source: action,
11520
11139
  beforeSnap,
11521
11140
  touchedIds,
@@ -11523,7 +11142,8 @@ async function dispatchActivityDelete(action, options, deps) {
11523
11142
  sirDetection: "after-diff",
11524
11143
  links: buildLinkDeletions(beforeLinks),
11525
11144
  trackingEvents: [trackingEvent],
11526
- hoursPerDay: sector.hoursPerDay
11145
+ hoursPerDay: sector.hoursPerDay,
11146
+ correlativeShifts
11527
11147
  });
11528
11148
  return {
11529
11149
  ok: true,
@@ -11563,8 +11183,6 @@ function buildLinkDeletions(beforeLinks) {
11563
11183
  source: { before: String(before.source), after: void 0 },
11564
11184
  target: { before: String(before.target), after: void 0 },
11565
11185
  type: { before: before.type, after: void 0 },
11566
- // Engine stores lag in WORKING HOURS — ChangeSet now emits HOURS too.
11567
- // `toPublicChangeSet` at the facade boundary converts to days (default).
11568
11186
  lag: { before: Number(before.lag), after: void 0 }
11569
11187
  },
11570
11188
  after: null
@@ -11653,7 +11271,7 @@ async function dispatchActivityMove(action, options, deps) {
11653
11271
  } else {
11654
11272
  if (oldParentKey !== ROOT_PARENT_ID) touched.add(oldParentKey);
11655
11273
  }
11656
- const beforeSnap = snapshotActivities(adapter, touched);
11274
+ const beforeSnap = await snapshotActivities(adapter, touched);
11657
11275
  if (parentChanged) {
11658
11276
  adapter.setActivityField(
11659
11277
  action.activityId,
@@ -11683,8 +11301,6 @@ async function dispatchActivityMove(action, options, deps) {
11683
11301
  newChildId: action.activityId,
11684
11302
  getParent: (id) => adapter.getActivity(id) ?? null,
11685
11303
  isCurrentlyLeaf: wasLeaf,
11686
- // Move reparents an EXISTING child — legacy never re-stamps the new
11687
- // parent's progress (it keeps its pre-move leaf value). See JUN-23.
11688
11304
  promotionSource: "reparent"
11689
11305
  });
11690
11306
  if (promotion) {
@@ -11793,7 +11409,7 @@ async function dispatchActivityMove(action, options, deps) {
11793
11409
  }
11794
11410
  return {
11795
11411
  ok: true,
11796
- changes: assembleChangeSet(adapter, {
11412
+ changes: await assembleChangeSet(adapter, {
11797
11413
  source: action,
11798
11414
  beforeSnap,
11799
11415
  touchedIds: touched,
@@ -11855,7 +11471,7 @@ async function dispatchActivityIndent(action, options, deps) {
11855
11471
  touched.add(targetParentId);
11856
11472
  if (oldParentId !== ROOT_PARENT_ID) touched.add(oldParentId);
11857
11473
  }
11858
- const beforeSnap = snapshotActivities(adapter, touched);
11474
+ const beforeSnap = await snapshotActivities(adapter, touched);
11859
11475
  for (const { activityId, newParentId } of moves) {
11860
11476
  adapter.setActivityField(activityId, ACTIVITY_PROPERTY.PARENT, newParentId);
11861
11477
  adapter.setActivityField(
@@ -11879,8 +11495,6 @@ async function dispatchActivityIndent(action, options, deps) {
11879
11495
  newChildId: activityId,
11880
11496
  getParent: (id) => adapter.getActivity(id) ?? null,
11881
11497
  isCurrentlyLeaf: wasLeaf,
11882
- // Indent reparents an EXISTING child — legacy never re-stamps the new
11883
- // parent's progress (it keeps its pre-indent leaf value). See JUN-23.
11884
11498
  promotionSource: "reparent"
11885
11499
  });
11886
11500
  if (promotion) {
@@ -11947,33 +11561,8 @@ async function dispatchActivityIndent(action, options, deps) {
11947
11561
  },
11948
11562
  {
11949
11563
  action,
11950
- // A pure indent (reparent) does NOT auto-reschedule dates in legacy:
11951
- // `actions.indent` runs purely through `gantt.moveTask`, firing only
11952
- // `onBeforeTaskMove`/`onAfterTaskMove` — never `autoSchedule()` /
11953
- // `onAfterAutoSchedule`. So the moved child + its downstream chain KEEP
11954
- // their pre-indent dates; only the new parent's bounds re-roll (via
11955
- // DHTMLX `_update_parents` in the move's batchUpdate — done unconditionally
11956
- // by `updateParentBoundsFromChildren` below). The core previously passed
11957
- // `{}` here, running a full ASAP/ALAP reflow that pulled the moved child +
11958
- // chain as-early-as-possible — diverging from the oracle (MORNING_QUEUE.md
11959
- // — JUN-11 corr20 stays 2024-05-07 stale, core moved it to 04-30; JUN-16(B)
11960
- // corr33 stays 2026-10-21 stale, core pulled it to 09-16). `null` suppresses
11961
- // the date cascade entirely, completing the outdent mirror (outdent's `{}`
11962
- // was always a no-op because its moved child keeps its links/position; a
11963
- // childless leaf + reparent of an EXISTING activity is never the trigger
11964
- // of an autoSchedule). A SUBSEQUENT date/constraint/link edit still
11965
- // cascades normally (its own handler passes a non-null trigger).
11966
11564
  autoscheduleFrom: null,
11967
11565
  recomputeParentsFrom: succeededIds,
11968
- // A pure indent re-rolls the new parent's start/end/duration but legacy
11969
- // leaves `for_disable_milestone_duration` STALE at the pre-indent value —
11970
- // the milestone-promotion branch (`adjustParentMilestone`) only fires for a
11971
- // 0-duration milestone, never a task → project promotion (MORNING_QUEUE.md
11972
- // — JUN-18 / JUN-11). A later scheduling recalc that re-rolls these parents
11973
- // re-derives the mirror = duration — that is how the oracle's mirror is
11974
- // FRESH whenever an edit follows the indent (MORNING_QUEUE.md — JUN-19).
11975
- // `resolveDerivedPasses` skips the ancestor stamp for activity-indent.
11976
- // activity-indent is a structural reparent: leaves EP and CP stale.
11977
11566
  now: deps.now,
11978
11567
  options
11979
11568
  }
@@ -12005,7 +11594,7 @@ async function dispatchActivityIndent(action, options, deps) {
12005
11594
  reason: failure.reason
12006
11595
  } : { activityId: String(activityId), ok: true };
12007
11596
  }),
12008
- changes: assembleChangeSet(adapter, {
11597
+ changes: await assembleChangeSet(adapter, {
12009
11598
  source: action,
12010
11599
  beforeSnap,
12011
11600
  touchedIds: touched,
@@ -12103,7 +11692,7 @@ async function dispatchActivityOutdent(action, options, deps) {
12103
11692
  if (grandparentKey !== ROOT_PARENT_ID) touched.add(String(grandparentKey));
12104
11693
  oldParents.add(oldParentKey);
12105
11694
  }
12106
- const beforeSnap = snapshotActivities(adapter, touched);
11695
+ const beforeSnap = await snapshotActivities(adapter, touched);
12107
11696
  for (const plan of planned) {
12108
11697
  adapter.setActivityField(
12109
11698
  plan.activityId,
@@ -12190,12 +11779,9 @@ async function dispatchActivityOutdent(action, options, deps) {
12190
11779
  defaultBaseCalendarId: deps.defaultBaseCalendarId
12191
11780
  },
12192
11781
  {
12193
- // Empty-batch gate: nothing moved → no autoscheduler pass (the
12194
- // unconditional parent-bounds rollup still runs).
12195
11782
  action,
12196
11783
  autoscheduleFrom: succeededIds.length > 0 ? "roots" : null,
12197
11784
  recomputeParentsFrom: succeededIds,
12198
- // activity-outdent is a structural reparent: leaves EP and CP stale.
12199
11785
  now: deps.now,
12200
11786
  options
12201
11787
  }
@@ -12225,7 +11811,7 @@ async function dispatchActivityOutdent(action, options, deps) {
12225
11811
  reason: failure.reason
12226
11812
  } : { activityId: String(activityId), ok: true };
12227
11813
  }),
12228
- changes: assembleChangeSet(adapter, {
11814
+ changes: await assembleChangeSet(adapter, {
12229
11815
  source: action,
12230
11816
  beforeSnap,
12231
11817
  touchedIds: touched,
@@ -12262,7 +11848,7 @@ async function dispatchActivitySetProgress(action, options, deps) {
12262
11848
  action.newValue
12263
11849
  );
12264
11850
  const touchedIds = collectTouchedIds(action.activityId, changes);
12265
- const beforeSnap = snapshotActivities(adapter, touchedIds);
11851
+ const beforeSnap = await snapshotActivities(adapter, touchedIds);
12266
11852
  applyFieldChanges(adapter, action.activityId, changes);
12267
11853
  runPostProcessorsOnAdapter(
12268
11854
  action.activityId,
@@ -12278,7 +11864,6 @@ async function dispatchActivitySetProgress(action, options, deps) {
12278
11864
  },
12279
11865
  {
12280
11866
  action,
12281
- // Pipeline gate: only schedule when the transform asked for it.
12282
11867
  autoscheduleFrom: changes.needsAutoSchedule ? action.activityId : null,
12283
11868
  recomputeParentsFrom: [],
12284
11869
  collectDirty: (sids) => collectDirtyForInlineEdit(action.activityId, touchedIds, sids),
@@ -12292,7 +11877,7 @@ async function dispatchActivitySetProgress(action, options, deps) {
12292
11877
  }));
12293
11878
  return {
12294
11879
  ok: true,
12295
- changes: assembleChangeSet(adapter, {
11880
+ changes: await assembleChangeSet(adapter, {
12296
11881
  source: action,
12297
11882
  beforeSnap,
12298
11883
  touchedIds,
@@ -12321,9 +11906,10 @@ async function dispatchDatesBatch(action, options, deps) {
12321
11906
  mergeBeforeSnapshots(beforeSnap, editTouched, deps);
12322
11907
  for (const id of editTouched) touchedIds.add(id);
12323
11908
  const beforeLinkLags = snapshotIncomingLinkLags(adapter, edit.activityId);
12324
- const preEditSnapshot = snapshotActivities(adapter, /* @__PURE__ */ new Set([String(edit.activityId)])).get(
11909
+ const preEditSnapshot = snapshotSingleActivity(
11910
+ adapter,
12325
11911
  String(edit.activityId)
12326
- ) ?? null;
11912
+ );
12327
11913
  applyFieldChanges(adapter, edit.activityId, outcome.changes);
12328
11914
  runPostProcessorsOnAdapter(
12329
11915
  edit.activityId,
@@ -12365,7 +11951,7 @@ async function dispatchDatesBatch(action, options, deps) {
12365
11951
  return {
12366
11952
  ok: true,
12367
11953
  verdicts,
12368
- changes: assembleChangeSet(adapter, {
11954
+ changes: await assembleChangeSet(adapter, {
12369
11955
  source: action,
12370
11956
  beforeSnap,
12371
11957
  touchedIds,
@@ -12446,8 +12032,11 @@ function mergeBeforeSnapshots(beforeSnap, ids, deps) {
12446
12032
  if (!beforeSnap.has(id)) missing.add(id);
12447
12033
  }
12448
12034
  if (missing.size === 0) return;
12449
- for (const [id, snap] of snapshotActivities(deps.adapter, missing)) {
12450
- beforeSnap.set(id, snap);
12035
+ for (const missingId of missing) {
12036
+ const liveActivity = deps.adapter.getActivity(missingId);
12037
+ if (liveActivity) {
12038
+ beforeSnap.set(missingId, structuredCloneActivity(liveActivity));
12039
+ }
12451
12040
  }
12452
12041
  }
12453
12042
 
@@ -12487,9 +12076,10 @@ async function dispatchBulkEdit(action, options, deps) {
12487
12076
  explicitDateEditActivities.add(String(edit.activityId));
12488
12077
  }
12489
12078
  const beforeLinkLags = snapshotIncomingLinkLags(adapter, edit.activityId);
12490
- const preEditSnapshot = snapshotActivities(adapter, /* @__PURE__ */ new Set([String(edit.activityId)])).get(
12079
+ const preEditSnapshot = snapshotSingleActivity(
12080
+ adapter,
12491
12081
  String(edit.activityId)
12492
- ) ?? null;
12082
+ );
12493
12083
  const customIdBeforeApply = readLiveCustomId(edit, deps);
12494
12084
  const changes = outcome.changes;
12495
12085
  applyFieldChanges(adapter, edit.activityId, changes);
@@ -12553,14 +12143,11 @@ async function dispatchBulkEdit(action, options, deps) {
12553
12143
  return {
12554
12144
  ok: true,
12555
12145
  verdicts,
12556
- changes: assembleChangeSet(adapter, {
12146
+ changes: await assembleChangeSet(adapter, {
12557
12147
  source: action,
12558
12148
  beforeSnap,
12559
12149
  touchedIds,
12560
12150
  scheduledIds,
12561
- // Los dependientes que mueve el autoscheduler no están en beforeSnap;
12562
- // sin su before-image el diff los marca FALSE-CREATED y el undo los
12563
- // borra (fix 4bbccbc de inline-edit).
12564
12151
  sirDetection: "before-diff",
12565
12152
  links: linkChanges,
12566
12153
  trackingEvents,
@@ -12687,11 +12274,11 @@ function mergeBeforeSnapshots2(beforeSnap, ids, deps) {
12687
12274
  if (!beforeSnap.has(candidateId)) missing.add(candidateId);
12688
12275
  }
12689
12276
  if (missing.size === 0) return;
12690
- for (const [snappedId, snapshot] of snapshotActivities(
12691
- deps.adapter,
12692
- missing
12693
- )) {
12694
- beforeSnap.set(snappedId, snapshot);
12277
+ for (const missingId of missing) {
12278
+ const liveActivity = deps.adapter.getActivity(missingId);
12279
+ if (liveActivity) {
12280
+ beforeSnap.set(missingId, structuredCloneActivity(liveActivity));
12281
+ }
12695
12282
  }
12696
12283
  }
12697
12284
 
@@ -13115,8 +12702,8 @@ function activeBaselineSignature(deps) {
13115
12702
  })
13116
12703
  );
13117
12704
  }
13118
- function dispatchBaselineApply(action, deps) {
13119
- const beforeSnap = snapshotActivities(
12705
+ async function dispatchBaselineApply(action, deps) {
12706
+ const beforeSnap = await snapshotActivities(
13120
12707
  deps.adapter,
13121
12708
  new Set(deps.adapter.getAllIds())
13122
12709
  );
@@ -13136,7 +12723,7 @@ function dispatchBaselineApply(action, deps) {
13136
12723
  }
13137
12724
  return {
13138
12725
  ok: true,
13139
- changes: assembleChangeSet(deps.adapter, {
12726
+ changes: await assembleChangeSet(deps.adapter, {
13140
12727
  source: action,
13141
12728
  beforeSnap,
13142
12729
  touchedIds: changedIds,
@@ -13153,15 +12740,15 @@ function assertValidCriterion(value) {
13153
12740
  `ponderator-criterion-set: invalid criterion "${String(value)}"`
13154
12741
  );
13155
12742
  }
13156
- function dispatchPonderatorCriterionSet(action, deps) {
12743
+ async function dispatchPonderatorCriterionSet(action, deps) {
13157
12744
  assertValidCriterion(action.criterion);
13158
12745
  const allIds = new Set(deps.adapter.getAllIds());
13159
- const beforeSnap = snapshotActivities(deps.adapter, allIds);
12746
+ const beforeSnap = await snapshotActivities(deps.adapter, allIds);
13160
12747
  recomputeBaselineWeightedFields(deps, action.criterion);
13161
12748
  deps.sector.activityCreter = action.criterion;
13162
12749
  return {
13163
12750
  ok: true,
13164
- changes: assembleChangeSet(deps.adapter, {
12751
+ changes: await assembleChangeSet(deps.adapter, {
13165
12752
  source: action,
13166
12753
  beforeSnap,
13167
12754
  touchedIds: allIds,
@@ -13172,15 +12759,15 @@ function dispatchPonderatorCriterionSet(action, deps) {
13172
12759
  }
13173
12760
 
13174
12761
  // src/dispatch/handlers/status-criteria-set.ts
13175
- function dispatchStatusCriteriaSet(action, deps) {
12762
+ async function dispatchStatusCriteriaSet(action, deps) {
13176
12763
  const resolved = resolveStatusCriteria(action.criteria);
13177
12764
  const allIds = new Set(deps.adapter.getAllIds());
13178
- const beforeSnap = snapshotActivities(deps.adapter, allIds);
12765
+ const beforeSnap = await snapshotActivities(deps.adapter, allIds);
13179
12766
  const changedIds = applyStatusPass(deps.adapter, resolved);
13180
12767
  deps.sector.statusCriteria = resolved;
13181
12768
  return {
13182
12769
  ok: true,
13183
- changes: assembleChangeSet(deps.adapter, {
12770
+ changes: await assembleChangeSet(deps.adapter, {
13184
12771
  source: action,
13185
12772
  beforeSnap,
13186
12773
  touchedIds: changedIds,
@@ -13246,6 +12833,15 @@ async function dispatch(action, options, deps) {
13246
12833
  if (action.kind === "visibility-set") {
13247
12834
  return dispatchVisibilitySet(action, selectionDeps(deps));
13248
12835
  }
12836
+ if (action.kind === "filter-set") {
12837
+ return dispatchFilterSet(action, {
12838
+ adapter: deps.adapter,
12839
+ hoursPerDay: deps.sector.hoursPerDay
12840
+ });
12841
+ }
12842
+ if (action.kind === "sort-set") {
12843
+ return dispatchSortSet(action, { adapter: deps.adapter });
12844
+ }
13249
12845
  if (action.kind === "sir-sync") {
13250
12846
  return dispatchSirSync(action, deps);
13251
12847
  }
@@ -15768,9 +15364,7 @@ var defaultLocale = {
15768
15364
  function createGanttShim(options = {}) {
15769
15365
  const userConfig = options.config || {};
15770
15366
  const shim = {
15771
- // ------ Config ------
15772
15367
  config: Object.assign({
15773
- // Defaults críticos para calendar
15774
15368
  duration_unit: "hour",
15775
15369
  duration_step: 1,
15776
15370
  work_time: false,
@@ -15781,16 +15375,13 @@ function createGanttShim(options = {}) {
15781
15375
  resource_property: "resource_id",
15782
15376
  resource_calendars: {},
15783
15377
  dynamic_resource_calendars: false,
15784
- // Config date module
15785
15378
  start_on_monday: true,
15786
15379
  server_utc: true,
15787
15380
  csp: "auto",
15788
15381
  show_errors: false
15789
15382
  }, userConfig),
15790
- // ------ Locale + templates ------
15791
15383
  locale: options.locale || defaultLocale,
15792
15384
  templates: options.templates || {},
15793
- // ------ Task resolver (opcional) ------
15794
15385
  getTask: options.getTask || function(id) {
15795
15386
  return null;
15796
15387
  },
@@ -15800,11 +15391,9 @@ function createGanttShim(options = {}) {
15800
15391
  isSummaryTask: options.isSummaryTask || function(task) {
15801
15392
  return false;
15802
15393
  },
15803
- // ------ State (mínimo) ------
15804
15394
  getState: function() {
15805
15395
  return { group_mode: false };
15806
15396
  },
15807
- // ------ Eventable (no-ops por defecto) ------
15808
15397
  callEvent: function(name, args) {
15809
15398
  const handler = options.onEvent;
15810
15399
  if (handler) handler(name, args);
@@ -15818,7 +15407,6 @@ function createGanttShim(options = {}) {
15818
15407
  },
15819
15408
  detachEvent: function() {
15820
15409
  },
15821
- // ------ Utils expuestas en gantt2 ------
15822
15410
  defined,
15823
15411
  mixin,
15824
15412
  copy,
@@ -15828,7 +15416,6 @@ function createGanttShim(options = {}) {
15828
15416
  else if (options.silent !== true) console.error("[calendar]", msg);
15829
15417
  }
15830
15418
  },
15831
- // ------ $services / $ui — stubs minimales para evitar cracks ------
15832
15419
  $services: { getService: function() {
15833
15420
  return null;
15834
15421
  } },
@@ -15849,7 +15436,6 @@ function createGanttShim(options = {}) {
15849
15436
  function createCalendar(options = {}) {
15850
15437
  const shim = createGanttShim(options);
15851
15438
  return {
15852
- // ------ Gestión de calendarios ------
15853
15439
  addCalendar: function(c) {
15854
15440
  return shim.addCalendar(c);
15855
15441
  },
@@ -15871,7 +15457,6 @@ function createCalendar(options = {}) {
15871
15457
  getResourceCalendar: function(r) {
15872
15458
  return shim.getResourceCalendar(r);
15873
15459
  },
15874
- // ------ Cálculo (también disponible en cada Calendar instance) ------
15875
15460
  setWorkTime: function(c) {
15876
15461
  return shim.setWorkTime(c);
15877
15462
  },
@@ -15893,7 +15478,6 @@ function createCalendar(options = {}) {
15893
15478
  calculateEndDate: function() {
15894
15479
  return shim.calculateEndDate.apply(shim, arguments);
15895
15480
  },
15896
- // ------ Para inspección/debug ------
15897
15481
  _internals: shim
15898
15482
  };
15899
15483
  }
@@ -15921,16 +15505,11 @@ function normalizeWorktimeHours(hours) {
15921
15505
  return [`${first}:00-${last + 1}:00`];
15922
15506
  }
15923
15507
  var DEFAULT_WORKTIME = {
15924
- // 08:00..16:00 UTC, Mon..Fri. Matches the prior generic fallback used by
15925
- // synthetic fixtures and CPM nodes whose calendar id is genuinely unknown.
15926
15508
  hours: ["8:00-16:00"],
15927
15509
  days: [false, true, true, true, true, true, false]
15928
15510
  };
15929
15511
  var CATALOG_ONLY_CALENDAR_ID = "__main_global__";
15930
15512
  var CATALOG_ONLY_WORKTIME = {
15931
- // Native MAIN/DHTMLX global calendar. A calendar present in the selector but
15932
- // lacking usable shifts is not registered by MAIN, so its date arithmetic
15933
- // falls through to this split-day global calendar.
15934
15513
  hours: ["8:00-12:00", "13:00-17:00"],
15935
15514
  days: [false, true, true, true, true, true, false]
15936
15515
  };
@@ -16122,7 +15701,6 @@ var WriteCapture = class {
16122
15701
  end() {
16123
15702
  this._journal = null;
16124
15703
  }
16125
- /** Field write on an activity — pre-mutation clone on first write per id. */
16126
15704
  note(key, current) {
16127
15705
  const journal = this._journal;
16128
15706
  if (!journal) return;
@@ -16150,13 +15728,11 @@ var WriteCapture = class {
16150
15728
  before: cloneLink(current)
16151
15729
  });
16152
15730
  }
16153
- /** Pre-sweep correlative_id of an activity the renumbering shifted (first-wins). */
16154
15731
  noteCorrelativeBefore(activityId, before) {
16155
15732
  const journal = this._journal;
16156
15733
  if (!journal || journal.correlativeBefore.has(activityId)) return;
16157
15734
  journal.correlativeBefore.set(activityId, before);
16158
15735
  }
16159
- /** Pre-applyResults clone of an activity the autoscheduler will move (first-wins). */
16160
15736
  noteScheduledBefore(activityId, current) {
16161
15737
  const journal = this._journal;
16162
15738
  if (!journal) return;
@@ -16169,7 +15745,6 @@ var WriteCapture = class {
16169
15745
  }
16170
15746
  journal.dirty.add(activityId);
16171
15747
  }
16172
- /** Field write on a link — pre-mutation clone on first write per link id. */
16173
15748
  noteLinkField(linkId, current) {
16174
15749
  const journal = this._journal;
16175
15750
  if (!journal || journal.linkFieldCaptured.has(linkId)) return;
@@ -16187,17 +15762,11 @@ function cloneLink(link) {
16187
15762
 
16188
15763
  // src/internal/state/calendar-calculator.ts
16189
15764
  var CalendarCalculator = class {
16190
- // In-dispatch calendar API memoization. Lifetime = one scheduler run.
16191
15765
  _cache = {
16192
15766
  closestWorkTime: /* @__PURE__ */ new Map(),
16193
15767
  endDate: /* @__PURE__ */ new Map(),
16194
15768
  duration: /* @__PURE__ */ new Map()
16195
15769
  };
16196
- // Single owner of the calendar subsystem. The calc resolves calendars (incl.
16197
- // the `-base` ones and the default fallback) through the reader — one resolver
16198
- // for the whole calendar surface instead of a separate Map + default field.
16199
- /** Resolver for ANY calendar incl. the `-base` ones — also consumed by the
16200
- * column pipelines via `pipeline-context`. */
16201
15770
  reader;
16202
15771
  constructor(setup) {
16203
15772
  this.reader = setup.reader;
@@ -16240,11 +15809,6 @@ var CalendarCalculator = class {
16240
15809
  )
16241
15810
  );
16242
15811
  }
16243
- /**
16244
- * Clears the in-dispatch calendar API memoization. Call at the start of
16245
- * every scheduler run (calendars are immutable within a dispatch but may
16246
- * change across dispatches).
16247
- */
16248
15812
  clearCache() {
16249
15813
  this._cache.closestWorkTime.clear();
16250
15814
  this._cache.endDate.clear();
@@ -16277,16 +15841,7 @@ var HierarchyIndex = class {
16277
15841
  activities;
16278
15842
  _childrenByParent = /* @__PURE__ */ new Map();
16279
15843
  _roots = [];
16280
- /**
16281
- * When true, `_childrenByParent` is stale (a `parent` write happened) and is
16282
- * lazily rebuilt on the next `getChildren`. A bulk reparent (K rows) marks
16283
- * dirty K times but pays ONE rebuild on the next read instead of K — turning
16284
- * bulk indent/outdent from O(K·N) into O(K+N). Only `getChildren` reads this
16285
- * index; `getParent`/`getParentId`/`isChildOf` read `activities` directly and
16286
- * are always fresh, so they don't consult the flag. See PERFORMANCE.md §A3.
16287
- */
16288
15844
  _dirty = false;
16289
- /** Mark the children index stale; the next `getChildren` rebuilds it once. */
16290
15845
  markDirty() {
16291
15846
  this._dirty = true;
16292
15847
  }
@@ -16330,11 +15885,6 @@ var HierarchyIndex = class {
16330
15885
  getParentId(id) {
16331
15886
  return this.activities.get(id)?.parentId ?? null;
16332
15887
  }
16333
- /**
16334
- * Incremental O(1) insert for a freshly added activity (create/paste).
16335
- * The id is new, so no rebuild is needed — reparenting goes through
16336
- * `rebuild()` instead.
16337
- */
16338
15888
  addChild(parentId, id) {
16339
15889
  if (this._dirty) return;
16340
15890
  if (isRootParent(parentId)) {
@@ -16346,7 +15896,6 @@ var HierarchyIndex = class {
16346
15896
  if (arr) arr.push(id);
16347
15897
  else this._childrenByParent.set(key, [id]);
16348
15898
  }
16349
- /** Full rebuild from the activity store. */
16350
15899
  rebuild() {
16351
15900
  this._childrenByParent.clear();
16352
15901
  this._roots = [];
@@ -16379,12 +15928,29 @@ var HierarchyIndex = class {
16379
15928
  var ViewStateStore = class {
16380
15929
  checkedSet = /* @__PURE__ */ new Set();
16381
15930
  hiddenSet = /* @__PURE__ */ new Set();
15931
+ activeFilter = null;
15932
+ activeOrder = null;
16382
15933
  isChecked(activityId) {
16383
15934
  return this.checkedSet.has(activityId);
16384
15935
  }
16385
15936
  isVisible(activityId) {
16386
15937
  return !this.hiddenSet.has(activityId);
16387
15938
  }
15939
+ hiddenIds() {
15940
+ return [...this.hiddenSet];
15941
+ }
15942
+ getActiveFilter() {
15943
+ return this.activeFilter;
15944
+ }
15945
+ setActiveFilter(nextFilter) {
15946
+ this.activeFilter = nextFilter;
15947
+ }
15948
+ getActiveOrder() {
15949
+ return this.activeOrder;
15950
+ }
15951
+ setActiveOrder(nextOrder) {
15952
+ this.activeOrder = nextOrder;
15953
+ }
16388
15954
  checkedIds() {
16389
15955
  return [...this.checkedSet];
16390
15956
  }
@@ -16410,58 +15976,49 @@ var ViewStateStore = class {
16410
15976
  hydrate(seed2) {
16411
15977
  this.checkedSet = new Set(seed2.checkedIds ?? []);
16412
15978
  this.hiddenSet = new Set(seed2.hiddenIds ?? []);
15979
+ this.activeFilter = null;
15980
+ this.activeOrder = null;
16413
15981
  }
16414
15982
  snapshot() {
16415
15983
  return {
16416
15984
  checked: new Set(this.checkedSet),
16417
- hidden: new Set(this.hiddenSet)
15985
+ hidden: new Set(this.hiddenSet),
15986
+ activeFilter: this.activeFilter,
15987
+ activeOrder: this.activeOrder
16418
15988
  };
16419
15989
  }
16420
15990
  restore(snapshot) {
16421
15991
  this.checkedSet = new Set(snapshot.checked);
16422
15992
  this.hiddenSet = new Set(snapshot.hidden);
15993
+ this.activeFilter = snapshot.activeFilter;
15994
+ this.activeOrder = snapshot.activeOrder;
16423
15995
  }
16424
15996
  };
16425
15997
 
16426
15998
  // src/internal/state/schedule-state.ts
16427
15999
  var ScheduleState = class {
16428
- // Private so every mutation routes through setActivityField/addActivity/…
16429
- // (the only path that feeds the write-capture → ChangeSet). External readers
16430
- // use the AutoSchedulerPort read methods (getActivity / getAllActivities / …).
16431
16000
  _activities = /* @__PURE__ */ new Map();
16432
- // Transient gesture state: the start_date an activity had at its last
16433
- // duration edit / drag. Read only by the no-op constraint revert to decide
16434
- // whether a soft constraint repositioned the activity. Never persisted,
16435
- // never in the ChangeSet — not domain data on CoreActivity.
16436
16001
  _lastStartDate = /* @__PURE__ */ new Map();
16437
- // Transient gesture state: what a leaf looked like right before it gained its
16438
- // first child and became a summary. Read by the demotion to give the activity
16439
- // its own values back instead of the aggregate its children left behind. Not
16440
- // persisted and not in the ChangeSet: it only makes sense inside the session
16441
- // that performed the promotion. Kept (not consumed) so undo/redo of a
16442
- // demotion restores identically every time.
16443
16002
  _promotionSnapshot = /* @__PURE__ */ new Map();
16444
16003
  _links = /* @__PURE__ */ new Map();
16445
16004
  _outgoing = /* @__PURE__ */ new Map();
16446
16005
  _incoming = /* @__PURE__ */ new Map();
16447
- // Parent → children index. Assigned in the constructor (needs the
16448
- // activities Map reference). See `HierarchyIndex`.
16449
16006
  _hierarchy;
16007
+ _buildOrderComparator;
16450
16008
  _cache = {
16451
16009
  ids: null,
16452
- visualOrderIds: null
16010
+ visualOrderIds: null,
16011
+ orderComparator: null
16453
16012
  };
16454
- // Per-dispatch write journal. See `WriteCapture` / `ActivityWriteCapture`.
16455
16013
  _writeCapture = new WriteCapture();
16456
16014
  _viewState = new ViewStateStore();
16457
16015
  _viewStateBefore = null;
16458
16016
  _lastStartDateBefore = null;
16459
16017
  _promotionSnapshotBefore = null;
16460
- // Calendar arithmetic + in-dispatch memoization. Assigned in the
16461
- // constructor once the calendar reader is built. See `CalendarCalculator`.
16462
16018
  _calendar;
16463
16019
  _flags;
16464
- constructor(snapshot) {
16020
+ constructor(snapshot, buildOrderComparator = () => null) {
16021
+ this._buildOrderComparator = buildOrderComparator;
16465
16022
  for (const activity of snapshot.activities) {
16466
16023
  this._activities.set(activity.id, activity);
16467
16024
  }
@@ -16476,22 +16033,12 @@ var ScheduleState = class {
16476
16033
  this._hierarchy = new HierarchyIndex(this._activities);
16477
16034
  this._hierarchy.rebuild();
16478
16035
  }
16479
- // -- AutoSchedulerPort: reads ------------------------------------------------
16480
- /**
16481
- * Materializes every alive activity. O(N) allocation.
16482
- * AVOID per-frame / per-dispatch consumers — prefer `forEachActivity` /
16483
- * `getAllIds` when only ids or fast field reads are needed.
16484
- */
16485
16036
  getAllActivities() {
16486
16037
  return Array.from(this._activities.values());
16487
16038
  }
16488
16039
  getAllLinks() {
16489
16040
  return Array.from(this._links.values());
16490
16041
  }
16491
- /**
16492
- * Read-only snapshot of every alive activity id. Cached and invalidated
16493
- * lazily on structural mutations (add/remove/parent change).
16494
- */
16495
16042
  getAllIds() {
16496
16043
  if (this._cache.ids) return this._cache.ids;
16497
16044
  this._cache.ids = Array.from(this._activities.keys());
@@ -16500,14 +16047,6 @@ var ScheduleState = class {
16500
16047
  activityCount() {
16501
16048
  return this._activities.size;
16502
16049
  }
16503
- /**
16504
- * Every alive activity id in canonical DFS visual order (pre-order from
16505
- * roots, siblings by `correlative_id` ASC — `iterateInVisualOrder`).
16506
- * Cached like `getAllIds`; invalidated on add/remove, on `parent` /
16507
- * `correlative_id` writes, and by `recomputeCorrelativeIds` (the only
16508
- * order chokepoint, which mutates `correlative_id` directly on the
16509
- * snapshots without going through `setActivityField`).
16510
- */
16511
16050
  getVisualOrderIds() {
16512
16051
  if (this._cache.visualOrderIds) return this._cache.visualOrderIds;
16513
16052
  this._cache.visualOrderIds = iterateInVisualOrder(this).map(
@@ -16515,14 +16054,9 @@ var ScheduleState = class {
16515
16054
  );
16516
16055
  return this._cache.visualOrderIds;
16517
16056
  }
16518
- /** Drops the memoized visual order. See `getVisualOrderIds`. */
16519
16057
  invalidateVisualOrderIds() {
16520
16058
  this._cache.visualOrderIds = null;
16521
16059
  }
16522
- /**
16523
- * Iterates every alive activity without materializing intermediate arrays.
16524
- * Use in hot paths that today call `getAllActivities()` only to walk it.
16525
- */
16526
16060
  forEachActivity(visit) {
16527
16061
  for (const [id, activity] of this._activities) {
16528
16062
  visit(activity, id);
@@ -16575,6 +16109,9 @@ var ScheduleState = class {
16575
16109
  checkedIds() {
16576
16110
  return this._viewState.checkedIds();
16577
16111
  }
16112
+ hiddenIds() {
16113
+ return this._viewState.hiddenIds();
16114
+ }
16578
16115
  setChecked(activityId, nextChecked) {
16579
16116
  this._captureViewStateOnce();
16580
16117
  return this._viewState.setChecked(String(activityId), nextChecked);
@@ -16583,8 +16120,54 @@ var ScheduleState = class {
16583
16120
  this._captureViewStateOnce();
16584
16121
  return this._viewState.setVisible(String(activityId), nextVisible);
16585
16122
  }
16123
+ getActiveFilter() {
16124
+ return this._viewState.getActiveFilter();
16125
+ }
16126
+ setActiveFilter(nextFilter) {
16127
+ this._captureViewStateOnce();
16128
+ this._viewState.setActiveFilter(nextFilter);
16129
+ }
16130
+ getActiveOrder() {
16131
+ return this._viewState.getActiveOrder();
16132
+ }
16133
+ setActiveOrder(nextOrder) {
16134
+ this._captureViewStateOnce();
16135
+ this._viewState.setActiveOrder(nextOrder);
16136
+ this.invalidateDerivedOrder();
16137
+ }
16138
+ /**
16139
+ * Rebuild-on-demand, memoized: at most one build per invalidation, never one
16140
+ * per comparison. getChildrenInVisualOrder asks for this once and then sorts a
16141
+ * whole sibling group with it, and collectBranchOrder walks every branch, so a
16142
+ * build per read would be thousands per dispatch.
16143
+ *
16144
+ * The factory reads hoursPerDay and the collation locale at build time, so a
16145
+ * rebuilt comparator always reflects the current context — that is what keeps
16146
+ * ordering and filtering from seeing two different hoursPerDay.
16147
+ */
16148
+ getOrderComparator() {
16149
+ const activeOrder = this._viewState.getActiveOrder();
16150
+ if (activeOrder === null) {
16151
+ this._cache.orderComparator = null;
16152
+ return null;
16153
+ }
16154
+ if (this._cache.orderComparator) return this._cache.orderComparator;
16155
+ this._cache.orderComparator = this._buildOrderComparator(activeOrder);
16156
+ return this._cache.orderComparator;
16157
+ }
16158
+ /**
16159
+ * Both order caches, always together. The comparator decides the sequence, so
16160
+ * a rebuilt comparator with a surviving sequence would paint the old order.
16161
+ * invalidateVisualOrderIds stays separate on purpose: a structural change
16162
+ * moves rows without touching the rules, so the comparator is still valid.
16163
+ */
16164
+ invalidateDerivedOrder() {
16165
+ this._cache.orderComparator = null;
16166
+ this._cache.visualOrderIds = null;
16167
+ }
16586
16168
  hydrateViewState(seed2) {
16587
16169
  this._viewState.hydrate(seed2);
16170
+ this.invalidateDerivedOrder();
16588
16171
  }
16589
16172
  _captureViewStateOnce() {
16590
16173
  if (this._writeCapture.peek() === null) return;
@@ -16598,7 +16181,6 @@ var ScheduleState = class {
16598
16181
  getIncomingLinkIds(activityId) {
16599
16182
  return this._incoming.get(String(activityId)) ?? EMPTY_LINK_IDS;
16600
16183
  }
16601
- // -- AutoSchedulerPort: hierarchy --------------------------------------------
16602
16184
  getChildren(parentId) {
16603
16185
  return this._hierarchy.getChildren(parentId);
16604
16186
  }
@@ -16614,7 +16196,6 @@ var ScheduleState = class {
16614
16196
  getRootIds() {
16615
16197
  return this._hierarchy.getRootIds();
16616
16198
  }
16617
- // -- AutoSchedulerPort: calendar (snapshot-aware, M-F 08-16 UTC fallback) ---
16618
16199
  getClosestWorkTime(params) {
16619
16200
  return this._calendar.getClosestWorkTime(params);
16620
16201
  }
@@ -16624,66 +16205,44 @@ var ScheduleState = class {
16624
16205
  calculateDuration(params) {
16625
16206
  return this._calendar.calculateDuration(params);
16626
16207
  }
16627
- /**
16628
- * Clears the in-dispatch calendar API memoization. Call at the start of
16629
- * every scheduler run (calendars are immutable within a dispatch but may
16630
- * change across dispatches).
16631
- */
16632
16208
  clearCalendarCache() {
16633
16209
  this._calendar.clearCache();
16634
16210
  }
16635
- // Calendar resolver exposed for external consumers (initial-passes'
16636
- // expected_progress, adjust-link-lag, pipeline-context). The single owner is
16637
- // `_calendar`; this getter just delegates.
16638
16211
  get calendarReader() {
16639
16212
  return this._calendar.reader;
16640
16213
  }
16641
- // -- AutoSchedulerPort: mutations --------------------------------------------
16642
16214
  batchUpdate(runMutations) {
16643
16215
  runMutations();
16644
16216
  }
16645
- /**
16646
- * Part of the `AutoSchedulerPort` port (live caller: `applyResults`). No-op
16647
- * here because activities mutate in place via `getLiveActivity`; only a
16648
- * DHTMLX-backed adapter needs this to trigger a re-render.
16649
- */
16650
16217
  updateActivity(_id) {
16651
16218
  }
16652
16219
  getLiveActivity(activityId) {
16653
16220
  return this.getActivity(activityId);
16654
16221
  }
16655
- // -- AutoSchedulerPort: flags / config ---------------------------------------
16656
16222
  getFlags() {
16657
16223
  return {
16658
16224
  ...this._flags,
16659
16225
  allCheckedTaskIds: this._viewState.checkedIds()
16660
16226
  };
16661
16227
  }
16662
- // Backend ships no project-level dates, so this is always null in
16663
- // production. The ALAP root-boundary branch that reads it stays dormant.
16664
16228
  getProjectEnd() {
16665
16229
  return null;
16666
16230
  }
16667
- // -- Write capture (per-dispatch journal) --------------------------------
16668
- /** Start recording every `setActivityField` write of the current dispatch. */
16669
16231
  beginWriteCapture() {
16670
16232
  this._writeCapture.begin();
16671
16233
  this._viewStateBefore = null;
16672
16234
  this._lastStartDateBefore = null;
16673
16235
  this._promotionSnapshotBefore = null;
16674
16236
  }
16675
- /** The live journal, or null when no capture is active. */
16676
16237
  peekWriteCapture() {
16677
16238
  return this._writeCapture.peek();
16678
16239
  }
16679
- /** Stop and discard the current dispatch's write journal. */
16680
16240
  endWriteCapture() {
16681
16241
  this._writeCapture.end();
16682
16242
  this._viewStateBefore = null;
16683
16243
  this._lastStartDateBefore = null;
16684
16244
  this._promotionSnapshotBefore = null;
16685
16245
  }
16686
- // -- Replay-specific mutators --------------------------------------------
16687
16246
  setActivityField(activityId, field, value) {
16688
16247
  const activity = this.getActivity(activityId);
16689
16248
  if (!activity) return;
@@ -16749,11 +16308,6 @@ var ScheduleState = class {
16749
16308
  this._writeCapture.noteLinkField(String(linkId), link);
16750
16309
  Reflect.set(link, field, value);
16751
16310
  }
16752
- /**
16753
- * Applies the backend identity returned after a successful persistence
16754
- * request. `proplannerId` is deliberately not a regular editable link field:
16755
- * it is boundary-owned identity and must never enter link-update/undo logic.
16756
- */
16757
16311
  setLinkProplannerId(linkId, proplannerId) {
16758
16312
  const link = this.getLink(linkId);
16759
16313
  if (!link) return;
@@ -16793,28 +16347,9 @@ var ScheduleState = class {
16793
16347
  this._cache.visualOrderIds = null;
16794
16348
  this._hierarchy.markDirty();
16795
16349
  }
16796
- /**
16797
- * Transactional rollback: invert every journaled mutation so the store returns
16798
- * to its pre-dispatch state. Consumed by the facade on a failed dispatch,
16799
- * BEFORE `endWriteCapture` discards the journal. Reverse-chronological replay,
16800
- * bucketed in the dependency order the red-team fixed (endpoints before links,
16801
- * re-inserts before re-adds). All writes are DIRECT (never through the
16802
- * journaling mutators) so the rollback does not re-journal itself. O(touched).
16803
- *
16804
- * NOTE: covers everything routed through setActivityField + the structural
16805
- * mutators (the whole handler phase). The autoscheduler's `applyResults` date
16806
- * writes bypass the journal and are not yet reverted here (transaction plan
16807
- * Stage 4) — a create that throws AFTER autoschedule leaves those dates, which
16808
- * is still strictly less corrupt than today's no-rollback.
16809
- */
16810
- /** Pre-sweep correlative_id of an activity the renumbering shifted. Journaled
16811
- * separately (the sweep bypasses setActivityField) so rollback can revert it. */
16812
16350
  noteCorrelativeBefore(activityId, before) {
16813
16351
  this._writeCapture.noteCorrelativeBefore(activityId, before);
16814
16352
  }
16815
- /** Pre-applyResults clone of an activity the autoscheduler will move. Journaled
16816
- * separately (applyResults bypasses setActivityField) so rollback can revert
16817
- * the scheduler's date writes. */
16818
16353
  noteScheduledBefore(activityId, current) {
16819
16354
  this._writeCapture.noteScheduledBefore(activityId, current);
16820
16355
  }
@@ -16832,6 +16367,7 @@ var ScheduleState = class {
16832
16367
  this._restoreActivityFields(before);
16833
16368
  if (this._viewStateBefore !== null) {
16834
16369
  this._viewState.restore(this._viewStateBefore);
16370
+ this.invalidateDerivedOrder();
16835
16371
  }
16836
16372
  if (this._promotionSnapshotBefore !== null) {
16837
16373
  this._promotionSnapshot = this._promotionSnapshotBefore;
@@ -16924,11 +16460,6 @@ function buildFlags(snapshot) {
16924
16460
  };
16925
16461
  }
16926
16462
 
16927
- // src/shared/clone-domain-value.ts
16928
- function cloneDomainValue(value) {
16929
- return structuredClone(value);
16930
- }
16931
-
16932
16463
  // src/init/read-api.ts
16933
16464
  function readActivity(state, id) {
16934
16465
  const activity = state.getActivity(id);
@@ -16962,7 +16493,7 @@ function readChildrenIds(state, parentId) {
16962
16493
  });
16963
16494
  return roots;
16964
16495
  }
16965
- return [...state.getChildren(key)].map(String);
16496
+ return getChildrenInVisualOrder(key, state);
16966
16497
  }
16967
16498
  function readSelectedActivityIds(state) {
16968
16499
  return state.checkedIds().map(String);
@@ -17020,9 +16551,6 @@ function computeProjectWorkHours(calendars) {
17020
16551
  // src/internal/state/pipeline-context.ts
17021
16552
  function buildPipelineContext(adapter, options) {
17022
16553
  return {
17023
- // Same work-calendar engine instance used by the mock adapter so both
17024
- // halves of the replay (auto-scheduler + column pipelines) agree on
17025
- // working-time math.
17026
16554
  calendars: adapter.calendarReader,
17027
16555
  hierarchy: createStateBackedHierarchyReader(adapter),
17028
16556
  activityReader: createStateBackedActivityReader(adapter),
@@ -17039,6 +16567,21 @@ function willRunCriticalPath(action) {
17039
16567
  }
17040
16568
 
17041
16569
  // src/dispatch/undo/undo-entry.ts
16570
+ function buildHistoryChangeSet(changes) {
16571
+ const activitiesWithoutAfter = changes.activities.map((entry) => ({
16572
+ ...entry,
16573
+ after: null
16574
+ }));
16575
+ const linksWithoutAfter = changes.links.map((entry) => ({
16576
+ ...entry,
16577
+ after: null
16578
+ }));
16579
+ return cloneDomainValue({
16580
+ ...changes,
16581
+ activities: activitiesWithoutAfter,
16582
+ links: linksWithoutAfter
16583
+ });
16584
+ }
17042
16585
  function buildUndoEntry(changeSet, beforeSnap, beforeLinks, afterSnap, afterLinks) {
17043
16586
  return { changeSet, beforeSnap, beforeLinks, afterSnap, afterLinks };
17044
16587
  }
@@ -17094,7 +16637,7 @@ function mergeCoalesced(top, next) {
17094
16637
  }
17095
16638
  function getDispatchHistoryPolicy(action) {
17096
16639
  if (action.kind === "persistence-acknowledge") return "clear-on-success";
17097
- if (action.kind === "sir-sync" || action.kind === "activity-lookahead-sync" || action.kind === "baseline-apply" || action.kind === "ponderator-criterion-set" || action.kind === "status-criteria-set") {
16640
+ 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") {
17098
16641
  return "skip";
17099
16642
  }
17100
16643
  return "record";
@@ -17336,24 +16879,20 @@ var UndoRecorder = class {
17336
16879
  redoStack = [];
17337
16880
  _lastKey = null;
17338
16881
  _lastTime = 0;
17339
- /**
17340
- * Push a forward entry; a new action invalidates the redo branch. When the
17341
- * entry coalesces with the top one (same cell key, within the time window),
17342
- * it merges into the top step instead of pushing a new one (decision #4).
17343
- */
17344
16882
  record(entry, coalesceKey = null, now = 0) {
17345
16883
  const top = this.undoStack[this.undoStack.length - 1];
17346
16884
  if (coalesceKey != null && coalesceKey === this._lastKey && now - this._lastTime <= COALESCE_WINDOW_MS && top !== void 0 && canCoalesce(top, entry)) {
17347
16885
  this.undoStack[this.undoStack.length - 1] = mergeCoalesced(top, entry);
17348
16886
  } else {
17349
16887
  this.undoStack.push(entry);
17350
- if (this.undoStack.length > this.maxDepth) this.undoStack.shift();
16888
+ if (this.undoStack.length > this.maxDepth) {
16889
+ this.undoStack.splice(0, this.undoStack.length - this.maxDepth);
16890
+ }
17351
16891
  }
17352
16892
  this._lastKey = coalesceKey;
17353
16893
  this._lastTime = now;
17354
16894
  this.redoStack.length = 0;
17355
16895
  }
17356
- /** Break the coalescing chain (called on undo/redo). */
17357
16896
  resetCoalesce() {
17358
16897
  this._lastKey = null;
17359
16898
  }
@@ -17385,13 +16924,48 @@ var UndoRecorder = class {
17385
16924
  }
17386
16925
  };
17387
16926
 
16927
+ // src/dispatch/shared/resequenced-parents.ts
16928
+ var POSITIONAL_FIELDS = ["parentId", "correlativeId"];
16929
+ function collectResequencedParents(changes, parentOf) {
16930
+ const touched = /* @__PURE__ */ new Set();
16931
+ const addParentOf = (activityId) => {
16932
+ const parentId = parentOf(activityId);
16933
+ touched.add(parentId === null ? ROOT_PARENT_ID : String(parentId));
16934
+ };
16935
+ for (const change of changes.activities) {
16936
+ const activityId = String(change.id);
16937
+ if (change.kind === "created") {
16938
+ addParentOf(activityId);
16939
+ continue;
16940
+ }
16941
+ if (change.kind === "deleted") {
16942
+ const deletedFields = change.fields;
16943
+ if (deletedFields && "parentId" in deletedFields) {
16944
+ touched.add(parentKeyOf2(deletedFields.parentId?.before));
16945
+ }
16946
+ continue;
16947
+ }
16948
+ const fields = change.fields;
16949
+ if (!fields) continue;
16950
+ const movedPositionally = POSITIONAL_FIELDS.some(
16951
+ (field) => field in fields
16952
+ );
16953
+ if (!movedPositionally) continue;
16954
+ addParentOf(activityId);
16955
+ if ("parentId" in fields) {
16956
+ touched.add(parentKeyOf2(fields.parentId?.before));
16957
+ }
16958
+ }
16959
+ return touched;
16960
+ }
16961
+ function parentKeyOf2(parentId) {
16962
+ if (parentId === null || parentId === void 0) return ROOT_PARENT_ID;
16963
+ return String(parentId);
16964
+ }
16965
+
17388
16966
  // src/init/build-state-snapshot.ts
17389
16967
  function buildStoreLink(link) {
17390
16968
  return {
17391
- // Spread first to preserve passthrough backend fields (proplannerId,
17392
- // ganttId, sectorId) through the snapshot — dropping proplannerId here was
17393
- // a bug: the core lost each link's backend id, so save dirty-detection and
17394
- // the DHTMLX adapter could not tell persisted links from new ones.
17395
16969
  ...link,
17396
16970
  id: String(link.id),
17397
16971
  source: String(link.source),
@@ -17404,11 +16978,6 @@ function serializeWorktime(worktime) {
17404
16978
  return {
17405
16979
  days: worktime.days,
17406
16980
  hours: worktime.hours,
17407
- // Preserve per-date overrides (holidays + workday shift exceptions)
17408
- // through the snapshot so the work-calendar engine sees them when
17409
- // the state hydrates. Dropping these here was the bug that made
17410
- // multi-shift / exception-day calendars snap to wrong hours after
17411
- // every edit.
17412
16981
  ...worktime.dates ? { dates: worktime.dates } : {},
17413
16982
  ...worktime.customWeeks ? { customWeeks: worktime.customWeeks } : {}
17414
16983
  };
@@ -17525,13 +17094,11 @@ var SaveTracker = class {
17525
17094
  initialized = false;
17526
17095
  linksAtLastSave = /* @__PURE__ */ new Map();
17527
17096
  activitiesAtLastSave = /* @__PURE__ */ new Map();
17528
- /** Take the initial snapshot once (after the autoscheduler settles). */
17529
17097
  init(activities, links) {
17530
17098
  this.snapshotActivities(activities);
17531
17099
  this.snapshotLinks(links);
17532
17100
  this.initialized = true;
17533
17101
  }
17534
- /** Re-snapshot activities (call after a save persists them). */
17535
17102
  snapshotActivities(activities) {
17536
17103
  this.activitiesAtLastSave.clear();
17537
17104
  for (const activity of activities) {
@@ -17542,7 +17109,6 @@ var SaveTracker = class {
17542
17109
  );
17543
17110
  }
17544
17111
  }
17545
- /** Re-snapshot links (call after a save persists them). */
17546
17112
  snapshotLinks(links) {
17547
17113
  this.linksAtLastSave.clear();
17548
17114
  for (const link of links) {
@@ -17553,7 +17119,6 @@ var SaveTracker = class {
17553
17119
  });
17554
17120
  }
17555
17121
  }
17556
- /** Persisted activities whose value changed since the last snapshot. */
17557
17122
  modifiedActivities(activities) {
17558
17123
  if (!this.initialized) return [];
17559
17124
  return activities.filter((activity) => {
@@ -17564,7 +17129,6 @@ var SaveTracker = class {
17564
17129
  return activityChangedSince(activity, saved);
17565
17130
  });
17566
17131
  }
17567
- /** Persisted links whose `lag`/`type` changed since the last snapshot. */
17568
17132
  modifiedLinks(links) {
17569
17133
  if (!this.initialized) return [];
17570
17134
  return links.filter((link) => {
@@ -17574,7 +17138,6 @@ var SaveTracker = class {
17574
17138
  return link.lag !== saved.lag || link.type !== saved.type;
17575
17139
  });
17576
17140
  }
17577
- /** Drop both mirrors (teardown). */
17578
17141
  clear() {
17579
17142
  this.linksAtLastSave.clear();
17580
17143
  this.activitiesAtLastSave.clear();
@@ -18344,35 +17907,58 @@ function cloneStats(stats) {
18344
17907
  var CustomIdTracker = class {
18345
17908
  prefixMap = /* @__PURE__ */ new Map();
18346
17909
  processedIds = /* @__PURE__ */ new Set();
18347
- _journal = null;
17910
+ _journalPrefixBefore = null;
17911
+ _journalIds = null;
18348
17912
  beginCustomIdTransaction() {
18349
- this._journal = [];
17913
+ this._journalPrefixBefore = /* @__PURE__ */ new Map();
17914
+ this._journalIds = [];
18350
17915
  }
18351
17916
  commitCustomIdTransaction() {
18352
- this._journal = null;
17917
+ this._journalPrefixBefore = null;
17918
+ this._journalIds = null;
18353
17919
  }
18354
17920
  rollbackCustomIdTransaction() {
18355
- const journal = this._journal;
18356
- if (journal === null) return;
18357
- for (const entry of [...journal].reverse()) {
18358
- const { prefix } = this.analyzeCustomId(entry.customId);
18359
- if (entry.prefixBefore === null) this.prefixMap.delete(prefix);
18360
- else this.prefixMap.set(prefix, entry.prefixBefore);
17921
+ const prefixBeforeByPrefix = this._journalPrefixBefore;
17922
+ const journaledIds = this._journalIds;
17923
+ if (prefixBeforeByPrefix === null || journaledIds === null) return;
17924
+ for (const [prefix, statsBefore] of prefixBeforeByPrefix) {
17925
+ if (statsBefore === null) this.prefixMap.delete(prefix);
17926
+ else this.prefixMap.set(prefix, statsBefore);
17927
+ }
17928
+ for (const entry of [...journaledIds].reverse()) {
18361
17929
  if (entry.hadId) this.processedIds.add(entry.customId);
18362
17930
  else this.processedIds.delete(entry.customId);
18363
17931
  }
18364
- this._journal = null;
17932
+ this._journalPrefixBefore = null;
17933
+ this._journalIds = null;
18365
17934
  }
18366
17935
  _noteCustomIdBefore(customId) {
18367
- if (this._journal === null) return;
17936
+ if (this._journalPrefixBefore === null || this._journalIds === null) {
17937
+ return;
17938
+ }
18368
17939
  const { prefix } = this.analyzeCustomId(customId);
18369
- const current = this.prefixMap.get(prefix);
18370
- this._journal.push({
17940
+ if (!this._journalPrefixBefore.has(prefix)) {
17941
+ const current = this.prefixMap.get(prefix);
17942
+ this._journalPrefixBefore.set(
17943
+ prefix,
17944
+ current ? cloneStats(current) : null
17945
+ );
17946
+ }
17947
+ this._journalIds.push({
18371
17948
  customId,
18372
- prefixBefore: current ? cloneStats(current) : null,
18373
17949
  hadId: this.processedIds.has(customId)
18374
17950
  });
18375
17951
  }
17952
+ _ensureFreshBounds(prefix) {
17953
+ const stats = this.prefixMap.get(prefix);
17954
+ if (!stats?.boundsDirty) return;
17955
+ stats.boundsDirty = false;
17956
+ const remaining = Array.from(stats.usedSuffixes);
17957
+ stats.min = minSuffixFromArray(remaining);
17958
+ stats.max = maxSuffixFromArray(remaining);
17959
+ stats.quantity = remaining.length;
17960
+ this._recalculateNext(prefix);
17961
+ }
18376
17962
  defaultPrefix;
18377
17963
  suffixIncrement;
18378
17964
  constructor(options = {}) {
@@ -18392,6 +17978,7 @@ var CustomIdTracker = class {
18392
17978
  };
18393
17979
  }
18394
17980
  _updatePrefixStats(prefix, suffix) {
17981
+ this._ensureFreshBounds(prefix);
18395
17982
  if (!this.prefixMap.has(prefix)) {
18396
17983
  this.prefixMap.set(prefix, {
18397
17984
  min: suffix,
@@ -18418,6 +18005,7 @@ var CustomIdTracker = class {
18418
18005
  stats.next = next ?? this.suffixIncrement;
18419
18006
  }
18420
18007
  getPrefixStats(prefix) {
18008
+ this._ensureFreshBounds(prefix);
18421
18009
  const stats = this.prefixMap.get(prefix);
18422
18010
  if (!stats) return null;
18423
18011
  return {
@@ -18428,6 +18016,7 @@ var CustomIdTracker = class {
18428
18016
  };
18429
18017
  }
18430
18018
  getNextSuffix(prefix) {
18019
+ this._ensureFreshBounds(prefix);
18431
18020
  const stats = this.prefixMap.get(prefix);
18432
18021
  return stats ? stats.next : this.suffixIncrement;
18433
18022
  }
@@ -18441,6 +18030,7 @@ var CustomIdTracker = class {
18441
18030
  const { prefix, suffix } = this.analyzeCustomId(customId);
18442
18031
  if (!prefix && !suffix) return { prefix, suffix };
18443
18032
  this._noteCustomIdBefore(customId);
18033
+ this._ensureFreshBounds(prefix);
18444
18034
  if (this.prefixMap.has(prefix)) {
18445
18035
  const stats = this.prefixMap.get(prefix);
18446
18036
  if (!stats.usedSuffixes.has(suffix)) {
@@ -18471,22 +18061,12 @@ var CustomIdTracker = class {
18471
18061
  this._noteCustomIdBefore(customId);
18472
18062
  const currentStats = this.prefixMap.get(prefix);
18473
18063
  if (currentStats.usedSuffixes.has(suffix)) {
18474
- const newQuantity = currentStats.quantity - 1;
18475
- if (newQuantity === 0) {
18064
+ currentStats.usedSuffixes.delete(suffix);
18065
+ currentStats.quantity -= 1;
18066
+ if (currentStats.usedSuffixes.size === 0) {
18476
18067
  this.prefixMap.delete(prefix);
18477
18068
  } else {
18478
- const newUsed = new Set(currentStats.usedSuffixes);
18479
- newUsed.delete(suffix);
18480
- const remaining = Array.from(newUsed);
18481
- if (remaining.length === 0) {
18482
- this.prefixMap.delete(prefix);
18483
- } else {
18484
- currentStats.usedSuffixes = newUsed;
18485
- currentStats.min = minSuffixFromArray(remaining);
18486
- currentStats.max = maxSuffixFromArray(remaining);
18487
- currentStats.quantity = newQuantity;
18488
- this._recalculateNext(prefix);
18489
- }
18069
+ currentStats.boundsDirty = true;
18490
18070
  }
18491
18071
  }
18492
18072
  this.processedIds.delete(customId);
@@ -18506,12 +18086,19 @@ var CustomIdTracker = class {
18506
18086
  return customId.length > MAX_CUSTOM_ID_LENGTH;
18507
18087
  }
18508
18088
  _shouldSearchForGaps(prefix) {
18089
+ this._ensureFreshBounds(prefix);
18509
18090
  if (!this.prefixMap.has(prefix)) return false;
18510
18091
  const stats = this.prefixMap.get(prefix);
18511
18092
  const nextWouldBe = `${prefix}${addToSuffix(stats.max, this.suffixIncrement)}`;
18512
18093
  return nextWouldBe.length > MAX_CUSTOM_ID_LENGTH;
18513
18094
  }
18095
+ _suffixForUnknownPrefix(prefix, baseSuffix) {
18096
+ const candidate = baseSuffix && isValidSuffix(baseSuffix) ? baseSuffix : this.suffixIncrement;
18097
+ if (`${prefix}${candidate}`.length > MAX_CUSTOM_ID_LENGTH) return null;
18098
+ return candidate;
18099
+ }
18514
18100
  _findFirstAvailableGap(prefix) {
18101
+ this._ensureFreshBounds(prefix);
18515
18102
  if (!this.prefixMap.has(prefix)) return null;
18516
18103
  const stats = this.prefixMap.get(prefix);
18517
18104
  let candidate = this.suffixIncrement;
@@ -18535,10 +18122,9 @@ var CustomIdTracker = class {
18535
18122
  return `${this.defaultPrefix}${nextSuffix}`;
18536
18123
  }
18537
18124
  getNextAvailableSuffix(prefix, baseSuffix = null) {
18125
+ this._ensureFreshBounds(prefix);
18538
18126
  if (!this.prefixMap.has(prefix)) {
18539
- const candidate2 = baseSuffix && isValidSuffix(baseSuffix) ? baseSuffix : this.suffixIncrement;
18540
- if (`${prefix}${candidate2}`.length > MAX_CUSTOM_ID_LENGTH) return null;
18541
- return candidate2;
18127
+ return this._suffixForUnknownPrefix(prefix, baseSuffix);
18542
18128
  }
18543
18129
  const stats = this.prefixMap.get(prefix);
18544
18130
  const step = this.suffixIncrement;
@@ -18579,9 +18165,6 @@ var CustomIdTracker = class {
18579
18165
  }
18580
18166
  return generatedId;
18581
18167
  }
18582
- /**
18583
- * Seed the tracker from an array of activities. Idempotent.
18584
- */
18585
18168
  populateFromActivities(activities) {
18586
18169
  if (!Array.isArray(activities)) return this;
18587
18170
  const uniqueCustomIds = [
@@ -18602,14 +18185,6 @@ var CustomIdTracker = class {
18602
18185
  getDefaults() {
18603
18186
  return { prefix: this.defaultPrefix, increment: this.suffixIncrement };
18604
18187
  }
18605
- /**
18606
- * Generates a custom ID for a new child activity.
18607
- *
18608
- * Three strategies (see `selectGenerationStrategy`):
18609
- * - parentConversion: parent has customId → release it, child uses defaults.
18610
- * - pasteReference: reference has customId → use its prefix + suffix as base.
18611
- * - noContext: no reference → use defaults.
18612
- */
18613
18188
  generateCustomIdForNewChild(params) {
18614
18189
  const { activity, useActivityCustomIdAsReference = false } = params;
18615
18190
  const customId = getCustomIdFromActivity(activity);
@@ -18623,6 +18198,7 @@ var CustomIdTracker = class {
18623
18198
  );
18624
18199
  let capturedNextSuffix = null;
18625
18200
  if (strategyKey === "parentConversion" && this.prefixMap.has(prefix)) {
18201
+ this._ensureFreshBounds(prefix);
18626
18202
  const currentMax = this.prefixMap.get(prefix).max;
18627
18203
  capturedNextSuffix = addToSuffix(currentMax, this.suffixIncrement);
18628
18204
  }
@@ -18653,11 +18229,6 @@ var CustomIdTracker = class {
18653
18229
  return noContextStrategy(this.defaultPrefix);
18654
18230
  }
18655
18231
  }
18656
- /**
18657
- * Generates customId for parent-to-child conversion after outdent demote.
18658
- * If `siblingCustomId` is provided, follows its pattern (prefix + next
18659
- * suffix). Otherwise uses defaults.
18660
- */
18661
18232
  generateCustomIdForRestoredChild(siblingCustomId = null) {
18662
18233
  if (siblingCustomId) {
18663
18234
  const trimmed = siblingCustomId.trim();
@@ -18693,11 +18264,6 @@ var CustomIdTracker = class {
18693
18264
  hasPrefix(prefix) {
18694
18265
  return this.prefixMap.has(prefix);
18695
18266
  }
18696
- /**
18697
- * O(1) check — used by inline-edit to validate "no duplicate". When
18698
- * `currentCustomId` is passed, returns false if the new value matches
18699
- * (no-op edit). Used by the dispatch's `customIdPipeline.validate`.
18700
- */
18701
18267
  isCustomIdInUse(customId, currentCustomId = null) {
18702
18268
  if (!customId || typeof customId !== "string" || !customId.trim()) {
18703
18269
  return false;
@@ -18710,6 +18276,65 @@ var CustomIdTracker = class {
18710
18276
  }
18711
18277
  };
18712
18278
 
18279
+ // src/internal/order/build-comparator.ts
18280
+ var MISSING_LAST = 1;
18281
+ var MISSING_FIRST = -1;
18282
+ function compareMissing(aMissing, bMissing) {
18283
+ if (!aMissing && !bMissing) return null;
18284
+ if (aMissing && bMissing) return 0;
18285
+ return aMissing ? MISSING_LAST : MISSING_FIRST;
18286
+ }
18287
+ function isMissing(value) {
18288
+ return value === null || value === void 0;
18289
+ }
18290
+ function enumRank(value, order) {
18291
+ const index = order.indexOf(String(value));
18292
+ return index === -1 ? order.length : index;
18293
+ }
18294
+ function compareValues(a, b, locale) {
18295
+ if (a instanceof Date && b instanceof Date) {
18296
+ return a.getTime() - b.getTime();
18297
+ }
18298
+ if (typeof a === "number" && typeof b === "number") {
18299
+ return a - b;
18300
+ }
18301
+ if (typeof a === "boolean" && typeof b === "boolean") {
18302
+ return Number(a) - Number(b);
18303
+ }
18304
+ if (Array.isArray(a) && Array.isArray(b)) {
18305
+ return a.length - b.length;
18306
+ }
18307
+ return String(a).localeCompare(String(b), locale, {
18308
+ sensitivity: "base",
18309
+ numeric: true
18310
+ });
18311
+ }
18312
+ function compareByRule(rule, context) {
18313
+ const descriptor = getFieldDescriptor(rule.field);
18314
+ if (descriptor === null) return null;
18315
+ return (a, b) => {
18316
+ const valueA = descriptor.extract(a, context);
18317
+ const valueB = descriptor.extract(b, context);
18318
+ const missing = compareMissing(isMissing(valueA), isMissing(valueB));
18319
+ if (missing !== null) return missing;
18320
+ const result = descriptor.valueKind === "enum" ? enumRank(valueA, descriptor.order) - enumRank(valueB, descriptor.order) : compareValues(valueA, valueB, context.locale);
18321
+ return rule.direction === "desc" ? -result : result;
18322
+ };
18323
+ }
18324
+ function buildComparator(order, context) {
18325
+ const comparators = order.rules.map((rule) => compareByRule(rule, context)).filter(
18326
+ (comparator) => comparator !== null
18327
+ );
18328
+ if (comparators.length === 0) return null;
18329
+ return (a, b) => {
18330
+ for (const comparator of comparators) {
18331
+ const result = comparator(a, b);
18332
+ if (result !== 0) return result;
18333
+ }
18334
+ return 0;
18335
+ };
18336
+ }
18337
+
18713
18338
  // src/internal/post-processors/demote-childless-summaries.ts
18714
18339
  function demoteChildlessSummaries(state) {
18715
18340
  const idsToDemote = [];
@@ -18864,8 +18489,6 @@ function normalizeMilestoneConstraintDatesForDisplay(state) {
18864
18489
  var SCHEDULE_CORE_STATUS = {
18865
18490
  READY: "ready",
18866
18491
  DESTROYED: "destroyed",
18867
- /** A rollback failed mid-restore — state may be inconsistent; the host must
18868
- * reload from backend. All further dispatches are refused. */
18869
18492
  POISONED: "poisoned"
18870
18493
  };
18871
18494
  function initializeCore(input) {
@@ -18892,7 +18515,8 @@ function initializeCore(input) {
18892
18515
  parsed2.calendars,
18893
18516
  baseCalendars
18894
18517
  );
18895
- const state = new ScheduleState(snapshot);
18518
+ const buildOrderComparator = (order) => buildComparator(order, buildFilterContext(sector.hoursPerDay));
18519
+ const state = new ScheduleState(snapshot, buildOrderComparator);
18896
18520
  state.hydrateViewState({ hiddenIds: parsed2.viewStateSeed.hiddenIds });
18897
18521
  const scheduler = new AutoScheduler(state, reporter);
18898
18522
  demoteChildlessSummaries(state);
@@ -18925,9 +18549,6 @@ function initializeCore(input) {
18925
18549
  sector,
18926
18550
  scheduler,
18927
18551
  skipAutoSchedule: input.skipInitialAutoSchedule === true,
18928
- // `loadNow` is rounded to end-of-local-day (legacy `calculateExpected`
18929
- // parity) — the LOAD expected_progress pass. Dispatch-time recomputes call
18930
- // `clock()` fresh, so a long-lived session tracks the real day.
18931
18552
  now: loadNow ?? void 0
18932
18553
  });
18933
18554
  return {
@@ -19043,13 +18664,18 @@ var ScheduleCore = class {
19043
18664
  this.assertReady();
19044
18665
  return readSelectedActivityIds(this.coreRuntime.state);
19045
18666
  }
19046
- /**
19047
- * Every activity id in canonical DFS visual order (pre-order from roots,
19048
- * siblings by `correlative_id` ASC) — ALL activities; filtering by
19049
- * `visible` is the consumer's job. Memoized in the state and invalidated
19050
- * on any structural mutation (add/remove/reparent/renumber), so repeated
19051
- * reads between mutations are O(1).
19052
- */
18667
+ getHiddenActivityIds() {
18668
+ this.assertReady();
18669
+ return this.coreRuntime.state.hiddenIds().map(String);
18670
+ }
18671
+ getActiveFilter() {
18672
+ this.assertReady();
18673
+ return this.coreRuntime.state.getActiveFilter();
18674
+ }
18675
+ getActiveOrder() {
18676
+ this.assertReady();
18677
+ return this.coreRuntime.state.getActiveOrder();
18678
+ }
19053
18679
  getVisualOrderIds() {
19054
18680
  this.assertReady();
19055
18681
  return [...this.coreRuntime.state.getVisualOrderIds()];
@@ -19149,7 +18775,7 @@ var ScheduleCore = class {
19149
18775
  );
19150
18776
  this._undo.record(
19151
18777
  buildUndoEntry(
19152
- result.changes,
18778
+ buildHistoryChangeSet(result.changes),
19153
18779
  result.__beforeSnap,
19154
18780
  result.__beforeLinks,
19155
18781
  created.afterSnap,
@@ -19166,19 +18792,13 @@ var ScheduleCore = class {
19166
18792
  this._saveTracker.snapshotLinks(this.getAllLinksView());
19167
18793
  this._undo.clear();
19168
18794
  }
18795
+ result = this._withReappliedViewState(action, result);
19169
18796
  if (!result.ok) return result;
19170
18797
  if (dispatchChangesSchedulingState(action) && changeSetIsSubstantive(result.changes)) {
19171
18798
  this._recordScheduleMutation(options.skipCriticalPath !== true);
19172
18799
  }
19173
- return cloneDomainValue(result);
18800
+ return toPublicDispatchResult(result);
19174
18801
  }
19175
- /**
19176
- * Starts or joins the Critical Path calculation for the current schedule
19177
- * revision. Snapshot capture and the final commit are serialized with user
19178
- * mutations, but the expensive calculation runs outside `_opQueue` against
19179
- * an isolated state. A newer revision aborts this job and makes its result
19180
- * ineligible to commit.
19181
- */
19182
18802
  recomputeCriticalPath() {
19183
18803
  const operation = this._enqueue(async () => ({
19184
18804
  job: this._startCriticalPathForCurrentRevision()
@@ -19194,6 +18814,99 @@ var ScheduleCore = class {
19194
18814
  await this.recomputeCriticalPath();
19195
18815
  }
19196
18816
  }
18817
+ _withReappliedViewState(action, result) {
18818
+ if (!result.ok || !reappliesViewState(action)) return result;
18819
+ const merged = this._reapplyViewState(result.changes);
18820
+ return merged === null ? result : { ...result, changes: merged };
18821
+ }
18822
+ /**
18823
+ * The single place the two view-state passes are chained. Dispatch, undo and
18824
+ * redo all route through here: when this existed only inside the dispatch
18825
+ * path, undo and redo reapplied the filter and forgot the order, so an edit
18826
+ * that moved a row and was then undone left the row in its new position.
18827
+ *
18828
+ * The sequence between the passes is indifferent. Filter and order are
18829
+ * orthogonal projections over the same tree — the filter decides which rows
18830
+ * exist on screen and never reads the order; the order sequences every
18831
+ * sibling group from the hierarchy index and never reads visibility. Either
18832
+ * sequence produces the same ChangeSet.
18833
+ *
18834
+ * Both passes answer null while their state is inactive, so an unfiltered,
18835
+ * unsorted schedule pays two property reads.
18836
+ */
18837
+ _reapplyViewState(changes) {
18838
+ const withFilter = this._reapplyActiveFilter(changes);
18839
+ const withOrder = this._reapplyActiveOrder(withFilter ?? changes);
18840
+ const sequenced = this._emitTouchedBranchOrder(
18841
+ withOrder ?? withFilter ?? changes
18842
+ );
18843
+ return sequenced ?? withOrder ?? withFilter;
18844
+ }
18845
+ /**
18846
+ * Emits `order` for the branches this mutation resequenced, when no user order
18847
+ * is active.
18848
+ *
18849
+ * The contract is that `order` reports a CHANGED SEQUENCE, not the presence of
18850
+ * a sort. Tying emission to the cause instead of the effect is what produced
18851
+ * the undo bug and, later, the reparent ones: without an active order a move,
18852
+ * an indent, an outdent or the undo of any of them rearranged rows and said
18853
+ * nothing, so an incremental consumer kept the old sequence. The undo of a
18854
+ * reparent was the worst of them — it carried neither `order` nor a single
18855
+ * correlativeId, so the position was not recoverable by any consumer.
18856
+ *
18857
+ * The touched branches are derived from the ChangeSet rather than accumulated
18858
+ * in the state: an entity whose parentId or correlativeId moved, plus the
18859
+ * parents of created and deleted rows, is exactly the set of branches whose
18860
+ * sequence can differ. That keeps this linear in the blast radius, adds
18861
+ * nothing to the write path, and cannot leak across dispatches.
18862
+ */
18863
+ _emitTouchedBranchOrder(changes) {
18864
+ const adapter = this.coreRuntime.state;
18865
+ if (adapter.getActiveOrder() !== null) return null;
18866
+ const touched = collectResequencedParents(
18867
+ changes,
18868
+ (activityId) => adapter.getParentId(activityId)
18869
+ );
18870
+ if (touched.size === 0) return null;
18871
+ const order = [...touched].map((parentId) => ({
18872
+ parentId,
18873
+ childIds: getChildrenInVisualOrder(parentId, adapter)
18874
+ })).filter((branch) => branch.childIds.length > 1);
18875
+ if (order.length === 0) return null;
18876
+ return { ...changes, order };
18877
+ }
18878
+ /**
18879
+ * Re-sequences the grid after any mutation that could have changed a value the
18880
+ * active order sorts by. Ordering is a view over the data, so an edit that
18881
+ * moves a row past its sibling must move the row, exactly as the filter makes
18882
+ * a no-longer-matching row disappear.
18883
+ *
18884
+ * Production only re-sorts after a bar drag; diverging from that is a
18885
+ * deliberate product decision, not an oversight.
18886
+ */
18887
+ _reapplyActiveOrder(changes) {
18888
+ const adapter = this.coreRuntime.state;
18889
+ if (adapter.getActiveOrder() === null) return null;
18890
+ adapter.invalidateDerivedOrder();
18891
+ return { ...changes, order: collectBranchOrder(adapter) };
18892
+ }
18893
+ _reapplyActiveFilter(changes) {
18894
+ const filter = this.coreRuntime.state.getActiveFilter();
18895
+ if (filter === null) return null;
18896
+ const adapter = this.coreRuntime.state;
18897
+ const visibleIds = evaluateVisibleIds({
18898
+ activities: adapter.getAllActivities(),
18899
+ parentOf: (activityId) => adapter.getParentId(activityId),
18900
+ filter,
18901
+ context: buildFilterContext(this.coreRuntime.sector.hoursPerDay)
18902
+ });
18903
+ const viewState = applyVisibleSet(adapter, visibleIds);
18904
+ if (viewState.length === 0) return null;
18905
+ return {
18906
+ ...changes,
18907
+ viewState: [...changes.viewState ?? [], ...viewState]
18908
+ };
18909
+ }
19197
18910
  _recordScheduleMutation(criticalPathIsFresh) {
19198
18911
  this._scheduleRevision++;
19199
18912
  if (this._activeCriticalPath) {
@@ -19244,7 +18957,7 @@ var ScheduleCore = class {
19244
18957
  for (const [activityId, fields] of fieldsByActivity) {
19245
18958
  this.coreRuntime.state.setActivityFields(activityId, fields);
19246
18959
  }
19247
- changes = assembleChangeSet(this.coreRuntime.state, {
18960
+ changes = await assembleChangeSet(this.coreRuntime.state, {
19248
18961
  source: { kind: "init" },
19249
18962
  beforeSnap: /* @__PURE__ */ new Map(),
19250
18963
  touchedIds: [],
@@ -19271,7 +18984,6 @@ var ScheduleCore = class {
19271
18984
  void promise.then(clearIfActive, clearIfActive);
19272
18985
  return promise;
19273
18986
  }
19274
- // bridge-load artifact: emits HOURS (no duration/lag diff anyway; bridge applies verbatim).
19275
18987
  async _runCriticalPathAndCapture() {
19276
18988
  if (this._status === SCHEDULE_CORE_STATUS.DESTROYED) {
19277
18989
  return {
@@ -19292,7 +19004,7 @@ var ScheduleCore = class {
19292
19004
  this.coreRuntime.state,
19293
19005
  this.coreRuntime.sector.hoursPerDay
19294
19006
  );
19295
- changes = assembleChangeSet(this.coreRuntime.state, {
19007
+ changes = await assembleChangeSet(this.coreRuntime.state, {
19296
19008
  source: { kind: "init" },
19297
19009
  beforeSnap: /* @__PURE__ */ new Map(),
19298
19010
  touchedIds: [],
@@ -19305,11 +19017,6 @@ var ScheduleCore = class {
19305
19017
  }
19306
19018
  return { changes };
19307
19019
  }
19308
- /**
19309
- * Undo/Redo restores the user's historical mutation while retaining current
19310
- * non-historical truth (for example a refreshed baseline). Re-derive every
19311
- * value that depends on both so the restored model is immediately coherent.
19312
- */
19313
19020
  _recomputeAfterHistoryRestore() {
19314
19021
  const state = this.coreRuntime.state;
19315
19022
  recomputeAllProgressRollup(state);
@@ -19345,7 +19052,12 @@ var ScheduleCore = class {
19345
19052
  if (needsResync(entry)) this._resyncCustomIdTrackerFromModel();
19346
19053
  this._undo.pushRedo(entry);
19347
19054
  this._undo.resetCoalesce();
19348
- return buildInverseChangeSet(this.coreRuntime.state, entry, "before");
19055
+ const changes = buildInverseChangeSet(
19056
+ this.coreRuntime.state,
19057
+ entry,
19058
+ "before"
19059
+ );
19060
+ return this._reapplyViewState(changes) ?? changes;
19349
19061
  });
19350
19062
  void operation.then(
19351
19063
  (changes) => {
@@ -19373,7 +19085,12 @@ var ScheduleCore = class {
19373
19085
  if (needsResync(entry)) this._resyncCustomIdTrackerFromModel();
19374
19086
  this._undo.pushUndo(entry);
19375
19087
  this._undo.resetCoalesce();
19376
- return buildInverseChangeSet(this.coreRuntime.state, entry, "after");
19088
+ const changes = buildInverseChangeSet(
19089
+ this.coreRuntime.state,
19090
+ entry,
19091
+ "after"
19092
+ );
19093
+ return this._reapplyViewState(changes) ?? changes;
19377
19094
  });
19378
19095
  void operation.then(
19379
19096
  (changes) => {
@@ -19396,11 +19113,6 @@ var ScheduleCore = class {
19396
19113
  canRedo() {
19397
19114
  return this._undo.canRedo();
19398
19115
  }
19399
- /**
19400
- * Establishes a new persistence boundary without mutating schedule state.
19401
- * Completed saves call this synchronously so neither prior undo entries nor
19402
- * their redo branch can cross the persisted boundary.
19403
- */
19404
19116
  clearHistory() {
19405
19117
  this._undo.clear();
19406
19118
  }
@@ -19435,13 +19147,6 @@ var ScheduleCore = class {
19435
19147
  );
19436
19148
  }
19437
19149
  }
19438
- /**
19439
- * Revert the current dispatch's mutations from the write-capture journal. If
19440
- * the restore ITSELF throws, the state may be a third, partially-inverted
19441
- * state — worse than either endpoint — so poison the core: refuse all further
19442
- * dispatches and surface the fault so the host reloads from backend. A failed
19443
- * rollback is never swallowed.
19444
- */
19445
19150
  _rollback() {
19446
19151
  try {
19447
19152
  this.coreRuntime.state.restoreFromCapture();
@@ -19456,6 +19161,14 @@ var ScheduleCore = class {
19456
19161
  }
19457
19162
  }
19458
19163
  };
19164
+ function toPublicDispatchResult(result) {
19165
+ const {
19166
+ __beforeSnap: droppedSnapshots,
19167
+ __beforeLinks: droppedLinks,
19168
+ ...publicResult
19169
+ } = result;
19170
+ return publicResult;
19171
+ }
19459
19172
 
19460
19173
  // src/boundary/save/link-changes.ts
19461
19174
  function checkNoUpdatedLinks(baseline, current) {
@@ -19510,6 +19223,8 @@ var DISPATCH_ACTION_KIND = {
19510
19223
  SELECTION_TOGGLE: "selection-toggle",
19511
19224
  SELECTION_REPLACE: "selection-replace",
19512
19225
  VISIBILITY_SET: "visibility-set",
19226
+ FILTER_SET: "filter-set",
19227
+ SORT_SET: "sort-set",
19513
19228
  SIR_SYNC: "sir-sync",
19514
19229
  ACTIVITY_LOOKAHEAD_SYNC: "activity-lookahead-sync"
19515
19230
  };
@@ -19535,6 +19250,8 @@ var KIND_CATALOG_COVERS_UNION = {
19535
19250
  [DISPATCH_ACTION_KIND.SELECTION_TOGGLE]: true,
19536
19251
  [DISPATCH_ACTION_KIND.SELECTION_REPLACE]: true,
19537
19252
  [DISPATCH_ACTION_KIND.VISIBILITY_SET]: true,
19253
+ [DISPATCH_ACTION_KIND.FILTER_SET]: true,
19254
+ [DISPATCH_ACTION_KIND.SORT_SET]: true,
19538
19255
  [DISPATCH_ACTION_KIND.SIR_SYNC]: true,
19539
19256
  [DISPATCH_ACTION_KIND.ACTIVITY_LOOKAHEAD_SYNC]: true
19540
19257
  };