@outbuild-company/schedule-core 1.6.1 → 1.6.3
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/README.md +26 -0
- package/dist/cdn/schedule-core.global.js +1 -1
- package/dist/cdn/schedule-core.global.js.map +1 -1
- package/dist/index.cjs +1733 -512
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +161 -19
- package/dist/index.d.ts +161 -19
- package/dist/index.js +1732 -513
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -210,19 +210,19 @@ function dispatchSelectionReplace(action, deps) {
|
|
|
210
210
|
}
|
|
211
211
|
|
|
212
212
|
// src/dispatch/shared/apply-visible-set.ts
|
|
213
|
-
function applyVisibleSet(adapter, visibleIds) {
|
|
213
|
+
function applyVisibleSet(adapter, visibleIds, activityIds = adapter.getAllIds()) {
|
|
214
214
|
const viewState = [];
|
|
215
|
-
|
|
215
|
+
for (const activityId of activityIds) {
|
|
216
216
|
const id = String(activityId);
|
|
217
217
|
const willBeVisible = visibleIds.has(id);
|
|
218
218
|
const before = adapter.isVisible(id);
|
|
219
|
-
if (before === willBeVisible)
|
|
219
|
+
if (before === willBeVisible) continue;
|
|
220
220
|
adapter.setVisible(id, willBeVisible);
|
|
221
221
|
viewState.push({
|
|
222
222
|
activityId: id,
|
|
223
223
|
visible: { before, after: willBeVisible }
|
|
224
224
|
});
|
|
225
|
-
}
|
|
225
|
+
}
|
|
226
226
|
return viewState;
|
|
227
227
|
}
|
|
228
228
|
|
|
@@ -496,6 +496,12 @@ function overlapsRange(activity, range) {
|
|
|
496
496
|
const windowStartsInside = windowStart >= taskStart && windowStart <= taskEnd;
|
|
497
497
|
return fullyInside || startsInside || windowStartsInside;
|
|
498
498
|
}
|
|
499
|
+
function matchesFilter(activity, filter, context) {
|
|
500
|
+
const passesCriteria = matchesCriteria(activity, filter, context);
|
|
501
|
+
const range = filter.dateRange;
|
|
502
|
+
const passesRange = range === void 0 || overlapsRange(activity, range);
|
|
503
|
+
return passesCriteria && passesRange;
|
|
504
|
+
}
|
|
499
505
|
function addAncestors(matchedId, parentOf, visibleIds) {
|
|
500
506
|
let ancestorId = parentOf(matchedId);
|
|
501
507
|
while (ancestorId !== null && !visibleIds.has(String(ancestorId))) {
|
|
@@ -505,13 +511,10 @@ function addAncestors(matchedId, parentOf, visibleIds) {
|
|
|
505
511
|
}
|
|
506
512
|
function evaluateVisibleIds(input) {
|
|
507
513
|
const { activities, parentOf, filter, context } = input;
|
|
508
|
-
const range = filter.dateRange;
|
|
509
514
|
const visibleIds = /* @__PURE__ */ new Set();
|
|
510
515
|
const matchedIds = [];
|
|
511
516
|
for (const activity of activities) {
|
|
512
|
-
|
|
513
|
-
const passesRange = range === void 0 || overlapsRange(activity, range);
|
|
514
|
-
if (passesCriteria && passesRange) {
|
|
517
|
+
if (matchesFilter(activity, filter, context)) {
|
|
515
518
|
visibleIds.add(String(activity.id));
|
|
516
519
|
matchedIds.push(activity.id);
|
|
517
520
|
}
|
|
@@ -521,6 +524,114 @@ function evaluateVisibleIds(input) {
|
|
|
521
524
|
}
|
|
522
525
|
return visibleIds;
|
|
523
526
|
}
|
|
527
|
+
function seedFilterProjection(input) {
|
|
528
|
+
const { activities, parentOf, filter, context } = input;
|
|
529
|
+
const matchedIds = /* @__PURE__ */ new Set();
|
|
530
|
+
const pinnedVisibleIds = /* @__PURE__ */ new Set();
|
|
531
|
+
const visibleReferenceCounts = /* @__PURE__ */ new Map();
|
|
532
|
+
const parentIds = /* @__PURE__ */ new Map();
|
|
533
|
+
const remainingChildren = /* @__PURE__ */ new Map();
|
|
534
|
+
for (const activity of activities) {
|
|
535
|
+
const activityId = String(activity.id);
|
|
536
|
+
const parentId = parentOf(activityId);
|
|
537
|
+
parentIds.set(activityId, parentId);
|
|
538
|
+
remainingChildren.set(activityId, remainingChildren.get(activityId) ?? 0);
|
|
539
|
+
if (parentId !== null) {
|
|
540
|
+
remainingChildren.set(
|
|
541
|
+
parentId,
|
|
542
|
+
(remainingChildren.get(parentId) ?? 0) + 1
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
const isMatch = matchesFilter(activity, filter, context);
|
|
546
|
+
const isPinned = input.pinnedVisibleIds?.has(activityId) === true;
|
|
547
|
+
visibleReferenceCounts.set(
|
|
548
|
+
activityId,
|
|
549
|
+
(isMatch ? 1 : 0) + (isPinned ? 1 : 0)
|
|
550
|
+
);
|
|
551
|
+
if (isMatch) matchedIds.add(activityId);
|
|
552
|
+
if (isPinned) pinnedVisibleIds.add(activityId);
|
|
553
|
+
}
|
|
554
|
+
return {
|
|
555
|
+
matchedIds,
|
|
556
|
+
pinnedVisibleIds,
|
|
557
|
+
visibleReferenceCounts,
|
|
558
|
+
parentIds,
|
|
559
|
+
remainingChildren
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
function propagateVisibleReferenceCounts(seed2) {
|
|
563
|
+
const { visibleReferenceCounts, parentIds, remainingChildren } = seed2;
|
|
564
|
+
const pendingIds = [];
|
|
565
|
+
for (const activityId of parentIds.keys()) {
|
|
566
|
+
if (remainingChildren.get(activityId) === 0) pendingIds.push(activityId);
|
|
567
|
+
}
|
|
568
|
+
while (pendingIds.length > 0) {
|
|
569
|
+
const activityId = pendingIds.pop();
|
|
570
|
+
if (activityId === void 0) break;
|
|
571
|
+
const parentId = parentIds.get(activityId);
|
|
572
|
+
if (parentId === null || parentId === void 0) continue;
|
|
573
|
+
const referenceCount = visibleReferenceCounts.get(activityId) ?? 0;
|
|
574
|
+
visibleReferenceCounts.set(
|
|
575
|
+
parentId,
|
|
576
|
+
(visibleReferenceCounts.get(parentId) ?? 0) + referenceCount
|
|
577
|
+
);
|
|
578
|
+
const remaining = (remainingChildren.get(parentId) ?? 1) - 1;
|
|
579
|
+
remainingChildren.set(parentId, remaining);
|
|
580
|
+
if (remaining === 0) pendingIds.push(parentId);
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
function collectVisibleIds(visibleReferenceCounts) {
|
|
584
|
+
const visibleIds = /* @__PURE__ */ new Set();
|
|
585
|
+
for (const [activityId, referenceCount] of visibleReferenceCounts) {
|
|
586
|
+
if (referenceCount > 0) visibleIds.add(activityId);
|
|
587
|
+
}
|
|
588
|
+
return visibleIds;
|
|
589
|
+
}
|
|
590
|
+
function buildFilterProjection(input) {
|
|
591
|
+
const seed2 = seedFilterProjection(input);
|
|
592
|
+
propagateVisibleReferenceCounts(seed2);
|
|
593
|
+
const visibleIds = collectVisibleIds(seed2.visibleReferenceCounts);
|
|
594
|
+
return {
|
|
595
|
+
filter: input.filter,
|
|
596
|
+
context: input.context,
|
|
597
|
+
matchedIds: seed2.matchedIds,
|
|
598
|
+
pinnedVisibleIds: seed2.pinnedVisibleIds,
|
|
599
|
+
visibleIds,
|
|
600
|
+
visibleReferenceCounts: seed2.visibleReferenceCounts
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
function updateFilterProjection(projection, activities, parentOf) {
|
|
604
|
+
const changedVisibilityIds = /* @__PURE__ */ new Set();
|
|
605
|
+
for (const activity of activities) {
|
|
606
|
+
const activityId = String(activity.id);
|
|
607
|
+
changedVisibilityIds.add(activityId);
|
|
608
|
+
const wasMatch = projection.matchedIds.has(activityId);
|
|
609
|
+
const isMatch = matchesFilter(
|
|
610
|
+
activity,
|
|
611
|
+
projection.filter,
|
|
612
|
+
projection.context
|
|
613
|
+
);
|
|
614
|
+
if (wasMatch === isMatch) continue;
|
|
615
|
+
if (isMatch) projection.matchedIds.add(activityId);
|
|
616
|
+
else projection.matchedIds.delete(activityId);
|
|
617
|
+
const referenceDelta = isMatch ? 1 : -1;
|
|
618
|
+
let currentId = activityId;
|
|
619
|
+
while (currentId !== null) {
|
|
620
|
+
const beforeCount = projection.visibleReferenceCounts.get(currentId) ?? 0;
|
|
621
|
+
const afterCount = beforeCount + referenceDelta;
|
|
622
|
+
projection.visibleReferenceCounts.set(currentId, afterCount);
|
|
623
|
+
const wasVisible = beforeCount > 0;
|
|
624
|
+
const isVisible = afterCount > 0;
|
|
625
|
+
if (wasVisible !== isVisible) {
|
|
626
|
+
changedVisibilityIds.add(currentId);
|
|
627
|
+
if (isVisible) projection.visibleIds.add(currentId);
|
|
628
|
+
else projection.visibleIds.delete(currentId);
|
|
629
|
+
}
|
|
630
|
+
currentId = parentOf(currentId);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
return changedVisibilityIds;
|
|
634
|
+
}
|
|
524
635
|
|
|
525
636
|
// src/internal/filter/context.ts
|
|
526
637
|
var COLLATION_LOCALE = "en";
|
|
@@ -581,17 +692,26 @@ function isValidDateValue(value) {
|
|
|
581
692
|
function isEmptyFilter(filter) {
|
|
582
693
|
return filter.criteria.length === 0 && filter.dateRange === void 0;
|
|
583
694
|
}
|
|
584
|
-
function
|
|
695
|
+
function resolveFilter(adapter, filter, hoursPerDay) {
|
|
585
696
|
const activities = adapter.getAllActivities();
|
|
586
697
|
if (isEmptyFilter(filter)) {
|
|
587
|
-
return
|
|
698
|
+
return {
|
|
699
|
+
visibleIds: evaluateVisibleIds({
|
|
700
|
+
activities,
|
|
701
|
+
parentOf: (activityId) => adapter.getParentId(activityId),
|
|
702
|
+
filter,
|
|
703
|
+
context: buildFilterContext(hoursPerDay)
|
|
704
|
+
}),
|
|
705
|
+
projection: null
|
|
706
|
+
};
|
|
588
707
|
}
|
|
589
|
-
|
|
708
|
+
const projection = buildFilterProjection({
|
|
590
709
|
activities,
|
|
591
710
|
parentOf: (activityId) => adapter.getParentId(activityId),
|
|
592
711
|
filter,
|
|
593
712
|
context: buildFilterContext(hoursPerDay)
|
|
594
713
|
});
|
|
714
|
+
return { visibleIds: projection.visibleIds, projection };
|
|
595
715
|
}
|
|
596
716
|
function dispatchFilterSet(action, deps) {
|
|
597
717
|
const { adapter, hoursPerDay } = deps;
|
|
@@ -605,7 +725,12 @@ function dispatchFilterSet(action, deps) {
|
|
|
605
725
|
dateRange: action.dateRange
|
|
606
726
|
};
|
|
607
727
|
adapter.setActiveFilter(isEmptyFilter(filter) ? null : filter);
|
|
608
|
-
const visibleIds =
|
|
728
|
+
const { visibleIds, projection } = resolveFilter(
|
|
729
|
+
adapter,
|
|
730
|
+
filter,
|
|
731
|
+
hoursPerDay
|
|
732
|
+
);
|
|
733
|
+
adapter.setFilterProjection(projection);
|
|
609
734
|
const viewState = applyVisibleSet(adapter, visibleIds);
|
|
610
735
|
const changes = {
|
|
611
736
|
source: action,
|
|
@@ -676,11 +801,7 @@ function visualIndexInParent(taskId, adapter) {
|
|
|
676
801
|
return siblings.findIndex((id) => String(id) === String(taskId));
|
|
677
802
|
}
|
|
678
803
|
function collectChildrenSnapshots(parentId, adapter) {
|
|
679
|
-
const
|
|
680
|
-
if (key === "0") {
|
|
681
|
-
return adapter.getAllActivities().filter((a) => a.parentId === null);
|
|
682
|
-
}
|
|
683
|
-
const childIds = adapter.getChildren(parentId);
|
|
804
|
+
const childIds = String(parentId) === ROOT_PARENT_ID ? adapter.getRootIds?.() ?? adapter.getChildren(ROOT_PARENT_ID) : adapter.getChildren(parentId);
|
|
684
805
|
const out = [];
|
|
685
806
|
for (const id of childIds) {
|
|
686
807
|
const snap = adapter.getActivity(id);
|
|
@@ -724,6 +845,14 @@ function collectBranchOrder(adapter) {
|
|
|
724
845
|
visit(ROOT_PARENT_ID);
|
|
725
846
|
return branches;
|
|
726
847
|
}
|
|
848
|
+
function collectBranchOrderForParents(adapter, parentIds) {
|
|
849
|
+
const branches = [];
|
|
850
|
+
for (const parentId of parentIds) {
|
|
851
|
+
const childIds = getChildrenInVisualOrder(parentId, adapter);
|
|
852
|
+
if (childIds.length > 1) branches.push({ parentId, childIds });
|
|
853
|
+
}
|
|
854
|
+
return branches;
|
|
855
|
+
}
|
|
727
856
|
|
|
728
857
|
// src/dispatch/order.ts
|
|
729
858
|
function validateRule(rule) {
|
|
@@ -2275,6 +2404,34 @@ function wouldIntroduceCycle(existingLinks, proposedLink) {
|
|
|
2275
2404
|
}
|
|
2276
2405
|
return hasPath(adjacency, tgt, src);
|
|
2277
2406
|
}
|
|
2407
|
+
function hasDirectedCycle(links) {
|
|
2408
|
+
const adjacency = /* @__PURE__ */ new Map();
|
|
2409
|
+
const indegrees = /* @__PURE__ */ new Map();
|
|
2410
|
+
for (const link of links) {
|
|
2411
|
+
const source = String(link.source);
|
|
2412
|
+
const target = String(link.target);
|
|
2413
|
+
const neighbors = adjacency.get(source) ?? [];
|
|
2414
|
+
neighbors.push(target);
|
|
2415
|
+
adjacency.set(source, neighbors);
|
|
2416
|
+
indegrees.set(source, indegrees.get(source) ?? 0);
|
|
2417
|
+
indegrees.set(target, (indegrees.get(target) ?? 0) + 1);
|
|
2418
|
+
}
|
|
2419
|
+
const ready = new Queue();
|
|
2420
|
+
for (const [activityId, indegree] of indegrees) {
|
|
2421
|
+
if (indegree === 0) ready.enqueue(activityId);
|
|
2422
|
+
}
|
|
2423
|
+
let visited = 0;
|
|
2424
|
+
while (!ready.isEmpty()) {
|
|
2425
|
+
const current = ready.dequeue();
|
|
2426
|
+
visited += 1;
|
|
2427
|
+
for (const neighbor of adjacency.get(current) ?? []) {
|
|
2428
|
+
const indegree = indegrees.get(neighbor) - 1;
|
|
2429
|
+
indegrees.set(neighbor, indegree);
|
|
2430
|
+
if (indegree === 0) ready.enqueue(neighbor);
|
|
2431
|
+
}
|
|
2432
|
+
}
|
|
2433
|
+
return visited !== indegrees.size;
|
|
2434
|
+
}
|
|
2278
2435
|
function hasPath(adjacency, from, to) {
|
|
2279
2436
|
if (from === to) return true;
|
|
2280
2437
|
const visited = /* @__PURE__ */ new Set([from]);
|
|
@@ -2304,6 +2461,70 @@ function applyLinkOperation(op, deps) {
|
|
|
2304
2461
|
return applyDelete(op, deps);
|
|
2305
2462
|
}
|
|
2306
2463
|
}
|
|
2464
|
+
function applyLinkCreates(links, deps) {
|
|
2465
|
+
if (links.length === 0) return { applied: true };
|
|
2466
|
+
const existingLinks = deps.port.getAllLinks();
|
|
2467
|
+
const duplicateKeys = /* @__PURE__ */ new Map();
|
|
2468
|
+
const edges = [];
|
|
2469
|
+
for (const link of existingLinks) {
|
|
2470
|
+
const key = linkKey(link);
|
|
2471
|
+
if (!duplicateKeys.has(key)) duplicateKeys.set(key, link.id);
|
|
2472
|
+
edges.push({ source: link.source, target: link.target });
|
|
2473
|
+
}
|
|
2474
|
+
const existingGraphHasCycle = hasDirectedCycle(edges);
|
|
2475
|
+
let rejected = null;
|
|
2476
|
+
for (const { operation, linkId } of links) {
|
|
2477
|
+
if (String(operation.source) === String(operation.target)) {
|
|
2478
|
+
rejected = { applied: false, rejected: "self-link" };
|
|
2479
|
+
break;
|
|
2480
|
+
}
|
|
2481
|
+
if (!deps.port.getActivity(operation.source) || !deps.port.getActivity(operation.target)) {
|
|
2482
|
+
rejected = { applied: false, rejected: "activity-missing" };
|
|
2483
|
+
break;
|
|
2484
|
+
}
|
|
2485
|
+
const key = linkKey(operation);
|
|
2486
|
+
const duplicateId = duplicateKeys.get(key);
|
|
2487
|
+
if (duplicateId !== void 0) {
|
|
2488
|
+
rejected = {
|
|
2489
|
+
applied: false,
|
|
2490
|
+
rejected: "duplicate",
|
|
2491
|
+
linkId: duplicateId
|
|
2492
|
+
};
|
|
2493
|
+
break;
|
|
2494
|
+
}
|
|
2495
|
+
duplicateKeys.set(key, linkId);
|
|
2496
|
+
if (existingGraphHasCycle && // ponytail: preserve legacy sequential semantics; optimize with dynamic
|
|
2497
|
+
// SCC reachability only if corrupt cyclic schedules become measurable.
|
|
2498
|
+
wouldIntroduceCycle(edges, {
|
|
2499
|
+
source: operation.source,
|
|
2500
|
+
target: operation.target
|
|
2501
|
+
})) {
|
|
2502
|
+
return { applied: false, rejected: "cycle" };
|
|
2503
|
+
}
|
|
2504
|
+
edges.push({ source: operation.source, target: operation.target });
|
|
2505
|
+
}
|
|
2506
|
+
if (!existingGraphHasCycle && hasDirectedCycle(edges)) {
|
|
2507
|
+
return { applied: false, rejected: "cycle" };
|
|
2508
|
+
}
|
|
2509
|
+
if (rejected) return rejected;
|
|
2510
|
+
for (const { operation, linkId } of links) {
|
|
2511
|
+
const preserved = deps.preserved?.get(linkId);
|
|
2512
|
+
deps.port.addLink({
|
|
2513
|
+
id: linkId,
|
|
2514
|
+
source: operation.source,
|
|
2515
|
+
target: operation.target,
|
|
2516
|
+
type: operation.type,
|
|
2517
|
+
lag: operation.lag,
|
|
2518
|
+
...preserved?.ganttId === void 0 ? {} : { ganttId: preserved.ganttId },
|
|
2519
|
+
...preserved?.sectorId === void 0 ? {} : { sectorId: preserved.sectorId },
|
|
2520
|
+
...preserved?.proplannerId === void 0 ? {} : { proplannerId: preserved.proplannerId }
|
|
2521
|
+
});
|
|
2522
|
+
}
|
|
2523
|
+
return { applied: true };
|
|
2524
|
+
}
|
|
2525
|
+
function linkKey(link) {
|
|
2526
|
+
return JSON.stringify([String(link.source), String(link.target), link.type]);
|
|
2527
|
+
}
|
|
2307
2528
|
function applyCreate(op, deps) {
|
|
2308
2529
|
const { port } = deps;
|
|
2309
2530
|
if (String(op.source) === String(op.target)) {
|
|
@@ -2427,14 +2648,14 @@ function diffLinks(input) {
|
|
|
2427
2648
|
unresolved.push(spec);
|
|
2428
2649
|
continue;
|
|
2429
2650
|
}
|
|
2430
|
-
const key =
|
|
2651
|
+
const key = linkKey2(source, spec.type);
|
|
2431
2652
|
if (desired.has(key)) continue;
|
|
2432
2653
|
desired.set(key, { source, type: spec.type, lag: spec.lag });
|
|
2433
2654
|
}
|
|
2434
2655
|
const currentByKey = /* @__PURE__ */ new Map();
|
|
2435
2656
|
for (const link of currentLinks) {
|
|
2436
2657
|
if (String(link.target) !== String(targetActivityId)) continue;
|
|
2437
|
-
currentByKey.set(
|
|
2658
|
+
currentByKey.set(linkKey2(link.source, link.type), link);
|
|
2438
2659
|
}
|
|
2439
2660
|
const operations = [];
|
|
2440
2661
|
for (const [key, link] of currentByKey) {
|
|
@@ -2461,7 +2682,7 @@ function diffLinks(input) {
|
|
|
2461
2682
|
}
|
|
2462
2683
|
return { operations, unresolved };
|
|
2463
2684
|
}
|
|
2464
|
-
function
|
|
2685
|
+
function linkKey2(source, type) {
|
|
2465
2686
|
return `${String(source)}::${type}`;
|
|
2466
2687
|
}
|
|
2467
2688
|
function diffOutgoingLinks(input) {
|
|
@@ -2474,14 +2695,14 @@ function diffOutgoingLinks(input) {
|
|
|
2474
2695
|
unresolved.push(spec);
|
|
2475
2696
|
continue;
|
|
2476
2697
|
}
|
|
2477
|
-
const key =
|
|
2698
|
+
const key = linkKey2(target, spec.type);
|
|
2478
2699
|
if (desired.has(key)) continue;
|
|
2479
2700
|
desired.set(key, { target, type: spec.type, lag: spec.lag });
|
|
2480
2701
|
}
|
|
2481
2702
|
const currentByKey = /* @__PURE__ */ new Map();
|
|
2482
2703
|
for (const link of currentLinks) {
|
|
2483
2704
|
if (String(link.source) !== String(sourceActivityId)) continue;
|
|
2484
|
-
currentByKey.set(
|
|
2705
|
+
currentByKey.set(linkKey2(link.target, link.type), link);
|
|
2485
2706
|
}
|
|
2486
2707
|
const operations = [];
|
|
2487
2708
|
for (const [key, link] of currentByKey) {
|
|
@@ -4202,29 +4423,6 @@ function toConstraintWarning(activityId, notification) {
|
|
|
4202
4423
|
};
|
|
4203
4424
|
}
|
|
4204
4425
|
|
|
4205
|
-
// src/constants/activity-properties.ts
|
|
4206
|
-
var ACTIVITY_PROPERTY = {
|
|
4207
|
-
PARENT: "parentId",
|
|
4208
|
-
TYPE: "type",
|
|
4209
|
-
START_DATE: "startDate",
|
|
4210
|
-
END_DATE: "endDate",
|
|
4211
|
-
CONSTRAINT_TYPE: "constraintType",
|
|
4212
|
-
CONSTRAINT_DATE: "constraintDate",
|
|
4213
|
-
AUTO_SCHEDULING: "autoScheduling",
|
|
4214
|
-
PROGRESS: "progress",
|
|
4215
|
-
COST: "cost",
|
|
4216
|
-
USED_COST: "usedCost",
|
|
4217
|
-
REAL_COST: "realCost",
|
|
4218
|
-
WORK_HOURS: "workHours",
|
|
4219
|
-
REAL_WORK_HOURS: "realWorkHours",
|
|
4220
|
-
CORRELATIVE_ID: "correlativeId",
|
|
4221
|
-
CUSTOM_ID: "customId",
|
|
4222
|
-
NEW_ACTIVITIES_ARRAY: "newActivityIds",
|
|
4223
|
-
HAS_NEW_ACTIVITIES: "hasNewActivities"};
|
|
4224
|
-
var LINK_PROPERTY = {
|
|
4225
|
-
TYPE: "type",
|
|
4226
|
-
LAG: "lag"};
|
|
4227
|
-
|
|
4228
4426
|
// src/columns/types.ts
|
|
4229
4427
|
var COLUMN_WRITABLE_FIELD_LIST = [
|
|
4230
4428
|
"name",
|
|
@@ -5548,7 +5746,7 @@ var CalculateBackwardParentsLinks = class {
|
|
|
5548
5746
|
return false;
|
|
5549
5747
|
}
|
|
5550
5748
|
return allLinksCalculations.reduce(
|
|
5551
|
-
(
|
|
5749
|
+
(min2, activity) => activity.lf < min2.lf ? activity : min2
|
|
5552
5750
|
);
|
|
5553
5751
|
}
|
|
5554
5752
|
calculateSfRestrictionDates() {
|
|
@@ -7721,13 +7919,13 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
|
|
|
7721
7919
|
getMinDateFromLinks(allLinksCalculations) {
|
|
7722
7920
|
try {
|
|
7723
7921
|
if (this.constraint === CONSTRAINT_TYPES.ALAP || this.constraint === CONSTRAINT_TYPES.ASAP) {
|
|
7724
|
-
const
|
|
7725
|
-
(
|
|
7922
|
+
const min2 = allLinksCalculations.reduce(
|
|
7923
|
+
(min3, activity) => activity.lf < min3.lf ? activity : min3
|
|
7726
7924
|
);
|
|
7727
|
-
return
|
|
7925
|
+
return min2;
|
|
7728
7926
|
}
|
|
7729
7927
|
return allLinksCalculations.reduce(
|
|
7730
|
-
(
|
|
7928
|
+
(min2, activity) => activity.ls < min2.ls ? activity : min2
|
|
7731
7929
|
);
|
|
7732
7930
|
} catch (error) {
|
|
7733
7931
|
throw new Error(
|
|
@@ -7737,7 +7935,7 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
|
|
|
7737
7935
|
}
|
|
7738
7936
|
getMinLfFromLinks(allLinksCalculations) {
|
|
7739
7937
|
return allLinksCalculations.reduce(
|
|
7740
|
-
(
|
|
7938
|
+
(min2, activity) => activity.lf < min2.lf ? activity : min2
|
|
7741
7939
|
);
|
|
7742
7940
|
}
|
|
7743
7941
|
getMinDateBasedOnConstraint(minCalculatedDateFromLinks, constraintType = this.constraint) {
|
|
@@ -8195,7 +8393,7 @@ var BackwardPath = class extends generic_calculations_default {
|
|
|
8195
8393
|
return false;
|
|
8196
8394
|
}
|
|
8197
8395
|
return allLinksCalculations.reduce(
|
|
8198
|
-
(
|
|
8396
|
+
(min2, activity) => activity.lf < min2.lf ? activity : min2
|
|
8199
8397
|
);
|
|
8200
8398
|
}
|
|
8201
8399
|
};
|
|
@@ -8794,7 +8992,7 @@ var CriticalPath = class {
|
|
|
8794
8992
|
activitiesCount: this.forwardPathCalculations?.size || 0
|
|
8795
8993
|
}
|
|
8796
8994
|
});
|
|
8797
|
-
|
|
8995
|
+
throw error;
|
|
8798
8996
|
}
|
|
8799
8997
|
}
|
|
8800
8998
|
async calculateFloatsAsync(forward, backward, isCurrent) {
|
|
@@ -8815,7 +9013,7 @@ var CriticalPath = class {
|
|
|
8815
9013
|
activitiesCount: this.forwardPathCalculations?.size || 0
|
|
8816
9014
|
}
|
|
8817
9015
|
});
|
|
8818
|
-
|
|
9016
|
+
throw error;
|
|
8819
9017
|
}
|
|
8820
9018
|
}
|
|
8821
9019
|
};
|
|
@@ -8840,16 +9038,41 @@ function constraintDateForCriticalPath(activity, state) {
|
|
|
8840
9038
|
return typedDayIsWorking ? getEffectiveConstraintDate(activity, state) : raw;
|
|
8841
9039
|
}
|
|
8842
9040
|
function toLegacyCalendar(api) {
|
|
9041
|
+
const endDateByKey = /* @__PURE__ */ new Map();
|
|
9042
|
+
const durationByKey = /* @__PURE__ */ new Map();
|
|
9043
|
+
const closestWorkTimeByKey = /* @__PURE__ */ new Map();
|
|
8843
9044
|
return {
|
|
8844
|
-
calculateEndDate: ({ start_date, duration }) =>
|
|
8845
|
-
|
|
9045
|
+
calculateEndDate: ({ start_date, duration }) => {
|
|
9046
|
+
const key = `${start_date.getTime()}|${duration}`;
|
|
9047
|
+
const cached = endDateByKey.get(key);
|
|
9048
|
+
if (cached !== void 0) return new Date(cached);
|
|
9049
|
+
const value = api.calculateEndDate(start_date, duration);
|
|
9050
|
+
endDateByKey.set(key, value.getTime());
|
|
9051
|
+
return value;
|
|
9052
|
+
},
|
|
9053
|
+
calculateDuration: ({ start_date, end_date }) => {
|
|
9054
|
+
const key = `${start_date.getTime()}|${end_date.getTime()}`;
|
|
9055
|
+
const cached = durationByKey.get(key);
|
|
9056
|
+
if (cached !== void 0) return cached;
|
|
9057
|
+
const value = api.calculateDuration(start_date, end_date);
|
|
9058
|
+
durationByKey.set(key, value);
|
|
9059
|
+
return value;
|
|
9060
|
+
},
|
|
8846
9061
|
getWorkHours: (date2) => api.getWorkHours(date2),
|
|
8847
9062
|
$gantt: {
|
|
8848
|
-
getClosestWorkTime: ({ date: date2, dir, unit }) =>
|
|
8849
|
-
|
|
8850
|
-
|
|
8851
|
-
|
|
8852
|
-
|
|
9063
|
+
getClosestWorkTime: ({ date: date2, dir, unit }) => {
|
|
9064
|
+
const resolvedUnit = unit ?? "hour";
|
|
9065
|
+
const key = `${date2.getTime()}|${dir}|${resolvedUnit}`;
|
|
9066
|
+
const cached = closestWorkTimeByKey.get(key);
|
|
9067
|
+
if (cached !== void 0) return new Date(cached);
|
|
9068
|
+
const value = api.getClosestWorkTime({
|
|
9069
|
+
date: date2,
|
|
9070
|
+
direction: dir,
|
|
9071
|
+
unit: resolvedUnit
|
|
9072
|
+
});
|
|
9073
|
+
closestWorkTimeByKey.set(key, value.getTime());
|
|
9074
|
+
return value;
|
|
9075
|
+
}
|
|
8853
9076
|
}
|
|
8854
9077
|
};
|
|
8855
9078
|
}
|
|
@@ -8929,19 +9152,19 @@ function orderByTree(leveled) {
|
|
|
8929
9152
|
return ordered;
|
|
8930
9153
|
}
|
|
8931
9154
|
function projectBounds(state) {
|
|
8932
|
-
let
|
|
8933
|
-
let
|
|
9155
|
+
let min2 = null;
|
|
9156
|
+
let max2 = null;
|
|
8934
9157
|
state.forEachActivity((activity) => {
|
|
8935
9158
|
if (activity.startDate) {
|
|
8936
9159
|
const start = activity.startDate.getTime();
|
|
8937
|
-
|
|
9160
|
+
min2 = min2 == null ? start : Math.min(min2, start);
|
|
8938
9161
|
}
|
|
8939
9162
|
if (activity.endDate) {
|
|
8940
9163
|
const end = activity.endDate.getTime();
|
|
8941
|
-
|
|
9164
|
+
max2 = max2 == null ? end : Math.max(max2, end);
|
|
8942
9165
|
}
|
|
8943
9166
|
});
|
|
8944
|
-
return { start_date: new Date(
|
|
9167
|
+
return { start_date: new Date(min2 ?? 0), end_date: new Date(max2 ?? 0) };
|
|
8945
9168
|
}
|
|
8946
9169
|
async function createGanttAdapter(state, hoursPerDay) {
|
|
8947
9170
|
const calendarCache = /* @__PURE__ */ new Map();
|
|
@@ -9008,13 +9231,27 @@ function fieldsForActivity(activityId, progress, maps) {
|
|
|
9008
9231
|
freeSlackHours: maps.freeFloat.get(activityId)?.activityFreeFloat ?? null
|
|
9009
9232
|
};
|
|
9010
9233
|
}
|
|
9234
|
+
var datesEqual = (left, right) => left === right || left !== null && right !== null && left.getTime() === right.getTime();
|
|
9235
|
+
function setCriticalPathFieldsIfChanged(state, activityId, fields) {
|
|
9236
|
+
const activity = state.getActivity(activityId);
|
|
9237
|
+
const current = activity?.criticalPath;
|
|
9238
|
+
const next = fields.criticalPath;
|
|
9239
|
+
if (activity && current && datesEqual(current.earlyStart, next.earlyStart) && datesEqual(current.earlyFinish, next.earlyFinish) && datesEqual(current.lateStart, next.lateStart) && datesEqual(current.lateFinish, next.lateFinish) && Object.is(current.totalSlackHours, next.totalSlackHours) && Object.is(activity.isCritical, fields.isCritical) && Object.is(activity.freeSlackHours, fields.freeSlackHours)) {
|
|
9240
|
+
return;
|
|
9241
|
+
}
|
|
9242
|
+
state.setActivityFields(activityId, fields);
|
|
9243
|
+
}
|
|
9011
9244
|
async function computeCriticalPathFields(state, hoursPerDay, isCurrent = () => true) {
|
|
9012
9245
|
if (!isCurrent()) return null;
|
|
9013
9246
|
const gantt = await createGanttAdapter(state, hoursPerDay);
|
|
9014
9247
|
if (!isCurrent()) return null;
|
|
9015
9248
|
const criticalPath = new legacy_default(gantt);
|
|
9016
9249
|
const calculated = await criticalPath.calculate(gantt, isCurrent);
|
|
9017
|
-
if (!calculated
|
|
9250
|
+
if (!calculated) {
|
|
9251
|
+
if (!isCurrent()) return null;
|
|
9252
|
+
throw new Error("critical path calculation aborted");
|
|
9253
|
+
}
|
|
9254
|
+
if (!isCurrent()) return null;
|
|
9018
9255
|
const maps = {
|
|
9019
9256
|
forward: criticalPath.forwardPathCalculations,
|
|
9020
9257
|
backward: criticalPath.backwardPathCalculations,
|
|
@@ -9049,11 +9286,33 @@ async function applyCriticalPath(state, hoursPerDay, isCurrent = () => true) {
|
|
|
9049
9286
|
if (!fieldsByActivity || !isCurrent()) return false;
|
|
9050
9287
|
for (const [activityId, fields] of fieldsByActivity) {
|
|
9051
9288
|
if (!isCurrent()) return false;
|
|
9052
|
-
state
|
|
9289
|
+
setCriticalPathFieldsIfChanged(state, activityId, fields);
|
|
9053
9290
|
}
|
|
9054
9291
|
return true;
|
|
9055
9292
|
}
|
|
9056
9293
|
|
|
9294
|
+
// src/constants/activity-properties.ts
|
|
9295
|
+
var ACTIVITY_PROPERTY = {
|
|
9296
|
+
PARENT: "parentId",
|
|
9297
|
+
TYPE: "type",
|
|
9298
|
+
START_DATE: "startDate",
|
|
9299
|
+
END_DATE: "endDate",
|
|
9300
|
+
CONSTRAINT_TYPE: "constraintType",
|
|
9301
|
+
CONSTRAINT_DATE: "constraintDate",
|
|
9302
|
+
PROGRESS: "progress",
|
|
9303
|
+
COST: "cost",
|
|
9304
|
+
USED_COST: "usedCost",
|
|
9305
|
+
REAL_COST: "realCost",
|
|
9306
|
+
WORK_HOURS: "workHours",
|
|
9307
|
+
REAL_WORK_HOURS: "realWorkHours",
|
|
9308
|
+
CORRELATIVE_ID: "correlativeId",
|
|
9309
|
+
CUSTOM_ID: "customId",
|
|
9310
|
+
NEW_ACTIVITIES_ARRAY: "newActivityIds",
|
|
9311
|
+
HAS_NEW_ACTIVITIES: "hasNewActivities"};
|
|
9312
|
+
var LINK_PROPERTY = {
|
|
9313
|
+
TYPE: "type",
|
|
9314
|
+
LAG: "lag"};
|
|
9315
|
+
|
|
9057
9316
|
// src/propagations/upward/real-cost.ts
|
|
9058
9317
|
function emitRealCost(state) {
|
|
9059
9318
|
const rootIds = [];
|
|
@@ -9526,6 +9785,40 @@ function buildLinkChangesForBatch(applied, beforeLinks, adapter) {
|
|
|
9526
9785
|
if (!finalLinkId) continue;
|
|
9527
9786
|
const after = adapter.getLink(finalLinkId);
|
|
9528
9787
|
if (!after) continue;
|
|
9788
|
+
const before = beforeLinks.get(finalLinkId);
|
|
9789
|
+
if (before) {
|
|
9790
|
+
const fields2 = {};
|
|
9791
|
+
if (String(before.source) !== String(after.source)) {
|
|
9792
|
+
fields2.source = {
|
|
9793
|
+
before: String(before.source),
|
|
9794
|
+
after: String(after.source)
|
|
9795
|
+
};
|
|
9796
|
+
}
|
|
9797
|
+
if (String(before.target) !== String(after.target)) {
|
|
9798
|
+
fields2.target = {
|
|
9799
|
+
before: String(before.target),
|
|
9800
|
+
after: String(after.target)
|
|
9801
|
+
};
|
|
9802
|
+
}
|
|
9803
|
+
if (before.type !== after.type) {
|
|
9804
|
+
fields2.type = { before: before.type, after: after.type };
|
|
9805
|
+
}
|
|
9806
|
+
if (Number(before.lag) !== Number(after.lag)) {
|
|
9807
|
+
fields2.lag = {
|
|
9808
|
+
before: Number(before.lag),
|
|
9809
|
+
after: Number(after.lag)
|
|
9810
|
+
};
|
|
9811
|
+
}
|
|
9812
|
+
if (Object.keys(fields2).length > 0) {
|
|
9813
|
+
out.push({
|
|
9814
|
+
id: String(finalLinkId),
|
|
9815
|
+
kind: "updated",
|
|
9816
|
+
fields: fields2,
|
|
9817
|
+
after: snapshotToLink(after)
|
|
9818
|
+
});
|
|
9819
|
+
}
|
|
9820
|
+
continue;
|
|
9821
|
+
}
|
|
9529
9822
|
out.push({
|
|
9530
9823
|
id: String(finalLinkId),
|
|
9531
9824
|
kind: "created",
|
|
@@ -9540,6 +9833,7 @@ function buildLinkChangesForBatch(applied, beforeLinks, adapter) {
|
|
|
9540
9833
|
continue;
|
|
9541
9834
|
}
|
|
9542
9835
|
if (op.kind === "delete") {
|
|
9836
|
+
if (adapter.getLink(op.linkId)) continue;
|
|
9543
9837
|
const beforeLink2 = beforeLinks.get(op.linkId);
|
|
9544
9838
|
out.push({
|
|
9545
9839
|
id: String(op.linkId),
|
|
@@ -9618,16 +9912,14 @@ async function dispatchInlineEdit(action, options, deps) {
|
|
|
9618
9912
|
const { adapter, ctx, scheduler, sector } = deps;
|
|
9619
9913
|
const pipeline = findPipelineForColumn(action.column);
|
|
9620
9914
|
if (!pipeline) {
|
|
9621
|
-
|
|
9622
|
-
|
|
9623
|
-
|
|
9915
|
+
return {
|
|
9916
|
+
ok: false,
|
|
9917
|
+
reason: REJECTION_REASON.NO_PIPELINE_FOR_COLUMN
|
|
9918
|
+
};
|
|
9624
9919
|
}
|
|
9625
|
-
if (
|
|
9920
|
+
if (action.column === COLUMN.DURATION) {
|
|
9626
9921
|
scheduler.invalidateExpandedLinksCache();
|
|
9627
9922
|
}
|
|
9628
|
-
if (action.column === ACTIVITY_PROPERTY.PARENT) {
|
|
9629
|
-
scheduler.invalidateAllCaches();
|
|
9630
|
-
}
|
|
9631
9923
|
const activitySnap = ctx.activityReader.getActivity(action.activityId);
|
|
9632
9924
|
if (!activitySnap) {
|
|
9633
9925
|
return { ok: false, reason: REJECTION_REASON.ACTIVITY_NOT_FOUND };
|
|
@@ -9758,9 +10050,6 @@ async function dispatchInlineEdit(action, options, deps) {
|
|
|
9758
10050
|
})
|
|
9759
10051
|
};
|
|
9760
10052
|
}
|
|
9761
|
-
function columnInvalidatesExpandedLinks(column) {
|
|
9762
|
-
return column === COLUMN.DURATION || column === ACTIVITY_PROPERTY.AUTO_SCHEDULING;
|
|
9763
|
-
}
|
|
9764
10053
|
|
|
9765
10054
|
// src/dispatch/handlers/link.ts
|
|
9766
10055
|
function collectBatchContext(operations, adapter) {
|
|
@@ -10270,11 +10559,24 @@ function buildNewActivity(input, adapter) {
|
|
|
10270
10559
|
startDate: rawStartDate,
|
|
10271
10560
|
endDate: rawStartDate
|
|
10272
10561
|
};
|
|
10273
|
-
|
|
10562
|
+
let startDate = overrides.startDate ? new Date(base.startDate) : adapter.getClosestWorkTime({
|
|
10274
10563
|
date: base.startDate,
|
|
10275
10564
|
dir: WORK_TIME_DIRECTION.FUTURE,
|
|
10276
10565
|
task: base
|
|
10277
10566
|
});
|
|
10567
|
+
if (!overrides.startDate && parent && isMilestoneType(parent.type)) {
|
|
10568
|
+
const inheritedDay = new Date(parent.startDate);
|
|
10569
|
+
inheritedDay.setUTCHours(0, 0, 0, 0);
|
|
10570
|
+
const snappedDay = new Date(startDate);
|
|
10571
|
+
snappedDay.setUTCHours(0, 0, 0, 0);
|
|
10572
|
+
if (snappedDay.getTime() !== inheritedDay.getTime()) {
|
|
10573
|
+
startDate = adapter.getClosestWorkTime({
|
|
10574
|
+
date: inheritedDay,
|
|
10575
|
+
dir: WORK_TIME_DIRECTION.FUTURE,
|
|
10576
|
+
task: base
|
|
10577
|
+
});
|
|
10578
|
+
}
|
|
10579
|
+
}
|
|
10278
10580
|
const endDate = adapter.calculateEndDate({
|
|
10279
10581
|
startDate,
|
|
10280
10582
|
durationHours: base.durationHours,
|
|
@@ -10376,8 +10678,8 @@ function computeInsertionCorrelativeId(adapter, parentId, afterSiblingId, before
|
|
|
10376
10678
|
}
|
|
10377
10679
|
}
|
|
10378
10680
|
if (siblings.length === 0) return isRoot ? 0 : 0;
|
|
10379
|
-
const
|
|
10380
|
-
return
|
|
10681
|
+
const max2 = Math.max(...siblings.map(readCorrelativeId));
|
|
10682
|
+
return max2 + 1;
|
|
10381
10683
|
}
|
|
10382
10684
|
var NOT_SET_SORT_VALUE2 = Number.MAX_SAFE_INTEGER;
|
|
10383
10685
|
var TEMP_CID_SENTINEL = Number.MAX_SAFE_INTEGER - 1;
|
|
@@ -10387,12 +10689,7 @@ function readCorrelativeId(activity) {
|
|
|
10387
10689
|
return Number.isFinite(n) ? n : NOT_SET_SORT_VALUE2;
|
|
10388
10690
|
}
|
|
10389
10691
|
function collectSiblings(adapter, parentKey) {
|
|
10390
|
-
|
|
10391
|
-
adapter.forEachActivity((a) => {
|
|
10392
|
-
const ap = normalizeParentKey(a.parentId);
|
|
10393
|
-
if (ap === parentKey) siblings.push(a);
|
|
10394
|
-
});
|
|
10395
|
-
return siblings;
|
|
10692
|
+
return collectChildrenSnapshots(parentKey, adapter);
|
|
10396
10693
|
}
|
|
10397
10694
|
function findFirstSelectedSibling(taskId, selected, adapter) {
|
|
10398
10695
|
let firstSelected = taskId;
|
|
@@ -10442,7 +10739,7 @@ function computeFractionalCidAtIndex(adapter, parentKey, targetIndex, excludeId)
|
|
|
10442
10739
|
// src/dispatch/handlers/activity-create.ts
|
|
10443
10740
|
async function createActivityCore(action, deps, opts = {}) {
|
|
10444
10741
|
const { adapter, scheduler, sector, calendars, activityIdGen, uidGen } = deps;
|
|
10445
|
-
scheduler.invalidateAllCaches();
|
|
10742
|
+
if (!opts.skipCacheInvalidation) scheduler.invalidateAllCaches();
|
|
10446
10743
|
const target = validateCreateTarget(action, adapter);
|
|
10447
10744
|
if (!target.ok) return target;
|
|
10448
10745
|
const { parent, anchorSiblingId, isRoot } = target;
|
|
@@ -10471,7 +10768,7 @@ async function createActivityCore(action, deps, opts = {}) {
|
|
|
10471
10768
|
newActivity.progress
|
|
10472
10769
|
);
|
|
10473
10770
|
assignCustomId(newActivity, action, deps, anchorSiblingId, parent, opts);
|
|
10474
|
-
const insertionCorrelativeId = computeInsertionCorrelativeId(
|
|
10771
|
+
const insertionCorrelativeId = opts.insertionCorrelativeId ?? computeInsertionCorrelativeId(
|
|
10475
10772
|
adapter,
|
|
10476
10773
|
isRoot ? ROOT_PARENT_ID : action.parentId,
|
|
10477
10774
|
action.afterSiblingId,
|
|
@@ -10488,9 +10785,11 @@ async function createActivityCore(action, deps, opts = {}) {
|
|
|
10488
10785
|
if (parentCustomId) {
|
|
10489
10786
|
deps.customIdTracker.releaseCustomId(parentCustomId);
|
|
10490
10787
|
}
|
|
10491
|
-
|
|
10492
|
-
|
|
10493
|
-
|
|
10788
|
+
if (!opts.skipRollupCascades) {
|
|
10789
|
+
recomputeHhCascadeForActivity(newId, adapter);
|
|
10790
|
+
recomputeUsedCostCascadeForActivity(newId, adapter);
|
|
10791
|
+
recomputeCostCascadeForActivity(newId, adapter);
|
|
10792
|
+
}
|
|
10494
10793
|
recomputeAndFoldCorrelatives(
|
|
10495
10794
|
adapter,
|
|
10496
10795
|
newId,
|
|
@@ -10662,296 +10961,62 @@ function findDefaultCalendarId(calendars) {
|
|
|
10662
10961
|
return "global";
|
|
10663
10962
|
}
|
|
10664
10963
|
|
|
10665
|
-
// src/
|
|
10666
|
-
function
|
|
10667
|
-
|
|
10668
|
-
|
|
10669
|
-
|
|
10670
|
-
|
|
10964
|
+
// src/propagations/upward/recompute-rollup-cascades.ts
|
|
10965
|
+
function recomputeRollupCascadesForParent(parentId, adapter) {
|
|
10966
|
+
recomputeHhCascadeForParent(parentId, adapter);
|
|
10967
|
+
recomputeUsedCostCascadeForParent(parentId, adapter);
|
|
10968
|
+
recomputeCostCascadeForParent(parentId, adapter);
|
|
10969
|
+
}
|
|
10970
|
+
|
|
10971
|
+
// src/propagations/shared/traversal-helpers.ts
|
|
10972
|
+
function collectDescendantIds(rootIds, adapter) {
|
|
10973
|
+
const out = /* @__PURE__ */ new Set();
|
|
10974
|
+
const stack = [];
|
|
10975
|
+
for (const id of rootIds) {
|
|
10976
|
+
const key = String(id);
|
|
10977
|
+
if (!out.has(key)) {
|
|
10978
|
+
out.add(key);
|
|
10979
|
+
stack.push(key);
|
|
10671
10980
|
}
|
|
10672
|
-
const parentId2 = sibling.parentId == null ? ROOT_PARENT_ID : String(sibling.parentId);
|
|
10673
|
-
return { ok: true, parentId: parentId2, firstAfter: destination.afterSiblingId };
|
|
10674
10981
|
}
|
|
10675
|
-
|
|
10676
|
-
|
|
10677
|
-
|
|
10678
|
-
|
|
10679
|
-
|
|
10680
|
-
|
|
10982
|
+
while (stack.length > 0) {
|
|
10983
|
+
const current = stack.pop();
|
|
10984
|
+
const children = adapter.getChildren(current);
|
|
10985
|
+
for (const childId of children) {
|
|
10986
|
+
const key = String(childId);
|
|
10987
|
+
if (!out.has(key)) {
|
|
10988
|
+
out.add(key);
|
|
10989
|
+
stack.push(key);
|
|
10990
|
+
}
|
|
10991
|
+
}
|
|
10992
|
+
}
|
|
10993
|
+
return out;
|
|
10681
10994
|
}
|
|
10682
|
-
function
|
|
10683
|
-
const
|
|
10995
|
+
function collectIncidentLinkIds(activityIds, adapter) {
|
|
10996
|
+
const out = /* @__PURE__ */ new Set();
|
|
10997
|
+
for (const activityId of activityIds) {
|
|
10998
|
+
for (const linkId of adapter.getOutgoingLinkIds(activityId)) {
|
|
10999
|
+
out.add(String(linkId));
|
|
11000
|
+
}
|
|
11001
|
+
for (const linkId of adapter.getIncomingLinkIds(activityId)) {
|
|
11002
|
+
out.add(String(linkId));
|
|
11003
|
+
}
|
|
11004
|
+
}
|
|
11005
|
+
return [...out];
|
|
11006
|
+
}
|
|
11007
|
+
|
|
11008
|
+
// src/internal/hierarchy/parent-demotion.ts
|
|
11009
|
+
function restoredPromotionFields(restore) {
|
|
11010
|
+
if (!restore) return null;
|
|
10684
11011
|
return {
|
|
10685
|
-
|
|
10686
|
-
|
|
10687
|
-
|
|
10688
|
-
|
|
10689
|
-
|
|
10690
|
-
|
|
10691
|
-
|
|
10692
|
-
|
|
10693
|
-
async function dispatchActivityPaste(action, options, deps) {
|
|
10694
|
-
const { adapter, scheduler, sector } = deps;
|
|
10695
|
-
const rootDest = resolvePasteRootDestination(action.destination, adapter);
|
|
10696
|
-
if (!rootDest.ok) return rootDest;
|
|
10697
|
-
const beforeSnap = await snapshotActivities(adapter, /* @__PURE__ */ new Set());
|
|
10698
|
-
const touched = /* @__PURE__ */ new Set();
|
|
10699
|
-
const originalToNew = /* @__PURE__ */ new Map();
|
|
10700
|
-
const createdIds = [];
|
|
10701
|
-
let prevRootId;
|
|
10702
|
-
for (const input of action.activities) {
|
|
10703
|
-
const mappedParent = originalToNew.get(input.originalParentId);
|
|
10704
|
-
let parentId;
|
|
10705
|
-
let afterSiblingId;
|
|
10706
|
-
let beforeSiblingId;
|
|
10707
|
-
if (mappedParent !== void 0) {
|
|
10708
|
-
parentId = mappedParent;
|
|
10709
|
-
} else {
|
|
10710
|
-
parentId = rootDest.parentId;
|
|
10711
|
-
if (prevRootId === void 0) {
|
|
10712
|
-
afterSiblingId = rootDest.firstAfter;
|
|
10713
|
-
beforeSiblingId = rootDest.firstBefore;
|
|
10714
|
-
} else {
|
|
10715
|
-
afterSiblingId = prevRootId;
|
|
10716
|
-
}
|
|
10717
|
-
}
|
|
10718
|
-
const core = await createActivityCore(
|
|
10719
|
-
{
|
|
10720
|
-
parentId,
|
|
10721
|
-
afterSiblingId,
|
|
10722
|
-
beforeSiblingId,
|
|
10723
|
-
...input.activityId ? { activityId: input.activityId } : {},
|
|
10724
|
-
overrides: applyPasteDomainSemantics(input.overrides),
|
|
10725
|
-
eventSource: action.eventSource
|
|
10726
|
-
},
|
|
10727
|
-
deps,
|
|
10728
|
-
{
|
|
10729
|
-
skipCorrelativeRecompute: true,
|
|
10730
|
-
skipBeforeSnap: true,
|
|
10731
|
-
customIdReferenceId: action.referenceActivityId
|
|
10732
|
-
}
|
|
10733
|
-
);
|
|
10734
|
-
if (!core.ok) return core;
|
|
10735
|
-
if (input.baselineSnapshot !== void 0) {
|
|
10736
|
-
const snapshot = input.baselineSnapshot;
|
|
10737
|
-
adapter.setActivityField(
|
|
10738
|
-
core.newId,
|
|
10739
|
-
"baselineSnapshot",
|
|
10740
|
-
snapshot ? {
|
|
10741
|
-
...snapshot,
|
|
10742
|
-
startDate: snapshot.startDate ? new Date(snapshot.startDate) : null,
|
|
10743
|
-
endDate: snapshot.endDate ? new Date(snapshot.endDate) : null
|
|
10744
|
-
} : null
|
|
10745
|
-
);
|
|
10746
|
-
}
|
|
10747
|
-
originalToNew.set(input.originalId, core.newId);
|
|
10748
|
-
createdIds.push(core.newId);
|
|
10749
|
-
if (mappedParent === void 0) prevRootId = core.newId;
|
|
10750
|
-
}
|
|
10751
|
-
const correlativeShifts = recomputeCorrelativeIds(adapter);
|
|
10752
|
-
const createdIdSet = new Set(createdIds.map(String));
|
|
10753
|
-
foldCorrelativeShifts(
|
|
10754
|
-
adapter,
|
|
10755
|
-
correlativeShifts,
|
|
10756
|
-
createdIdSet,
|
|
10757
|
-
beforeSnap,
|
|
10758
|
-
touched
|
|
10759
|
-
);
|
|
10760
|
-
for (const createdId of createdIds) touched.add(String(createdId));
|
|
10761
|
-
const appliedLinks = [];
|
|
10762
|
-
for (const link of action.links) {
|
|
10763
|
-
const newSource = originalToNew.get(link.source);
|
|
10764
|
-
const newTarget = originalToNew.get(link.target);
|
|
10765
|
-
if (newSource === void 0 || newTarget === void 0) continue;
|
|
10766
|
-
const op = {
|
|
10767
|
-
kind: "create",
|
|
10768
|
-
source: newSource,
|
|
10769
|
-
target: newTarget,
|
|
10770
|
-
type: link.type,
|
|
10771
|
-
lag: lagDaysToHours(link.lag, sector.hoursPerDay)
|
|
10772
|
-
};
|
|
10773
|
-
const res = applyLinkOperation(op, {
|
|
10774
|
-
port: adapter,
|
|
10775
|
-
newLinkId: link.linkId ? () => link.linkId : deps.linkIdGen.next
|
|
10776
|
-
});
|
|
10777
|
-
appliedLinks.push({
|
|
10778
|
-
op,
|
|
10779
|
-
finalLinkId: res.applied ? res.linkId : null,
|
|
10780
|
-
rejected: res.applied ? null : res.rejected ?? "link_op_rejected"
|
|
10781
|
-
});
|
|
10782
|
-
}
|
|
10783
|
-
const { scheduledIds } = await runPostMutation(
|
|
10784
|
-
{
|
|
10785
|
-
adapter,
|
|
10786
|
-
scheduler,
|
|
10787
|
-
sector: deps.sector,
|
|
10788
|
-
defaultBaseCalendarId: deps.defaultBaseCalendarId
|
|
10789
|
-
},
|
|
10790
|
-
{
|
|
10791
|
-
action,
|
|
10792
|
-
autoscheduleFrom: createdIds[0] ?? null,
|
|
10793
|
-
recomputeParentsFrom: createdIds,
|
|
10794
|
-
now: deps.now,
|
|
10795
|
-
options
|
|
10796
|
-
}
|
|
10797
|
-
);
|
|
10798
|
-
const linkChanges = buildLinkChangesForBatch(
|
|
10799
|
-
appliedLinks,
|
|
10800
|
-
/* @__PURE__ */ new Map(),
|
|
10801
|
-
adapter
|
|
10802
|
-
);
|
|
10803
|
-
return {
|
|
10804
|
-
ok: true,
|
|
10805
|
-
changes: await assembleChangeSet(adapter, {
|
|
10806
|
-
source: action,
|
|
10807
|
-
beforeSnap,
|
|
10808
|
-
touchedIds: touched,
|
|
10809
|
-
scheduledIds,
|
|
10810
|
-
links: linkChanges,
|
|
10811
|
-
hoursPerDay: sector.hoursPerDay
|
|
10812
|
-
})
|
|
10813
|
-
};
|
|
10814
|
-
}
|
|
10815
|
-
|
|
10816
|
-
// src/dispatch/handlers/sir-sync.ts
|
|
10817
|
-
function dispatchSirSync(action, deps) {
|
|
10818
|
-
const { adapter } = deps;
|
|
10819
|
-
const id = action.activityId;
|
|
10820
|
-
const snapshot = adapter.getActivity(id);
|
|
10821
|
-
if (!snapshot) {
|
|
10822
|
-
return { ok: false, reason: REJECTION_REASON.ACTIVITY_NOT_FOUND };
|
|
10823
|
-
}
|
|
10824
|
-
const before = snapshot.pendingRequestIds ?? [];
|
|
10825
|
-
const after = action.pendingRequests.map((r) => r.id);
|
|
10826
|
-
adapter.setActivityField(action.activityId, "pendingRequestIds", after);
|
|
10827
|
-
const change = {
|
|
10828
|
-
id,
|
|
10829
|
-
kind: "updated",
|
|
10830
|
-
fields: { pendingRequestIds: { before, after } },
|
|
10831
|
-
after: { id, pendingRequestIds: after }
|
|
10832
|
-
};
|
|
10833
|
-
return {
|
|
10834
|
-
ok: true,
|
|
10835
|
-
changes: {
|
|
10836
|
-
source: action,
|
|
10837
|
-
activities: [change],
|
|
10838
|
-
links: [],
|
|
10839
|
-
calendars: [],
|
|
10840
|
-
trackingEvents: []
|
|
10841
|
-
}
|
|
10842
|
-
};
|
|
10843
|
-
}
|
|
10844
|
-
|
|
10845
|
-
// src/dispatch/handlers/activity-lookahead-sync.ts
|
|
10846
|
-
function dispatchActivityLookaheadSync(action, deps) {
|
|
10847
|
-
const ids = [...new Set(action.activityIds.map(String))];
|
|
10848
|
-
const snapshots = ids.map((id) => deps.adapter.getActivity(id));
|
|
10849
|
-
if (snapshots.some((snapshot) => !snapshot)) {
|
|
10850
|
-
return { ok: false, reason: REJECTION_REASON.ACTIVITY_NOT_FOUND };
|
|
10851
|
-
}
|
|
10852
|
-
const activities = [];
|
|
10853
|
-
for (const [index, id] of ids.entries()) {
|
|
10854
|
-
const snapshot = snapshots[index];
|
|
10855
|
-
if (!snapshot) continue;
|
|
10856
|
-
const fields = {};
|
|
10857
|
-
if (snapshot.isLookahead !== action.isLookahead) {
|
|
10858
|
-
fields.isLookahead = {
|
|
10859
|
-
before: snapshot.isLookahead,
|
|
10860
|
-
after: action.isLookahead
|
|
10861
|
-
};
|
|
10862
|
-
deps.adapter.setActivityField(id, "isLookahead", action.isLookahead);
|
|
10863
|
-
}
|
|
10864
|
-
if (snapshot.hasLookaheadTasks !== action.hasLookaheadTasks) {
|
|
10865
|
-
fields.hasLookaheadTasks = {
|
|
10866
|
-
before: snapshot.hasLookaheadTasks,
|
|
10867
|
-
after: action.hasLookaheadTasks
|
|
10868
|
-
};
|
|
10869
|
-
deps.adapter.setActivityField(
|
|
10870
|
-
id,
|
|
10871
|
-
"hasLookaheadTasks",
|
|
10872
|
-
action.hasLookaheadTasks
|
|
10873
|
-
);
|
|
10874
|
-
}
|
|
10875
|
-
if (Object.keys(fields).length === 0) continue;
|
|
10876
|
-
activities.push({
|
|
10877
|
-
id,
|
|
10878
|
-
kind: "updated",
|
|
10879
|
-
fields,
|
|
10880
|
-
after: {
|
|
10881
|
-
...snapshot,
|
|
10882
|
-
isLookahead: action.isLookahead,
|
|
10883
|
-
hasLookaheadTasks: action.hasLookaheadTasks
|
|
10884
|
-
}
|
|
10885
|
-
});
|
|
10886
|
-
}
|
|
10887
|
-
return {
|
|
10888
|
-
ok: true,
|
|
10889
|
-
changes: {
|
|
10890
|
-
source: action,
|
|
10891
|
-
activities,
|
|
10892
|
-
links: [],
|
|
10893
|
-
calendars: [],
|
|
10894
|
-
trackingEvents: []
|
|
10895
|
-
}
|
|
10896
|
-
};
|
|
10897
|
-
}
|
|
10898
|
-
|
|
10899
|
-
// src/propagations/upward/recompute-rollup-cascades.ts
|
|
10900
|
-
function recomputeRollupCascadesForParent(parentId, adapter) {
|
|
10901
|
-
recomputeHhCascadeForParent(parentId, adapter);
|
|
10902
|
-
recomputeUsedCostCascadeForParent(parentId, adapter);
|
|
10903
|
-
recomputeCostCascadeForParent(parentId, adapter);
|
|
10904
|
-
}
|
|
10905
|
-
|
|
10906
|
-
// src/propagations/shared/traversal-helpers.ts
|
|
10907
|
-
function collectDescendantIds(rootIds, adapter) {
|
|
10908
|
-
const out = /* @__PURE__ */ new Set();
|
|
10909
|
-
const stack = [];
|
|
10910
|
-
for (const id of rootIds) {
|
|
10911
|
-
const key = String(id);
|
|
10912
|
-
if (!out.has(key)) {
|
|
10913
|
-
out.add(key);
|
|
10914
|
-
stack.push(key);
|
|
10915
|
-
}
|
|
10916
|
-
}
|
|
10917
|
-
while (stack.length > 0) {
|
|
10918
|
-
const current = stack.pop();
|
|
10919
|
-
const children = adapter.getChildren(current);
|
|
10920
|
-
for (const childId of children) {
|
|
10921
|
-
const key = String(childId);
|
|
10922
|
-
if (!out.has(key)) {
|
|
10923
|
-
out.add(key);
|
|
10924
|
-
stack.push(key);
|
|
10925
|
-
}
|
|
10926
|
-
}
|
|
10927
|
-
}
|
|
10928
|
-
return out;
|
|
10929
|
-
}
|
|
10930
|
-
function collectIncidentLinkIds(activityIds, adapter) {
|
|
10931
|
-
const out = /* @__PURE__ */ new Set();
|
|
10932
|
-
for (const activityId of activityIds) {
|
|
10933
|
-
for (const linkId of adapter.getOutgoingLinkIds(activityId)) {
|
|
10934
|
-
out.add(String(linkId));
|
|
10935
|
-
}
|
|
10936
|
-
for (const linkId of adapter.getIncomingLinkIds(activityId)) {
|
|
10937
|
-
out.add(String(linkId));
|
|
10938
|
-
}
|
|
10939
|
-
}
|
|
10940
|
-
return [...out];
|
|
10941
|
-
}
|
|
10942
|
-
|
|
10943
|
-
// src/internal/hierarchy/parent-demotion.ts
|
|
10944
|
-
function restoredPromotionFields(restore) {
|
|
10945
|
-
if (!restore) return null;
|
|
10946
|
-
return {
|
|
10947
|
-
type: restore.type,
|
|
10948
|
-
startDate: new Date(restore.startDate),
|
|
10949
|
-
endDate: new Date(restore.endDate),
|
|
10950
|
-
durationHours: restore.durationHours,
|
|
10951
|
-
expectedProgressBaseline: restore.expectedProgressBaseline,
|
|
10952
|
-
constraintType: restore.constraintType,
|
|
10953
|
-
constraintDate: restore.constraintDate ? new Date(restore.constraintDate) : null,
|
|
10954
|
-
progress: restore.progress
|
|
11012
|
+
type: restore.type,
|
|
11013
|
+
startDate: new Date(restore.startDate),
|
|
11014
|
+
endDate: new Date(restore.endDate),
|
|
11015
|
+
durationHours: restore.durationHours,
|
|
11016
|
+
expectedProgressBaseline: restore.expectedProgressBaseline,
|
|
11017
|
+
constraintType: restore.constraintType,
|
|
11018
|
+
constraintDate: restore.constraintDate ? new Date(restore.constraintDate) : null,
|
|
11019
|
+
progress: restore.progress
|
|
10955
11020
|
};
|
|
10956
11021
|
}
|
|
10957
11022
|
function canonicalEndDateField(parent, durationHours, computeEndDate) {
|
|
@@ -11194,7 +11259,647 @@ function buildLinkDeletions(beforeLinks) {
|
|
|
11194
11259
|
after: null
|
|
11195
11260
|
});
|
|
11196
11261
|
}
|
|
11197
|
-
return out;
|
|
11262
|
+
return out;
|
|
11263
|
+
}
|
|
11264
|
+
|
|
11265
|
+
// src/dispatch/handlers/activity-batch.ts
|
|
11266
|
+
async function dispatchActivityBatch(action, options, deps) {
|
|
11267
|
+
const validationError = validateBatch(action, deps);
|
|
11268
|
+
if (validationError) return { ok: false, reason: validationError };
|
|
11269
|
+
const plan = buildBatchPlan(action, deps);
|
|
11270
|
+
if (!plan.ok) return plan;
|
|
11271
|
+
const existingActivityIds = action.mode === "replace" ? new Set(deps.adapter.getAllIds().map((id) => String(id))) : /* @__PURE__ */ new Set();
|
|
11272
|
+
const beforeSnap = action.mode === "replace" ? await snapshotActivities(deps.adapter, existingActivityIds) : /* @__PURE__ */ new Map();
|
|
11273
|
+
const beforeLinks = action.mode === "replace" ? snapshotAllLinks(deps) : /* @__PURE__ */ new Map();
|
|
11274
|
+
const viewState = action.mode === "replace" ? captureDeletedViewState(deps.adapter, existingActivityIds) : [];
|
|
11275
|
+
deps.scheduler.invalidateAllCaches();
|
|
11276
|
+
const appliedLinks = [];
|
|
11277
|
+
if (action.mode === "replace") {
|
|
11278
|
+
for (const linkId of beforeLinks.keys()) {
|
|
11279
|
+
const deleted = applyLinkOperation(
|
|
11280
|
+
{ kind: "delete", linkId },
|
|
11281
|
+
{ port: deps.adapter }
|
|
11282
|
+
);
|
|
11283
|
+
if (!deleted.applied) {
|
|
11284
|
+
return {
|
|
11285
|
+
ok: false,
|
|
11286
|
+
reason: deleted.rejected ?? REJECTION_REASON.INVALID
|
|
11287
|
+
};
|
|
11288
|
+
}
|
|
11289
|
+
appliedLinks.push({
|
|
11290
|
+
op: { kind: "delete", linkId },
|
|
11291
|
+
finalLinkId: linkId,
|
|
11292
|
+
rejected: null
|
|
11293
|
+
});
|
|
11294
|
+
}
|
|
11295
|
+
for (const activityId of existingActivityIds) {
|
|
11296
|
+
const customId = deps.adapter.getActivity(activityId)?.customId;
|
|
11297
|
+
if (typeof customId === "string" && customId.length > 0) {
|
|
11298
|
+
deps.customIdTracker.releaseCustomId(customId);
|
|
11299
|
+
}
|
|
11300
|
+
deps.adapter.removeActivity(activityId);
|
|
11301
|
+
}
|
|
11302
|
+
}
|
|
11303
|
+
const created = await createPlannedActivities(action, plan.plan.items, deps);
|
|
11304
|
+
if (!created.ok) return created;
|
|
11305
|
+
const correlativeShifts = isSimpleRootAppend(action) ? [] : recomputeCorrelativeIds(deps.adapter);
|
|
11306
|
+
const createdIdSet = new Set(
|
|
11307
|
+
plan.plan.items.map((item) => String(item.activityId))
|
|
11308
|
+
);
|
|
11309
|
+
const existingCorrelativeShifts = correlativeShifts.filter(
|
|
11310
|
+
(shift) => !createdIdSet.has(shift.activityId)
|
|
11311
|
+
);
|
|
11312
|
+
const touchedIds = action.mode === "replace" ? new Set(existingActivityIds) : /* @__PURE__ */ new Set();
|
|
11313
|
+
foldCorrelativeShifts(
|
|
11314
|
+
deps.adapter,
|
|
11315
|
+
correlativeShifts,
|
|
11316
|
+
createdIdSet,
|
|
11317
|
+
beforeSnap,
|
|
11318
|
+
touchedIds
|
|
11319
|
+
);
|
|
11320
|
+
for (const item of plan.plan.items) {
|
|
11321
|
+
touchedIds.add(String(item.activityId));
|
|
11322
|
+
}
|
|
11323
|
+
const linkCreates = plan.plan.links.map((link) => ({
|
|
11324
|
+
operation: {
|
|
11325
|
+
kind: "create",
|
|
11326
|
+
source: link.source,
|
|
11327
|
+
target: link.target,
|
|
11328
|
+
type: link.type,
|
|
11329
|
+
lag: options.inputUnit === "hours" ? link.lag : lagDaysToHours(link.lag, deps.sector.hoursPerDay)
|
|
11330
|
+
},
|
|
11331
|
+
linkId: link.linkId
|
|
11332
|
+
}));
|
|
11333
|
+
const createdLinks = applyLinkCreates(linkCreates, {
|
|
11334
|
+
port: deps.adapter,
|
|
11335
|
+
preserved: beforeLinks
|
|
11336
|
+
});
|
|
11337
|
+
if (!createdLinks.applied) {
|
|
11338
|
+
return {
|
|
11339
|
+
ok: false,
|
|
11340
|
+
reason: createdLinks.rejected ?? REJECTION_REASON.INVALID
|
|
11341
|
+
};
|
|
11342
|
+
}
|
|
11343
|
+
for (const { operation, linkId } of linkCreates) {
|
|
11344
|
+
appliedLinks.push({
|
|
11345
|
+
op: operation,
|
|
11346
|
+
finalLinkId: linkId,
|
|
11347
|
+
rejected: null
|
|
11348
|
+
});
|
|
11349
|
+
}
|
|
11350
|
+
const createdIds = plan.plan.items.map((item) => item.activityId);
|
|
11351
|
+
const { scheduledIds } = await runPostMutation(
|
|
11352
|
+
{
|
|
11353
|
+
adapter: deps.adapter,
|
|
11354
|
+
scheduler: deps.scheduler,
|
|
11355
|
+
sector: deps.sector,
|
|
11356
|
+
defaultBaseCalendarId: deps.defaultBaseCalendarId
|
|
11357
|
+
},
|
|
11358
|
+
{
|
|
11359
|
+
action,
|
|
11360
|
+
autoscheduleFrom: action.items.length > 0 || action.links.length > 0 ? "roots" : null,
|
|
11361
|
+
recomputeParentsFrom: createdIds,
|
|
11362
|
+
now: deps.now,
|
|
11363
|
+
options
|
|
11364
|
+
}
|
|
11365
|
+
);
|
|
11366
|
+
const changes = await assembleChangeSet(deps.adapter, {
|
|
11367
|
+
source: action,
|
|
11368
|
+
beforeSnap,
|
|
11369
|
+
touchedIds,
|
|
11370
|
+
scheduledIds,
|
|
11371
|
+
links: buildLinkChangesForBatch(appliedLinks, beforeLinks, deps.adapter),
|
|
11372
|
+
hoursPerDay: deps.sector.hoursPerDay,
|
|
11373
|
+
correlativeShifts: existingCorrelativeShifts,
|
|
11374
|
+
...action.mode === "replace" ? { sirDetection: "after-diff" } : {}
|
|
11375
|
+
});
|
|
11376
|
+
return {
|
|
11377
|
+
ok: true,
|
|
11378
|
+
changes: viewState.length > 0 ? { ...changes, viewState } : changes,
|
|
11379
|
+
...action.mode === "replace" ? {
|
|
11380
|
+
__beforeSnap: beforeSnap,
|
|
11381
|
+
__beforeLinks: stringKeyedLinks(beforeLinks)
|
|
11382
|
+
} : {}
|
|
11383
|
+
};
|
|
11384
|
+
}
|
|
11385
|
+
function validateBatch(action, deps) {
|
|
11386
|
+
if (action.mode !== "append" && action.mode !== "replace") {
|
|
11387
|
+
return REJECTION_REASON.INVALID;
|
|
11388
|
+
}
|
|
11389
|
+
const batchIds = /* @__PURE__ */ new Set();
|
|
11390
|
+
const explicitActivityIds = /* @__PURE__ */ new Set();
|
|
11391
|
+
for (const item of action.items) {
|
|
11392
|
+
if (item.batchId.length === 0 || batchIds.has(item.batchId)) {
|
|
11393
|
+
return REJECTION_REASON.INVALID;
|
|
11394
|
+
}
|
|
11395
|
+
batchIds.add(item.batchId);
|
|
11396
|
+
if (item.index !== void 0 && (!Number.isInteger(item.index) || item.index < 0)) {
|
|
11397
|
+
return REJECTION_REASON.INVALID;
|
|
11398
|
+
}
|
|
11399
|
+
if (item.activityId !== void 0) {
|
|
11400
|
+
const activityId = String(item.activityId);
|
|
11401
|
+
if (activityId.length === 0 || activityId === "0" || explicitActivityIds.has(activityId) || action.mode === "append" && deps.adapter.getActivity(activityId) !== null) {
|
|
11402
|
+
return REJECTION_REASON.INVALID;
|
|
11403
|
+
}
|
|
11404
|
+
explicitActivityIds.add(activityId);
|
|
11405
|
+
}
|
|
11406
|
+
}
|
|
11407
|
+
for (const item of action.items) {
|
|
11408
|
+
if (!validReference(item.parent, true, action.mode, batchIds, deps)) {
|
|
11409
|
+
return REJECTION_REASON.PARENT_NOT_FOUND;
|
|
11410
|
+
}
|
|
11411
|
+
}
|
|
11412
|
+
if (hasParentCycle(action.items)) return REJECTION_REASON.INVALID;
|
|
11413
|
+
const explicitLinkIds = /* @__PURE__ */ new Set();
|
|
11414
|
+
for (const link of action.links) {
|
|
11415
|
+
if (!Object.values(LINK_TYPE).includes(link.type) || !Number.isFinite(link.lag)) {
|
|
11416
|
+
return !Number.isFinite(link.lag) ? REJECTION_REASON.INVALID_LINK_LAG : REJECTION_REASON.INVALID_LINK_TYPE;
|
|
11417
|
+
}
|
|
11418
|
+
if (!validReference(link.source, false, action.mode, batchIds, deps) || !validReference(link.target, false, action.mode, batchIds, deps)) {
|
|
11419
|
+
return REJECTION_REASON.ACTIVITY_NOT_FOUND;
|
|
11420
|
+
}
|
|
11421
|
+
if (link.linkId !== void 0) {
|
|
11422
|
+
const linkId = String(link.linkId);
|
|
11423
|
+
if (linkId.length === 0 || explicitLinkIds.has(linkId) || action.mode === "append" && deps.adapter.getLink(linkId) !== null) {
|
|
11424
|
+
return REJECTION_REASON.INVALID;
|
|
11425
|
+
}
|
|
11426
|
+
explicitLinkIds.add(linkId);
|
|
11427
|
+
}
|
|
11428
|
+
}
|
|
11429
|
+
return null;
|
|
11430
|
+
}
|
|
11431
|
+
function validReference(reference, allowRoot, mode, batchIds, deps) {
|
|
11432
|
+
if (typeof reference === "string") {
|
|
11433
|
+
if (reference === "0") return allowRoot;
|
|
11434
|
+
return mode === "append" && deps.adapter.getActivity(String(reference)) !== null;
|
|
11435
|
+
}
|
|
11436
|
+
return reference !== null && reference.batchId.length > 0 && batchIds.has(reference.batchId);
|
|
11437
|
+
}
|
|
11438
|
+
function hasParentCycle(items) {
|
|
11439
|
+
const parentByBatchId = /* @__PURE__ */ new Map();
|
|
11440
|
+
for (const item of items) {
|
|
11441
|
+
if (typeof item.parent !== "string") {
|
|
11442
|
+
parentByBatchId.set(item.batchId, item.parent.batchId);
|
|
11443
|
+
}
|
|
11444
|
+
}
|
|
11445
|
+
const verified = /* @__PURE__ */ new Set();
|
|
11446
|
+
for (const item of items) {
|
|
11447
|
+
const path = /* @__PURE__ */ new Set();
|
|
11448
|
+
let current = item.batchId;
|
|
11449
|
+
while (current !== void 0 && !verified.has(current)) {
|
|
11450
|
+
if (path.has(current)) return true;
|
|
11451
|
+
path.add(current);
|
|
11452
|
+
current = parentByBatchId.get(current);
|
|
11453
|
+
}
|
|
11454
|
+
for (const batchId of path) verified.add(batchId);
|
|
11455
|
+
}
|
|
11456
|
+
return false;
|
|
11457
|
+
}
|
|
11458
|
+
function buildBatchPlan(action, deps) {
|
|
11459
|
+
for (const item of action.items) {
|
|
11460
|
+
if (item.activityId !== void 0) {
|
|
11461
|
+
deps.activityIdGen.bump(item.activityId);
|
|
11462
|
+
}
|
|
11463
|
+
}
|
|
11464
|
+
const activityIdsByBatchId = /* @__PURE__ */ new Map();
|
|
11465
|
+
for (const item of action.items) {
|
|
11466
|
+
activityIdsByBatchId.set(
|
|
11467
|
+
item.batchId,
|
|
11468
|
+
item.activityId ?? deps.activityIdGen.next()
|
|
11469
|
+
);
|
|
11470
|
+
}
|
|
11471
|
+
for (const link of action.links) {
|
|
11472
|
+
if (link.linkId !== void 0) deps.linkIdGen.bump(link.linkId);
|
|
11473
|
+
}
|
|
11474
|
+
const linkIds = action.links.map(
|
|
11475
|
+
(link) => link.linkId ?? deps.linkIdGen.next()
|
|
11476
|
+
);
|
|
11477
|
+
const insertionCorrelativeIds = planInsertionCorrelatives(
|
|
11478
|
+
action,
|
|
11479
|
+
activityIdsByBatchId,
|
|
11480
|
+
deps
|
|
11481
|
+
);
|
|
11482
|
+
const items = [];
|
|
11483
|
+
for (const item of action.items) {
|
|
11484
|
+
const activityId = activityIdsByBatchId.get(item.batchId);
|
|
11485
|
+
const insertionCorrelativeId = insertionCorrelativeIds.get(item.batchId);
|
|
11486
|
+
if (activityId === void 0 || insertionCorrelativeId === void 0) {
|
|
11487
|
+
return { ok: false, reason: REJECTION_REASON.INVALID };
|
|
11488
|
+
}
|
|
11489
|
+
const parentBatchId = typeof item.parent === "string" ? null : item.parent.batchId;
|
|
11490
|
+
const parentId = typeof item.parent === "string" ? item.parent : activityIdsByBatchId.get(item.parent.batchId);
|
|
11491
|
+
if (parentId === void 0) {
|
|
11492
|
+
return { ok: false, reason: REJECTION_REASON.PARENT_NOT_FOUND };
|
|
11493
|
+
}
|
|
11494
|
+
items.push({
|
|
11495
|
+
input: item,
|
|
11496
|
+
activityId,
|
|
11497
|
+
parentId,
|
|
11498
|
+
parentBatchId,
|
|
11499
|
+
insertionCorrelativeId
|
|
11500
|
+
});
|
|
11501
|
+
}
|
|
11502
|
+
const links = [];
|
|
11503
|
+
for (const [index, link] of action.links.entries()) {
|
|
11504
|
+
const source = resolveActivityReference(link.source, activityIdsByBatchId);
|
|
11505
|
+
const target = resolveActivityReference(link.target, activityIdsByBatchId);
|
|
11506
|
+
const linkId = linkIds[index];
|
|
11507
|
+
if (source === null || target === null || linkId === void 0) {
|
|
11508
|
+
return { ok: false, reason: REJECTION_REASON.ACTIVITY_NOT_FOUND };
|
|
11509
|
+
}
|
|
11510
|
+
links.push({
|
|
11511
|
+
source,
|
|
11512
|
+
target,
|
|
11513
|
+
type: link.type,
|
|
11514
|
+
lag: link.lag,
|
|
11515
|
+
linkId
|
|
11516
|
+
});
|
|
11517
|
+
}
|
|
11518
|
+
return { ok: true, plan: { items, links } };
|
|
11519
|
+
}
|
|
11520
|
+
function planInsertionCorrelatives(action, activityIdsByBatchId, deps) {
|
|
11521
|
+
if (isSimpleRootAppend(action)) {
|
|
11522
|
+
const firstCorrelativeId = deps.adapter.activityCount();
|
|
11523
|
+
return new Map(
|
|
11524
|
+
action.items.map((item, index) => [
|
|
11525
|
+
item.batchId,
|
|
11526
|
+
firstCorrelativeId + index
|
|
11527
|
+
])
|
|
11528
|
+
);
|
|
11529
|
+
}
|
|
11530
|
+
const newIds = new Set(
|
|
11531
|
+
Array.from(activityIdsByBatchId.values(), (id) => String(id))
|
|
11532
|
+
);
|
|
11533
|
+
const plansByParent = /* @__PURE__ */ new Map();
|
|
11534
|
+
for (const item of action.items) {
|
|
11535
|
+
const activityId = activityIdsByBatchId.get(item.batchId);
|
|
11536
|
+
if (activityId === void 0) continue;
|
|
11537
|
+
const parentId = typeof item.parent === "string" ? item.parent : activityIdsByBatchId.get(item.parent.batchId);
|
|
11538
|
+
if (parentId === void 0) continue;
|
|
11539
|
+
const parentKey = String(parentId);
|
|
11540
|
+
let plan = plansByParent.get(parentKey);
|
|
11541
|
+
if (!plan) {
|
|
11542
|
+
const existing = action.mode === "replace" || typeof item.parent !== "string" && activityIdsByBatchId.has(item.parent.batchId) ? [] : collectSiblings(deps.adapter, parentKey).sort((left, right) => {
|
|
11543
|
+
const diff = readCorrelativeId(left) - readCorrelativeId(right);
|
|
11544
|
+
return diff || String(left.id).localeCompare(String(right.id));
|
|
11545
|
+
}).map((activity) => String(activity.id));
|
|
11546
|
+
plan = { existing, newIdsByTarget: /* @__PURE__ */ new Map() };
|
|
11547
|
+
plansByParent.set(parentKey, plan);
|
|
11548
|
+
}
|
|
11549
|
+
const target = item.index === void 0 ? plan.existing.length : Math.min(item.index, plan.existing.length);
|
|
11550
|
+
const idsAtTarget = plan.newIdsByTarget.get(target) ?? [];
|
|
11551
|
+
idsAtTarget.push(String(activityId));
|
|
11552
|
+
plan.newIdsByTarget.set(target, idsAtTarget);
|
|
11553
|
+
}
|
|
11554
|
+
const result = /* @__PURE__ */ new Map();
|
|
11555
|
+
const batchIdByActivityId = new Map(
|
|
11556
|
+
Array.from(activityIdsByBatchId, ([batchId, activityId]) => [
|
|
11557
|
+
String(activityId),
|
|
11558
|
+
batchId
|
|
11559
|
+
])
|
|
11560
|
+
);
|
|
11561
|
+
for (const plan of plansByParent.values()) {
|
|
11562
|
+
const order = [];
|
|
11563
|
+
for (let target = 0; target <= plan.existing.length; target += 1) {
|
|
11564
|
+
for (const newId of plan.newIdsByTarget.get(target) ?? []) {
|
|
11565
|
+
order.push(newId);
|
|
11566
|
+
}
|
|
11567
|
+
const existingId = plan.existing[target];
|
|
11568
|
+
if (existingId !== void 0) order.push(existingId);
|
|
11569
|
+
}
|
|
11570
|
+
let index = 0;
|
|
11571
|
+
while (index < order.length) {
|
|
11572
|
+
if (!newIds.has(order[index])) {
|
|
11573
|
+
index += 1;
|
|
11574
|
+
continue;
|
|
11575
|
+
}
|
|
11576
|
+
const start = index;
|
|
11577
|
+
while (index < order.length && newIds.has(order[index])) index += 1;
|
|
11578
|
+
const count = index - start;
|
|
11579
|
+
const left = start > 0 ? activityCorrelative(order[start - 1], deps) : null;
|
|
11580
|
+
const right = index < order.length ? activityCorrelative(order[index], deps) : null;
|
|
11581
|
+
for (let offset = 0; offset < count; offset += 1) {
|
|
11582
|
+
const id = order[start + offset];
|
|
11583
|
+
const batchId = batchIdByActivityId.get(id);
|
|
11584
|
+
if (batchId === void 0) continue;
|
|
11585
|
+
result.set(
|
|
11586
|
+
batchId,
|
|
11587
|
+
interpolateCorrelative(left, right, offset + 1, count)
|
|
11588
|
+
);
|
|
11589
|
+
}
|
|
11590
|
+
}
|
|
11591
|
+
}
|
|
11592
|
+
return result;
|
|
11593
|
+
}
|
|
11594
|
+
function isSimpleRootAppend(action) {
|
|
11595
|
+
return action.mode === "append" && action.items.every(
|
|
11596
|
+
(item) => item.parent === "0" && item.index === void 0
|
|
11597
|
+
);
|
|
11598
|
+
}
|
|
11599
|
+
function activityCorrelative(activityId, deps) {
|
|
11600
|
+
const activity = deps.adapter.getActivity(activityId);
|
|
11601
|
+
return activity ? readCorrelativeId(activity) : 0;
|
|
11602
|
+
}
|
|
11603
|
+
function interpolateCorrelative(left, right, position, count) {
|
|
11604
|
+
if (left !== null && right !== null && right > left) {
|
|
11605
|
+
return left + (right - left) * position / (count + 1);
|
|
11606
|
+
}
|
|
11607
|
+
if (left !== null) return left + position;
|
|
11608
|
+
if (right !== null) return right - (count - position + 1);
|
|
11609
|
+
return position - 1;
|
|
11610
|
+
}
|
|
11611
|
+
async function createPlannedActivities(action, plannedItems, deps) {
|
|
11612
|
+
const childrenByParent = /* @__PURE__ */ new Map();
|
|
11613
|
+
const ready = [];
|
|
11614
|
+
for (const item of plannedItems) {
|
|
11615
|
+
if (item.parentBatchId === null) {
|
|
11616
|
+
ready.push(item);
|
|
11617
|
+
continue;
|
|
11618
|
+
}
|
|
11619
|
+
const children = childrenByParent.get(item.parentBatchId) ?? [];
|
|
11620
|
+
children.push(item);
|
|
11621
|
+
childrenByParent.set(item.parentBatchId, children);
|
|
11622
|
+
}
|
|
11623
|
+
for (let index = 0; index < ready.length; index += 1) {
|
|
11624
|
+
const item = ready[index];
|
|
11625
|
+
const core = await createActivityCore(
|
|
11626
|
+
{
|
|
11627
|
+
parentId: item.parentId,
|
|
11628
|
+
activityId: item.activityId,
|
|
11629
|
+
...item.input.overrides === void 0 ? {} : { overrides: item.input.overrides },
|
|
11630
|
+
...action.eventSource === void 0 ? {} : { eventSource: action.eventSource }
|
|
11631
|
+
},
|
|
11632
|
+
deps,
|
|
11633
|
+
{
|
|
11634
|
+
skipCorrelativeRecompute: true,
|
|
11635
|
+
skipBeforeSnap: true,
|
|
11636
|
+
skipCacheInvalidation: true,
|
|
11637
|
+
skipRollupCascades: true,
|
|
11638
|
+
insertionCorrelativeId: item.insertionCorrelativeId
|
|
11639
|
+
}
|
|
11640
|
+
);
|
|
11641
|
+
if (!core.ok) return core;
|
|
11642
|
+
for (const child of childrenByParent.get(item.input.batchId) ?? []) {
|
|
11643
|
+
ready.push(child);
|
|
11644
|
+
}
|
|
11645
|
+
}
|
|
11646
|
+
if (ready.length !== plannedItems.length) {
|
|
11647
|
+
return { ok: false, reason: REJECTION_REASON.INVALID };
|
|
11648
|
+
}
|
|
11649
|
+
const recomputedParents = /* @__PURE__ */ new Set();
|
|
11650
|
+
for (let index = ready.length - 1; index >= 0; index -= 1) {
|
|
11651
|
+
const parentId = ready[index].parentId;
|
|
11652
|
+
if (parentId === "0" || recomputedParents.has(String(parentId))) continue;
|
|
11653
|
+
recomputedParents.add(String(parentId));
|
|
11654
|
+
recomputeRollupCascadesForParent(parentId, deps.adapter);
|
|
11655
|
+
}
|
|
11656
|
+
return { ok: true };
|
|
11657
|
+
}
|
|
11658
|
+
function resolveActivityReference(reference, activityIdsByBatchId) {
|
|
11659
|
+
if (typeof reference === "string") return reference;
|
|
11660
|
+
return activityIdsByBatchId.get(reference.batchId) ?? null;
|
|
11661
|
+
}
|
|
11662
|
+
function snapshotAllLinks(deps) {
|
|
11663
|
+
return new Map(
|
|
11664
|
+
deps.adapter.getAllLinks().map((link) => [String(link.id), { ...link }])
|
|
11665
|
+
);
|
|
11666
|
+
}
|
|
11667
|
+
function stringKeyedLinks(links) {
|
|
11668
|
+
return new Map(Array.from(links, ([linkId, link]) => [String(linkId), link]));
|
|
11669
|
+
}
|
|
11670
|
+
|
|
11671
|
+
// src/dispatch/handlers/activity-paste.ts
|
|
11672
|
+
function resolvePasteRootDestination(destination, adapter) {
|
|
11673
|
+
if ("afterSiblingId" in destination) {
|
|
11674
|
+
const sibling = adapter.getActivity(destination.afterSiblingId);
|
|
11675
|
+
if (!sibling) {
|
|
11676
|
+
return { ok: false, reason: REJECTION_REASON.ANCHOR_SIBLING_NOT_FOUND };
|
|
11677
|
+
}
|
|
11678
|
+
const parentId2 = sibling.parentId == null ? ROOT_PARENT_ID : String(sibling.parentId);
|
|
11679
|
+
return { ok: true, parentId: parentId2, firstAfter: destination.afterSiblingId };
|
|
11680
|
+
}
|
|
11681
|
+
const parentId = destination.parentId;
|
|
11682
|
+
const siblings = collectSiblings(adapter, parentId).sort(
|
|
11683
|
+
(a, b) => readCorrelativeId(a) - readCorrelativeId(b)
|
|
11684
|
+
);
|
|
11685
|
+
const before = siblings[destination.index]?.id;
|
|
11686
|
+
return { ok: true, parentId, firstBefore: before };
|
|
11687
|
+
}
|
|
11688
|
+
function applyPasteDomainSemantics(overrides) {
|
|
11689
|
+
const { customId: _customId, ...content } = overrides;
|
|
11690
|
+
return {
|
|
11691
|
+
...content,
|
|
11692
|
+
progress: 0,
|
|
11693
|
+
ponderator: 0,
|
|
11694
|
+
usedCost: 0,
|
|
11695
|
+
workHours: 0,
|
|
11696
|
+
isLookahead: false
|
|
11697
|
+
};
|
|
11698
|
+
}
|
|
11699
|
+
async function dispatchActivityPaste(action, options, deps) {
|
|
11700
|
+
const { adapter, scheduler, sector } = deps;
|
|
11701
|
+
const rootDest = resolvePasteRootDestination(action.destination, adapter);
|
|
11702
|
+
if (!rootDest.ok) return rootDest;
|
|
11703
|
+
const beforeSnap = await snapshotActivities(adapter, /* @__PURE__ */ new Set());
|
|
11704
|
+
const touched = /* @__PURE__ */ new Set();
|
|
11705
|
+
const originalToNew = /* @__PURE__ */ new Map();
|
|
11706
|
+
const createdIds = [];
|
|
11707
|
+
let prevRootId;
|
|
11708
|
+
for (const input of action.activities) {
|
|
11709
|
+
const mappedParent = originalToNew.get(input.originalParentId);
|
|
11710
|
+
let parentId;
|
|
11711
|
+
let afterSiblingId;
|
|
11712
|
+
let beforeSiblingId;
|
|
11713
|
+
if (mappedParent !== void 0) {
|
|
11714
|
+
parentId = mappedParent;
|
|
11715
|
+
} else {
|
|
11716
|
+
parentId = rootDest.parentId;
|
|
11717
|
+
if (prevRootId === void 0) {
|
|
11718
|
+
afterSiblingId = rootDest.firstAfter;
|
|
11719
|
+
beforeSiblingId = rootDest.firstBefore;
|
|
11720
|
+
} else {
|
|
11721
|
+
afterSiblingId = prevRootId;
|
|
11722
|
+
}
|
|
11723
|
+
}
|
|
11724
|
+
const core = await createActivityCore(
|
|
11725
|
+
{
|
|
11726
|
+
parentId,
|
|
11727
|
+
afterSiblingId,
|
|
11728
|
+
beforeSiblingId,
|
|
11729
|
+
...input.activityId ? { activityId: input.activityId } : {},
|
|
11730
|
+
overrides: applyPasteDomainSemantics(input.overrides),
|
|
11731
|
+
eventSource: action.eventSource
|
|
11732
|
+
},
|
|
11733
|
+
deps,
|
|
11734
|
+
{
|
|
11735
|
+
skipCorrelativeRecompute: true,
|
|
11736
|
+
skipBeforeSnap: true,
|
|
11737
|
+
customIdReferenceId: action.referenceActivityId
|
|
11738
|
+
}
|
|
11739
|
+
);
|
|
11740
|
+
if (!core.ok) return core;
|
|
11741
|
+
if (input.baselineSnapshot !== void 0) {
|
|
11742
|
+
const snapshot = input.baselineSnapshot;
|
|
11743
|
+
adapter.setActivityField(
|
|
11744
|
+
core.newId,
|
|
11745
|
+
"baselineSnapshot",
|
|
11746
|
+
snapshot ? {
|
|
11747
|
+
...snapshot,
|
|
11748
|
+
startDate: snapshot.startDate ? new Date(snapshot.startDate) : null,
|
|
11749
|
+
endDate: snapshot.endDate ? new Date(snapshot.endDate) : null
|
|
11750
|
+
} : null
|
|
11751
|
+
);
|
|
11752
|
+
}
|
|
11753
|
+
originalToNew.set(input.originalId, core.newId);
|
|
11754
|
+
createdIds.push(core.newId);
|
|
11755
|
+
if (mappedParent === void 0) prevRootId = core.newId;
|
|
11756
|
+
}
|
|
11757
|
+
const correlativeShifts = recomputeCorrelativeIds(adapter);
|
|
11758
|
+
const createdIdSet = new Set(createdIds.map(String));
|
|
11759
|
+
foldCorrelativeShifts(
|
|
11760
|
+
adapter,
|
|
11761
|
+
correlativeShifts,
|
|
11762
|
+
createdIdSet,
|
|
11763
|
+
beforeSnap,
|
|
11764
|
+
touched
|
|
11765
|
+
);
|
|
11766
|
+
for (const createdId of createdIds) touched.add(String(createdId));
|
|
11767
|
+
const appliedLinks = [];
|
|
11768
|
+
for (const link of action.links) {
|
|
11769
|
+
const newSource = originalToNew.get(link.source);
|
|
11770
|
+
const newTarget = originalToNew.get(link.target);
|
|
11771
|
+
if (newSource === void 0 || newTarget === void 0) continue;
|
|
11772
|
+
const op = {
|
|
11773
|
+
kind: "create",
|
|
11774
|
+
source: newSource,
|
|
11775
|
+
target: newTarget,
|
|
11776
|
+
type: link.type,
|
|
11777
|
+
lag: lagDaysToHours(link.lag, sector.hoursPerDay)
|
|
11778
|
+
};
|
|
11779
|
+
const res = applyLinkOperation(op, {
|
|
11780
|
+
port: adapter,
|
|
11781
|
+
newLinkId: link.linkId ? () => link.linkId : deps.linkIdGen.next
|
|
11782
|
+
});
|
|
11783
|
+
appliedLinks.push({
|
|
11784
|
+
op,
|
|
11785
|
+
finalLinkId: res.applied ? res.linkId : null,
|
|
11786
|
+
rejected: res.applied ? null : res.rejected ?? "link_op_rejected"
|
|
11787
|
+
});
|
|
11788
|
+
}
|
|
11789
|
+
const { scheduledIds } = await runPostMutation(
|
|
11790
|
+
{
|
|
11791
|
+
adapter,
|
|
11792
|
+
scheduler,
|
|
11793
|
+
sector: deps.sector,
|
|
11794
|
+
defaultBaseCalendarId: deps.defaultBaseCalendarId
|
|
11795
|
+
},
|
|
11796
|
+
{
|
|
11797
|
+
action,
|
|
11798
|
+
autoscheduleFrom: createdIds[0] ?? null,
|
|
11799
|
+
recomputeParentsFrom: createdIds,
|
|
11800
|
+
now: deps.now,
|
|
11801
|
+
options
|
|
11802
|
+
}
|
|
11803
|
+
);
|
|
11804
|
+
const linkChanges = buildLinkChangesForBatch(
|
|
11805
|
+
appliedLinks,
|
|
11806
|
+
/* @__PURE__ */ new Map(),
|
|
11807
|
+
adapter
|
|
11808
|
+
);
|
|
11809
|
+
return {
|
|
11810
|
+
ok: true,
|
|
11811
|
+
changes: await assembleChangeSet(adapter, {
|
|
11812
|
+
source: action,
|
|
11813
|
+
beforeSnap,
|
|
11814
|
+
touchedIds: touched,
|
|
11815
|
+
scheduledIds,
|
|
11816
|
+
links: linkChanges,
|
|
11817
|
+
hoursPerDay: sector.hoursPerDay
|
|
11818
|
+
})
|
|
11819
|
+
};
|
|
11820
|
+
}
|
|
11821
|
+
|
|
11822
|
+
// src/dispatch/handlers/sir-sync.ts
|
|
11823
|
+
function dispatchSirSync(action, deps) {
|
|
11824
|
+
const { adapter } = deps;
|
|
11825
|
+
const id = action.activityId;
|
|
11826
|
+
const snapshot = adapter.getActivity(id);
|
|
11827
|
+
if (!snapshot) {
|
|
11828
|
+
return { ok: false, reason: REJECTION_REASON.ACTIVITY_NOT_FOUND };
|
|
11829
|
+
}
|
|
11830
|
+
const before = snapshot.pendingRequestIds ?? [];
|
|
11831
|
+
const after = action.pendingRequests.map((r) => r.id);
|
|
11832
|
+
adapter.setActivityField(action.activityId, "pendingRequestIds", after);
|
|
11833
|
+
const change = {
|
|
11834
|
+
id,
|
|
11835
|
+
kind: "updated",
|
|
11836
|
+
fields: { pendingRequestIds: { before, after } },
|
|
11837
|
+
after: { id, pendingRequestIds: after }
|
|
11838
|
+
};
|
|
11839
|
+
return {
|
|
11840
|
+
ok: true,
|
|
11841
|
+
changes: {
|
|
11842
|
+
source: action,
|
|
11843
|
+
activities: [change],
|
|
11844
|
+
links: [],
|
|
11845
|
+
calendars: [],
|
|
11846
|
+
trackingEvents: []
|
|
11847
|
+
}
|
|
11848
|
+
};
|
|
11849
|
+
}
|
|
11850
|
+
|
|
11851
|
+
// src/dispatch/handlers/activity-lookahead-sync.ts
|
|
11852
|
+
function dispatchActivityLookaheadSync(action, deps) {
|
|
11853
|
+
const ids = [...new Set(action.activityIds.map(String))];
|
|
11854
|
+
const snapshots = ids.map((id) => deps.adapter.getActivity(id));
|
|
11855
|
+
if (snapshots.some((snapshot) => !snapshot)) {
|
|
11856
|
+
return { ok: false, reason: REJECTION_REASON.ACTIVITY_NOT_FOUND };
|
|
11857
|
+
}
|
|
11858
|
+
const activities = [];
|
|
11859
|
+
for (const [index, id] of ids.entries()) {
|
|
11860
|
+
const snapshot = snapshots[index];
|
|
11861
|
+
if (!snapshot) continue;
|
|
11862
|
+
const fields = {};
|
|
11863
|
+
if (snapshot.isLookahead !== action.isLookahead) {
|
|
11864
|
+
fields.isLookahead = {
|
|
11865
|
+
before: snapshot.isLookahead,
|
|
11866
|
+
after: action.isLookahead
|
|
11867
|
+
};
|
|
11868
|
+
deps.adapter.setActivityField(id, "isLookahead", action.isLookahead);
|
|
11869
|
+
}
|
|
11870
|
+
if (snapshot.hasLookaheadTasks !== action.hasLookaheadTasks) {
|
|
11871
|
+
fields.hasLookaheadTasks = {
|
|
11872
|
+
before: snapshot.hasLookaheadTasks,
|
|
11873
|
+
after: action.hasLookaheadTasks
|
|
11874
|
+
};
|
|
11875
|
+
deps.adapter.setActivityField(
|
|
11876
|
+
id,
|
|
11877
|
+
"hasLookaheadTasks",
|
|
11878
|
+
action.hasLookaheadTasks
|
|
11879
|
+
);
|
|
11880
|
+
}
|
|
11881
|
+
if (Object.keys(fields).length === 0) continue;
|
|
11882
|
+
activities.push({
|
|
11883
|
+
id,
|
|
11884
|
+
kind: "updated",
|
|
11885
|
+
fields,
|
|
11886
|
+
after: {
|
|
11887
|
+
...snapshot,
|
|
11888
|
+
isLookahead: action.isLookahead,
|
|
11889
|
+
hasLookaheadTasks: action.hasLookaheadTasks
|
|
11890
|
+
}
|
|
11891
|
+
});
|
|
11892
|
+
}
|
|
11893
|
+
return {
|
|
11894
|
+
ok: true,
|
|
11895
|
+
changes: {
|
|
11896
|
+
source: action,
|
|
11897
|
+
activities,
|
|
11898
|
+
links: [],
|
|
11899
|
+
calendars: [],
|
|
11900
|
+
trackingEvents: []
|
|
11901
|
+
}
|
|
11902
|
+
};
|
|
11198
11903
|
}
|
|
11199
11904
|
|
|
11200
11905
|
// src/internal/hierarchy/invalid-links.ts
|
|
@@ -12792,7 +13497,10 @@ async function dispatchStatusCriteriaSet(action, deps) {
|
|
|
12792
13497
|
}
|
|
12793
13498
|
|
|
12794
13499
|
// src/dispatch/dispatch.ts
|
|
12795
|
-
async function
|
|
13500
|
+
async function performDispatch(action, options, deps) {
|
|
13501
|
+
if (action.kind === "activity-batch") {
|
|
13502
|
+
return dispatchActivityBatch(action, options, deps);
|
|
13503
|
+
}
|
|
12796
13504
|
if (action.kind === "persistence-acknowledge") {
|
|
12797
13505
|
return dispatchPersistenceAcknowledge(action, deps);
|
|
12798
13506
|
}
|
|
@@ -16026,6 +16734,7 @@ var ScheduleState = class {
|
|
|
16026
16734
|
};
|
|
16027
16735
|
_writeCapture = new WriteCapture();
|
|
16028
16736
|
_viewState = new ViewStateStore();
|
|
16737
|
+
_filterProjection = null;
|
|
16029
16738
|
_viewStateBefore = null;
|
|
16030
16739
|
_lastStartDateBefore = null;
|
|
16031
16740
|
_promotionSnapshotBefore = null;
|
|
@@ -16140,6 +16849,13 @@ var ScheduleState = class {
|
|
|
16140
16849
|
setActiveFilter(nextFilter) {
|
|
16141
16850
|
this._captureViewStateOnce();
|
|
16142
16851
|
this._viewState.setActiveFilter(nextFilter);
|
|
16852
|
+
this._filterProjection = null;
|
|
16853
|
+
}
|
|
16854
|
+
getFilterProjection() {
|
|
16855
|
+
return this._filterProjection;
|
|
16856
|
+
}
|
|
16857
|
+
setFilterProjection(projection) {
|
|
16858
|
+
this._filterProjection = projection;
|
|
16143
16859
|
}
|
|
16144
16860
|
getActiveOrder() {
|
|
16145
16861
|
return this._viewState.getActiveOrder();
|
|
@@ -16181,6 +16897,7 @@ var ScheduleState = class {
|
|
|
16181
16897
|
}
|
|
16182
16898
|
hydrateViewState(seed2) {
|
|
16183
16899
|
this._viewState.hydrate(seed2);
|
|
16900
|
+
this._filterProjection = null;
|
|
16184
16901
|
this.invalidateDerivedOrder();
|
|
16185
16902
|
}
|
|
16186
16903
|
_captureViewStateOnce() {
|
|
@@ -16381,6 +17098,7 @@ var ScheduleState = class {
|
|
|
16381
17098
|
this._restoreActivityFields(before);
|
|
16382
17099
|
if (this._viewStateBefore !== null) {
|
|
16383
17100
|
this._viewState.restore(this._viewStateBefore);
|
|
17101
|
+
this._filterProjection = null;
|
|
16384
17102
|
this.invalidateDerivedOrder();
|
|
16385
17103
|
}
|
|
16386
17104
|
if (this._promotionSnapshotBefore !== null) {
|
|
@@ -16590,8 +17308,10 @@ function buildHistoryChangeSet(changes) {
|
|
|
16590
17308
|
...entry,
|
|
16591
17309
|
after: null
|
|
16592
17310
|
}));
|
|
17311
|
+
const source = changes.source.kind === "activity-batch" ? { ...changes.source, items: [], links: [] } : changes.source;
|
|
16593
17312
|
return cloneDomainValue({
|
|
16594
17313
|
...changes,
|
|
17314
|
+
source,
|
|
16595
17315
|
activities: activitiesWithoutAfter,
|
|
16596
17316
|
links: linksWithoutAfter
|
|
16597
17317
|
});
|
|
@@ -16608,7 +17328,7 @@ function captureCreatedSnapshots(state, changeSet) {
|
|
|
16608
17328
|
if (live) afterSnap.set(String(ch.id), structuredCloneActivity(live));
|
|
16609
17329
|
}
|
|
16610
17330
|
for (const ch of changeSet.links) {
|
|
16611
|
-
if (ch.kind
|
|
17331
|
+
if (ch.kind === "deleted") continue;
|
|
16612
17332
|
const live = state.getLink(String(ch.id));
|
|
16613
17333
|
if (live) afterLinks.set(String(ch.id), { ...live });
|
|
16614
17334
|
}
|
|
@@ -16831,6 +17551,17 @@ function applyChangeSetSide(state, entry, side) {
|
|
|
16831
17551
|
for (const ch of cs.links) {
|
|
16832
17552
|
if (ch.kind === "updated") {
|
|
16833
17553
|
if (!ch.fields) continue;
|
|
17554
|
+
if (Object.hasOwn(ch.fields, "source") || Object.hasOwn(ch.fields, "target")) {
|
|
17555
|
+
const snapshot = side === "before" ? entry.beforeLinks?.get(String(ch.id)) : entry.afterLinks?.get(String(ch.id));
|
|
17556
|
+
if (!snapshot) {
|
|
17557
|
+
throw new Error(
|
|
17558
|
+
`${side === "before" ? "undo" : "redo"}: missing link snapshot for ${ch.id}`
|
|
17559
|
+
);
|
|
17560
|
+
}
|
|
17561
|
+
state.removeLink(String(ch.id));
|
|
17562
|
+
state.addLink({ ...snapshot });
|
|
17563
|
+
continue;
|
|
17564
|
+
}
|
|
16834
17565
|
for (const [field, fv] of Object.entries(ch.fields)) {
|
|
16835
17566
|
setLinkFieldDynamic(
|
|
16836
17567
|
state,
|
|
@@ -17101,9 +17832,26 @@ function idArrayEquals(current, saved) {
|
|
|
17101
17832
|
return currentIds.every((value, index) => value === savedIds[index]);
|
|
17102
17833
|
}
|
|
17103
17834
|
|
|
17835
|
+
// src/boundary/save/link-changes.ts
|
|
17836
|
+
function linkChangedSince(baseline, current) {
|
|
17837
|
+
return baseline.source !== current.source || baseline.target !== current.target || baseline.lag !== current.lag || baseline.type !== current.type;
|
|
17838
|
+
}
|
|
17839
|
+
function checkNoUpdatedLinks(baseline, current) {
|
|
17840
|
+
const baselineById = new Map(
|
|
17841
|
+
baseline.map((link) => [String(link.id), link])
|
|
17842
|
+
);
|
|
17843
|
+
return current.filter((link) => {
|
|
17844
|
+
const base = baselineById.get(String(link.id));
|
|
17845
|
+
if (!base) return false;
|
|
17846
|
+
return linkChangedSince(base, link);
|
|
17847
|
+
});
|
|
17848
|
+
}
|
|
17849
|
+
|
|
17104
17850
|
// src/boundary/save/save-tracker.ts
|
|
17105
17851
|
var SaveTracker = class {
|
|
17106
17852
|
initialized = false;
|
|
17853
|
+
dirtyActivityIds = /* @__PURE__ */ new Set();
|
|
17854
|
+
dirtyLinkIds = /* @__PURE__ */ new Set();
|
|
17107
17855
|
linksAtLastSave = /* @__PURE__ */ new Map();
|
|
17108
17856
|
activitiesAtLastSave = /* @__PURE__ */ new Map();
|
|
17109
17857
|
init(activities, links) {
|
|
@@ -17113,10 +17861,16 @@ var SaveTracker = class {
|
|
|
17113
17861
|
}
|
|
17114
17862
|
snapshotActivities(activities) {
|
|
17115
17863
|
this.activitiesAtLastSave.clear();
|
|
17864
|
+
this.dirtyActivityIds.clear();
|
|
17116
17865
|
for (const activity of activities) {
|
|
17117
|
-
|
|
17866
|
+
const activityId = String(activity.id);
|
|
17867
|
+
if (activity.proplannerId == null) {
|
|
17868
|
+
this.dirtyActivityIds.add(activityId);
|
|
17869
|
+
continue;
|
|
17870
|
+
}
|
|
17871
|
+
const persistable = projectPersistableActivity(activity);
|
|
17118
17872
|
this.activitiesAtLastSave.set(String(activity.id), {
|
|
17119
|
-
persistable
|
|
17873
|
+
persistable,
|
|
17120
17874
|
deletedSnapshot: {
|
|
17121
17875
|
id: activity.id,
|
|
17122
17876
|
proplannerId: activity.proplannerId,
|
|
@@ -17124,12 +17878,20 @@ var SaveTracker = class {
|
|
|
17124
17878
|
hadBaseline: activity.baselineSnapshot !== null || activity.baselinePoints.length > 0
|
|
17125
17879
|
}
|
|
17126
17880
|
});
|
|
17881
|
+
if (activityChangedSince(activity, persistable)) {
|
|
17882
|
+
this.dirtyActivityIds.add(activityId);
|
|
17883
|
+
}
|
|
17127
17884
|
}
|
|
17128
17885
|
}
|
|
17129
17886
|
snapshotLinks(links) {
|
|
17130
17887
|
this.linksAtLastSave.clear();
|
|
17888
|
+
this.dirtyLinkIds.clear();
|
|
17131
17889
|
for (const link of links) {
|
|
17132
|
-
|
|
17890
|
+
const linkId = String(link.id);
|
|
17891
|
+
if (link.proplannerId == null) {
|
|
17892
|
+
this.dirtyLinkIds.add(linkId);
|
|
17893
|
+
continue;
|
|
17894
|
+
}
|
|
17133
17895
|
this.linksAtLastSave.set(String(link.id), {
|
|
17134
17896
|
id: link.id,
|
|
17135
17897
|
proplannerId: link.proplannerId,
|
|
@@ -17140,21 +17902,52 @@ var SaveTracker = class {
|
|
|
17140
17902
|
});
|
|
17141
17903
|
}
|
|
17142
17904
|
}
|
|
17143
|
-
|
|
17144
|
-
if (!this.initialized) return
|
|
17145
|
-
|
|
17146
|
-
|
|
17147
|
-
|
|
17148
|
-
|
|
17149
|
-
|
|
17150
|
-
|
|
17151
|
-
|
|
17152
|
-
|
|
17153
|
-
|
|
17154
|
-
|
|
17155
|
-
|
|
17156
|
-
|
|
17157
|
-
|
|
17905
|
+
recordChanges(activities, links, getActivity, getLink) {
|
|
17906
|
+
if (!this.initialized) return;
|
|
17907
|
+
for (const change of activities) {
|
|
17908
|
+
const activityId = String(change.id);
|
|
17909
|
+
const current = getActivity(activityId);
|
|
17910
|
+
const saved = this.activitiesAtLastSave.get(activityId);
|
|
17911
|
+
if (current === null ? saved !== void 0 : current.proplannerId == null || saved === void 0 || activityChangedSince(current, saved.persistable)) {
|
|
17912
|
+
this.dirtyActivityIds.add(activityId);
|
|
17913
|
+
} else {
|
|
17914
|
+
this.dirtyActivityIds.delete(activityId);
|
|
17915
|
+
}
|
|
17916
|
+
}
|
|
17917
|
+
for (const change of links) {
|
|
17918
|
+
const linkId = String(change.id);
|
|
17919
|
+
const current = getLink(linkId);
|
|
17920
|
+
const saved = this.linksAtLastSave.get(linkId);
|
|
17921
|
+
if (current === null ? saved !== void 0 : current.proplannerId == null || saved === void 0 || linkChangedSince(saved, current)) {
|
|
17922
|
+
this.dirtyLinkIds.add(linkId);
|
|
17923
|
+
} else {
|
|
17924
|
+
this.dirtyLinkIds.delete(linkId);
|
|
17925
|
+
}
|
|
17926
|
+
}
|
|
17927
|
+
}
|
|
17928
|
+
acknowledgePersistedLookahead(activityIds, getActivity) {
|
|
17929
|
+
if (!this.initialized) return;
|
|
17930
|
+
for (const activityId of activityIds) {
|
|
17931
|
+
const current = getActivity(activityId);
|
|
17932
|
+
const saved = this.activitiesAtLastSave.get(activityId);
|
|
17933
|
+
if (current === null || saved === void 0) continue;
|
|
17934
|
+
const persistable = {
|
|
17935
|
+
...saved.persistable,
|
|
17936
|
+
isLookahead: current.isLookahead
|
|
17937
|
+
};
|
|
17938
|
+
this.activitiesAtLastSave.set(activityId, {
|
|
17939
|
+
...saved,
|
|
17940
|
+
persistable
|
|
17941
|
+
});
|
|
17942
|
+
if (current.proplannerId == null || activityChangedSince(current, persistable)) {
|
|
17943
|
+
this.dirtyActivityIds.add(activityId);
|
|
17944
|
+
} else {
|
|
17945
|
+
this.dirtyActivityIds.delete(activityId);
|
|
17946
|
+
}
|
|
17947
|
+
}
|
|
17948
|
+
}
|
|
17949
|
+
hasUnsavedChanges() {
|
|
17950
|
+
return this.initialized && (this.dirtyActivityIds.size > 0 || this.dirtyLinkIds.size > 0);
|
|
17158
17951
|
}
|
|
17159
17952
|
deletedActivities(activities) {
|
|
17160
17953
|
if (!this.initialized) return [];
|
|
@@ -17192,10 +17985,13 @@ var SaveTracker = class {
|
|
|
17192
17985
|
if (link.proplannerId == null) return false;
|
|
17193
17986
|
const saved = this.linksAtLastSave.get(String(link.id));
|
|
17194
17987
|
if (!saved) return true;
|
|
17195
|
-
return
|
|
17988
|
+
return linkChangedSince(saved, link);
|
|
17196
17989
|
});
|
|
17197
17990
|
}
|
|
17198
17991
|
clear() {
|
|
17992
|
+
this.initialized = false;
|
|
17993
|
+
this.dirtyActivityIds.clear();
|
|
17994
|
+
this.dirtyLinkIds.clear();
|
|
17199
17995
|
this.linksAtLastSave.clear();
|
|
17200
17996
|
this.activitiesAtLastSave.clear();
|
|
17201
17997
|
}
|
|
@@ -17360,7 +18156,7 @@ function parseActivity(raw, context) {
|
|
|
17360
18156
|
context.hoursPerDay
|
|
17361
18157
|
),
|
|
17362
18158
|
isCritical: Boolean(raw.is_critical),
|
|
17363
|
-
freeSlackHours:
|
|
18159
|
+
freeSlackHours: null,
|
|
17364
18160
|
expectedProgress: null,
|
|
17365
18161
|
expectedProgressBaseline: null,
|
|
17366
18162
|
status: null,
|
|
@@ -17797,13 +18593,19 @@ function createActivityIdGenerator(options = {}) {
|
|
|
17797
18593
|
const n = typeof id === "number" ? id : Number(id);
|
|
17798
18594
|
if (!Number.isFinite(n)) return;
|
|
17799
18595
|
raise(n);
|
|
18596
|
+
},
|
|
18597
|
+
snapshot() {
|
|
18598
|
+
return counter;
|
|
18599
|
+
},
|
|
18600
|
+
restore(snapshot) {
|
|
18601
|
+
counter = snapshot;
|
|
17800
18602
|
}
|
|
17801
18603
|
};
|
|
17802
18604
|
}
|
|
17803
18605
|
|
|
17804
18606
|
// src/generators/link-id-generator.ts
|
|
17805
18607
|
function createLinkIdGenerator(options = {}) {
|
|
17806
|
-
let counter = options.seed ??
|
|
18608
|
+
let counter = options.seed ?? 0;
|
|
17807
18609
|
const raise = (value) => {
|
|
17808
18610
|
if (value > counter) counter = value;
|
|
17809
18611
|
};
|
|
@@ -17822,6 +18624,12 @@ function createLinkIdGenerator(options = {}) {
|
|
|
17822
18624
|
const n = typeof id === "number" ? id : Number(id);
|
|
17823
18625
|
if (!Number.isFinite(n)) return;
|
|
17824
18626
|
raise(n);
|
|
18627
|
+
},
|
|
18628
|
+
snapshot() {
|
|
18629
|
+
return counter;
|
|
18630
|
+
},
|
|
18631
|
+
restore(snapshot) {
|
|
18632
|
+
counter = snapshot;
|
|
17825
18633
|
}
|
|
17826
18634
|
};
|
|
17827
18635
|
}
|
|
@@ -17851,6 +18659,12 @@ function createUniqueCorrelativeIdGenerator(options = {}) {
|
|
|
17851
18659
|
if (uid2 == null) return;
|
|
17852
18660
|
const n = typeof uid2 === "number" ? uid2 : Number(uid2);
|
|
17853
18661
|
raise(n);
|
|
18662
|
+
},
|
|
18663
|
+
snapshot() {
|
|
18664
|
+
return counter;
|
|
18665
|
+
},
|
|
18666
|
+
restore(snapshot) {
|
|
18667
|
+
counter = snapshot;
|
|
17854
18668
|
}
|
|
17855
18669
|
};
|
|
17856
18670
|
}
|
|
@@ -17927,13 +18741,13 @@ function minSuffixFromArray(suffixes) {
|
|
|
17927
18741
|
if (!suffixes || suffixes.length === 0) {
|
|
17928
18742
|
throw new Error("minSuffixFromArray requires non-empty array");
|
|
17929
18743
|
}
|
|
17930
|
-
return suffixes.reduce((
|
|
18744
|
+
return suffixes.reduce((min2, current) => minSuffix(min2, current));
|
|
17931
18745
|
}
|
|
17932
18746
|
function maxSuffixFromArray(suffixes) {
|
|
17933
18747
|
if (!suffixes || suffixes.length === 0) {
|
|
17934
18748
|
throw new Error("maxSuffixFromArray requires non-empty array");
|
|
17935
18749
|
}
|
|
17936
|
-
return suffixes.reduce((
|
|
18750
|
+
return suffixes.reduce((max2, current) => maxSuffix(max2, current));
|
|
17937
18751
|
}
|
|
17938
18752
|
|
|
17939
18753
|
// src/generators/custom-id/generation-strategies.ts
|
|
@@ -18553,7 +19367,8 @@ var SCHEDULE_CORE_STATUS = {
|
|
|
18553
19367
|
};
|
|
18554
19368
|
function initializeCore(input) {
|
|
18555
19369
|
const clock = input.clock ?? null;
|
|
18556
|
-
const
|
|
19370
|
+
const initializedAt = clock?.() ?? null;
|
|
19371
|
+
const loadNow = initializedAt ? endOfLocalDay(initializedAt) : null;
|
|
18557
19372
|
const reporter = input.reporter ?? noopReporter;
|
|
18558
19373
|
const parsed2 = parseFromBackend(
|
|
18559
19374
|
{
|
|
@@ -18584,6 +19399,7 @@ function initializeCore(input) {
|
|
|
18584
19399
|
knownIds: parsed2.activities.map((a) => a.id)
|
|
18585
19400
|
});
|
|
18586
19401
|
const linkIdGen = createLinkIdGenerator({
|
|
19402
|
+
seed: initializedAt?.getTime() ?? 0,
|
|
18587
19403
|
knownIds: parsed2.links.map((l) => l.id)
|
|
18588
19404
|
});
|
|
18589
19405
|
const uidGen = createUniqueCorrelativeIdGenerator({
|
|
@@ -18627,13 +19443,204 @@ function initializeCore(input) {
|
|
|
18627
19443
|
};
|
|
18628
19444
|
}
|
|
18629
19445
|
|
|
19446
|
+
// src/propagations/upward/date-gesture-preview.ts
|
|
19447
|
+
var emptyFormula = () => ({
|
|
19448
|
+
constantStart: null,
|
|
19449
|
+
variableStartOffset: null,
|
|
19450
|
+
constantEnd: null,
|
|
19451
|
+
variableEndOffset: null
|
|
19452
|
+
});
|
|
19453
|
+
var min = (left, right) => left === null ? right : Math.min(left, right);
|
|
19454
|
+
var max = (left, right) => left === null ? right : Math.max(left, right);
|
|
19455
|
+
function createDateGesturePreview(adapter, gesture, assertCurrent) {
|
|
19456
|
+
const participantIds = [
|
|
19457
|
+
...new Set(
|
|
19458
|
+
gesture.kind === "move" ? gesture.activityIds.map(String) : [String(gesture.activityId)]
|
|
19459
|
+
)
|
|
19460
|
+
];
|
|
19461
|
+
if (participantIds.length === 0) {
|
|
19462
|
+
throw new Error("[ScheduleCore] date gesture has no participants");
|
|
19463
|
+
}
|
|
19464
|
+
const formulas = buildParticipantFormulas(adapter, gesture, participantIds);
|
|
19465
|
+
addAncestorFormulas(adapter, participantIds, formulas);
|
|
19466
|
+
return {
|
|
19467
|
+
getDates(activityId, proposedEdgeTimeMs) {
|
|
19468
|
+
assertCurrent();
|
|
19469
|
+
if (!Number.isFinite(proposedEdgeTimeMs)) {
|
|
19470
|
+
throw new Error("[ScheduleCore] invalid date gesture edge");
|
|
19471
|
+
}
|
|
19472
|
+
const formula = formulas.get(String(activityId));
|
|
19473
|
+
if (!formula) return null;
|
|
19474
|
+
const startTimeMs = evaluateStart(formula, proposedEdgeTimeMs);
|
|
19475
|
+
const endTimeMs = evaluateEnd(formula, proposedEdgeTimeMs);
|
|
19476
|
+
if (startTimeMs === null || endTimeMs === null) {
|
|
19477
|
+
throw new Error(
|
|
19478
|
+
`[ScheduleCore] incomplete date gesture bounds for ${String(activityId)}`
|
|
19479
|
+
);
|
|
19480
|
+
}
|
|
19481
|
+
return { startTimeMs, endTimeMs };
|
|
19482
|
+
}
|
|
19483
|
+
};
|
|
19484
|
+
}
|
|
19485
|
+
function buildParticipantFormulas(adapter, gesture, participantIds) {
|
|
19486
|
+
const formulas = /* @__PURE__ */ new Map();
|
|
19487
|
+
const anchorId = gesture.kind === "move" ? String(gesture.anchorActivityId) : null;
|
|
19488
|
+
const anchor = anchorId === null ? null : requireLeafActivity(adapter, anchorId);
|
|
19489
|
+
if (anchorId !== null && !participantIds.includes(anchorId)) {
|
|
19490
|
+
throw new Error("[ScheduleCore] move anchor is not a participant");
|
|
19491
|
+
}
|
|
19492
|
+
for (const activityId of participantIds) {
|
|
19493
|
+
const activity = requireLeafActivity(adapter, activityId);
|
|
19494
|
+
if (gesture.kind === "move") {
|
|
19495
|
+
const anchorStart = anchor.startDate.getTime();
|
|
19496
|
+
formulas.set(activityId, {
|
|
19497
|
+
constantStart: null,
|
|
19498
|
+
variableStartOffset: activity.startDate.getTime() - anchorStart,
|
|
19499
|
+
constantEnd: null,
|
|
19500
|
+
variableEndOffset: activity.endDate.getTime() - anchorStart
|
|
19501
|
+
});
|
|
19502
|
+
} else if (gesture.kind === "resize-start") {
|
|
19503
|
+
formulas.set(activityId, {
|
|
19504
|
+
constantStart: null,
|
|
19505
|
+
variableStartOffset: 0,
|
|
19506
|
+
constantEnd: activity.endDate.getTime(),
|
|
19507
|
+
variableEndOffset: null
|
|
19508
|
+
});
|
|
19509
|
+
} else {
|
|
19510
|
+
formulas.set(activityId, {
|
|
19511
|
+
constantStart: activity.startDate.getTime(),
|
|
19512
|
+
variableStartOffset: null,
|
|
19513
|
+
constantEnd: null,
|
|
19514
|
+
variableEndOffset: 0
|
|
19515
|
+
});
|
|
19516
|
+
}
|
|
19517
|
+
}
|
|
19518
|
+
return formulas;
|
|
19519
|
+
}
|
|
19520
|
+
function addAncestorFormulas(adapter, participantIds, formulas) {
|
|
19521
|
+
const ancestors = findAncestorsOfDirty(adapter, new Set(participantIds));
|
|
19522
|
+
for (const parentId of ancestors) {
|
|
19523
|
+
const formula = emptyFormula();
|
|
19524
|
+
for (const childId of adapter.getChildren(parentId)) {
|
|
19525
|
+
const childFormula = formulas.get(childId);
|
|
19526
|
+
if (childFormula) {
|
|
19527
|
+
mergeFormula(formula, childFormula);
|
|
19528
|
+
continue;
|
|
19529
|
+
}
|
|
19530
|
+
const child = adapter.getActivity(childId);
|
|
19531
|
+
if (!child) {
|
|
19532
|
+
throw new Error(
|
|
19533
|
+
`[ScheduleCore] missing child ${childId} while previewing parent ${parentId}`
|
|
19534
|
+
);
|
|
19535
|
+
}
|
|
19536
|
+
formula.constantStart = min(
|
|
19537
|
+
formula.constantStart,
|
|
19538
|
+
child.startDate.getTime()
|
|
19539
|
+
);
|
|
19540
|
+
formula.constantEnd = max(formula.constantEnd, child.endDate.getTime());
|
|
19541
|
+
}
|
|
19542
|
+
formulas.set(parentId, formula);
|
|
19543
|
+
}
|
|
19544
|
+
}
|
|
19545
|
+
function requireLeafActivity(adapter, activityId) {
|
|
19546
|
+
const activity = adapter.getActivity(activityId);
|
|
19547
|
+
if (!activity) {
|
|
19548
|
+
throw new Error(
|
|
19549
|
+
`[ScheduleCore] missing date gesture activity ${activityId}`
|
|
19550
|
+
);
|
|
19551
|
+
}
|
|
19552
|
+
if (adapter.hasChildren(activityId)) {
|
|
19553
|
+
throw new Error(
|
|
19554
|
+
`[ScheduleCore] summary activity ${activityId} cannot be dragged directly`
|
|
19555
|
+
);
|
|
19556
|
+
}
|
|
19557
|
+
return activity;
|
|
19558
|
+
}
|
|
19559
|
+
function mergeFormula(target, source) {
|
|
19560
|
+
if (source.constantStart !== null) {
|
|
19561
|
+
target.constantStart = min(target.constantStart, source.constantStart);
|
|
19562
|
+
}
|
|
19563
|
+
if (source.variableStartOffset !== null) {
|
|
19564
|
+
target.variableStartOffset = min(
|
|
19565
|
+
target.variableStartOffset,
|
|
19566
|
+
source.variableStartOffset
|
|
19567
|
+
);
|
|
19568
|
+
}
|
|
19569
|
+
if (source.constantEnd !== null) {
|
|
19570
|
+
target.constantEnd = max(target.constantEnd, source.constantEnd);
|
|
19571
|
+
}
|
|
19572
|
+
if (source.variableEndOffset !== null) {
|
|
19573
|
+
target.variableEndOffset = max(
|
|
19574
|
+
target.variableEndOffset,
|
|
19575
|
+
source.variableEndOffset
|
|
19576
|
+
);
|
|
19577
|
+
}
|
|
19578
|
+
}
|
|
19579
|
+
function evaluateStart(formula, proposedEdgeTimeMs) {
|
|
19580
|
+
if (formula.variableStartOffset === null) return formula.constantStart;
|
|
19581
|
+
const variable = proposedEdgeTimeMs + formula.variableStartOffset;
|
|
19582
|
+
return formula.constantStart === null ? variable : Math.min(formula.constantStart, variable);
|
|
19583
|
+
}
|
|
19584
|
+
function evaluateEnd(formula, proposedEdgeTimeMs) {
|
|
19585
|
+
if (formula.variableEndOffset === null) return formula.constantEnd;
|
|
19586
|
+
const variable = proposedEdgeTimeMs + formula.variableEndOffset;
|
|
19587
|
+
return formula.constantEnd === null ? variable : Math.max(formula.constantEnd, variable);
|
|
19588
|
+
}
|
|
19589
|
+
|
|
18630
19590
|
// src/init/schedule-core.ts
|
|
19591
|
+
function changesRequireFilterProjectionRebuild(changes) {
|
|
19592
|
+
for (const change of changes.activities) {
|
|
19593
|
+
if (change.kind === "deleted") return true;
|
|
19594
|
+
const hasMovedParent = change.kind === "updated" && change.fields !== void 0 && "parentId" in change.fields;
|
|
19595
|
+
if (hasMovedParent) return true;
|
|
19596
|
+
}
|
|
19597
|
+
return false;
|
|
19598
|
+
}
|
|
19599
|
+
function collectChangedActivities(changes, adapter) {
|
|
19600
|
+
const activities = [];
|
|
19601
|
+
for (const change of changes.activities) {
|
|
19602
|
+
const activity = adapter.getActivity(change.id);
|
|
19603
|
+
if (activity === null) return null;
|
|
19604
|
+
activities.push(activity);
|
|
19605
|
+
}
|
|
19606
|
+
return activities;
|
|
19607
|
+
}
|
|
19608
|
+
function isCurrentFilterProjection(projection, filter, context) {
|
|
19609
|
+
if (projection === null || projection.filter !== filter) return false;
|
|
19610
|
+
const hasCurrentHours = projection.context.hoursPerDay === context.hoursPerDay;
|
|
19611
|
+
const hasCurrentLocale = projection.context.locale === context.locale;
|
|
19612
|
+
return hasCurrentHours && hasCurrentLocale;
|
|
19613
|
+
}
|
|
18631
19614
|
var ScheduleCore = class {
|
|
18632
19615
|
_status = SCHEDULE_CORE_STATUS.READY;
|
|
18633
19616
|
coreRuntime;
|
|
18634
19617
|
_undo = new UndoRecorder();
|
|
18635
19618
|
_opQueue = Promise.resolve();
|
|
18636
19619
|
_scheduleRevision = 0;
|
|
19620
|
+
/**
|
|
19621
|
+
* Revision counting mutations that have been ADMITTED, whether or not they
|
|
19622
|
+
* have changed anything yet. `_scheduleRevision` counts the ones that
|
|
19623
|
+
* actually did.
|
|
19624
|
+
*
|
|
19625
|
+
* INVARIANT: `_pendingScheduleRevision >= _scheduleRevision`, and equality
|
|
19626
|
+
* means no mutation is in flight.
|
|
19627
|
+
*
|
|
19628
|
+
* The two exist separately because the useful instant and the knowable
|
|
19629
|
+
* instant are not the same one. A critical-path calculation becomes garbage
|
|
19630
|
+
* the moment the next mutation is admitted, but whether that mutation is
|
|
19631
|
+
* substantive is only knowable once its ChangeSet exists, which is hundreds
|
|
19632
|
+
* of milliseconds later at project scale. Measured live on a 12268-activity
|
|
19633
|
+
* project: the cancellation flag flipped 929 ms into a 930 ms calculation,
|
|
19634
|
+
* 812 into 812 and 785 into 785, because the job's apply block queues behind
|
|
19635
|
+
* the very dispatch whose completion cancels it. Cancellation and job end
|
|
19636
|
+
* were the same event, so every discarded job ran the whole calculation.
|
|
19637
|
+
*
|
|
19638
|
+
* Splitting the counter buys the early signal without moving the meaning of
|
|
19639
|
+
* `_scheduleRevision`, whose three readers (`isCriticalPathSettled`,
|
|
19640
|
+
* `createDateGesturePreview` and the job's own `isCurrent`) are all written
|
|
19641
|
+
* against "the state actually changed".
|
|
19642
|
+
*/
|
|
19643
|
+
_pendingScheduleRevision = 0;
|
|
18637
19644
|
_criticalPathRevision = -1;
|
|
18638
19645
|
_activeCriticalPath = null;
|
|
18639
19646
|
constructor(input) {
|
|
@@ -18686,6 +19693,16 @@ var ScheduleCore = class {
|
|
|
18686
19693
|
this.assertReady();
|
|
18687
19694
|
return readActivity(this.coreRuntime.state, id);
|
|
18688
19695
|
}
|
|
19696
|
+
createDateGesturePreview(gesture) {
|
|
19697
|
+
this.assertReady();
|
|
19698
|
+
const revision = this._scheduleRevision;
|
|
19699
|
+
return createDateGesturePreview(this.coreRuntime.state, gesture, () => {
|
|
19700
|
+
this.assertReady();
|
|
19701
|
+
if (this._scheduleRevision !== revision) {
|
|
19702
|
+
throw new Error("[ScheduleCore] date gesture preview is stale");
|
|
19703
|
+
}
|
|
19704
|
+
});
|
|
19705
|
+
}
|
|
18689
19706
|
getAllActivitiesView() {
|
|
18690
19707
|
this.assertReady();
|
|
18691
19708
|
return readAllActivities(this.coreRuntime.state);
|
|
@@ -18783,10 +19800,7 @@ var ScheduleCore = class {
|
|
|
18783
19800
|
}
|
|
18784
19801
|
hasUnsavedChanges() {
|
|
18785
19802
|
this.assertReady();
|
|
18786
|
-
return this._saveTracker.hasUnsavedChanges(
|
|
18787
|
-
this.coreRuntime.state.getAllActivities(),
|
|
18788
|
-
this.getAllLinksView()
|
|
18789
|
-
);
|
|
19803
|
+
return this._saveTracker.hasUnsavedChanges();
|
|
18790
19804
|
}
|
|
18791
19805
|
getDeletedActivitiesSinceLastSave() {
|
|
18792
19806
|
this.assertReady();
|
|
@@ -18804,10 +19818,90 @@ var ScheduleCore = class {
|
|
|
18804
19818
|
);
|
|
18805
19819
|
return workPromise;
|
|
18806
19820
|
}
|
|
19821
|
+
/**
|
|
19822
|
+
* Marks a mutation as admitted and invalidates the calculation in flight.
|
|
19823
|
+
*
|
|
19824
|
+
* Called BEFORE `_enqueue`, which is the point of the whole thing: the wait
|
|
19825
|
+
* in the operation queue is part of the window a running calculation wastes,
|
|
19826
|
+
* and it is the longest part of it when several mutations are already
|
|
19827
|
+
* queued.
|
|
19828
|
+
*
|
|
19829
|
+
* `dispatchChangesSchedulingState` is a pure function of the action, so this
|
|
19830
|
+
* decision needs no state and cannot be wrong about the action's nature. What
|
|
19831
|
+
* it cannot know yet is whether the mutation will produce anything, which is
|
|
19832
|
+
* what `_settleScheduleMutation` reconciles afterwards.
|
|
19833
|
+
*/
|
|
19834
|
+
_beginScheduleMutation(action) {
|
|
19835
|
+
if (!dispatchChangesSchedulingState(action)) return false;
|
|
19836
|
+
return this._admitScheduleMutation();
|
|
19837
|
+
}
|
|
19838
|
+
/** Undo and redo have no action to classify: reaching them IS the mutation. */
|
|
19839
|
+
_admitScheduleMutation() {
|
|
19840
|
+
this._pendingScheduleRevision++;
|
|
19841
|
+
if (this._activeCriticalPath) {
|
|
19842
|
+
this._activeCriticalPath.cancellation.cancelled = true;
|
|
19843
|
+
}
|
|
19844
|
+
return true;
|
|
19845
|
+
}
|
|
19846
|
+
/**
|
|
19847
|
+
* Closes a mutation admitted by `_beginScheduleMutation`, on EVERY exit path.
|
|
19848
|
+
*
|
|
19849
|
+
* `changedState` false means the mutation was admitted and produced nothing
|
|
19850
|
+
* (rejected, non-substantive, or rolled back). The pending revision walks
|
|
19851
|
+
* back so the invariant holds and `isCriticalPathSettled` keeps telling the
|
|
19852
|
+
* truth, and the calculation this mutation killed for nothing is re-armed.
|
|
19853
|
+
*
|
|
19854
|
+
* The re-arm goes through the queue and that is not incidental. Started
|
|
19855
|
+
* outside it, the calculation would run immediately while the next queued
|
|
19856
|
+
* mutation is still waiting, and that mutation would kill it again on
|
|
19857
|
+
* admission: a cancel-and-restart treadmill burning a fresh project-wide deep
|
|
19858
|
+
* copy per lap. Inside the queue the restart cannot happen until the queue
|
|
19859
|
+
* drains, so at most one calculation is armed per settled mutation. The burst
|
|
19860
|
+
* scenario will NOT catch a regression here, because there every dispatch
|
|
19861
|
+
* succeeds and this path is never taken.
|
|
19862
|
+
*
|
|
19863
|
+
* It re-arms through `recomputeCriticalPath` rather than enqueueing the job
|
|
19864
|
+
* directly, because the queue slot must NOT await the job: the job's own
|
|
19865
|
+
* apply block needs a later slot on this same queue, so awaiting it from
|
|
19866
|
+
* inside a slot deadlocks the core. `recomputeCriticalPath` already has the
|
|
19867
|
+
* shape that returns the job's promise out of the slot instead of awaiting
|
|
19868
|
+
* it, and it keeps `_criticalPathReady` pointing at the live calculation.
|
|
19869
|
+
*/
|
|
19870
|
+
_settleScheduleMutation(admitted, changedState) {
|
|
19871
|
+
if (!admitted) return;
|
|
19872
|
+
if (changedState) return;
|
|
19873
|
+
this._pendingScheduleRevision = Math.max(
|
|
19874
|
+
this._pendingScheduleRevision - 1,
|
|
19875
|
+
this._scheduleRevision
|
|
19876
|
+
);
|
|
19877
|
+
if (this._pendingScheduleRevision !== this._scheduleRevision) return;
|
|
19878
|
+
if (this._criticalPathRevision === this._scheduleRevision) return;
|
|
19879
|
+
void this.recomputeCriticalPath().catch((error) => {
|
|
19880
|
+
this.coreRuntime.reporter.error(
|
|
19881
|
+
"[ScheduleCore] Critical Path re-arm after a barren mutation failed",
|
|
19882
|
+
error
|
|
19883
|
+
);
|
|
19884
|
+
});
|
|
19885
|
+
}
|
|
18807
19886
|
async dispatch(action, options = {}) {
|
|
18808
|
-
|
|
19887
|
+
const admitted = this._beginScheduleMutation(action);
|
|
19888
|
+
return this._enqueue(() => this._dispatchInner(action, options, admitted));
|
|
19889
|
+
}
|
|
19890
|
+
async applyActivityBatch(action, options = {}) {
|
|
19891
|
+
const admitted = this._beginScheduleMutation(action);
|
|
19892
|
+
return this._enqueue(() => this._dispatchInner(action, options, admitted));
|
|
19893
|
+
}
|
|
19894
|
+
async _dispatchInner(action, options = {}, admitted = false) {
|
|
19895
|
+
let changedState = false;
|
|
19896
|
+
try {
|
|
19897
|
+
const dispatched = await this._runDispatch(action, options);
|
|
19898
|
+
changedState = dispatched.changedState;
|
|
19899
|
+
return dispatched.result;
|
|
19900
|
+
} finally {
|
|
19901
|
+
this._settleScheduleMutation(admitted, changedState);
|
|
19902
|
+
}
|
|
18809
19903
|
}
|
|
18810
|
-
async
|
|
19904
|
+
async _runDispatch(action, options) {
|
|
18811
19905
|
this.assertReady();
|
|
18812
19906
|
const pipelineContext = buildPipelineContext(this.coreRuntime.state, {
|
|
18813
19907
|
hoursPerDay: this.coreRuntime.sector.hoursPerDay,
|
|
@@ -18815,11 +19909,16 @@ var ScheduleCore = class {
|
|
|
18815
19909
|
inputUnit: options.inputUnit ?? "days"
|
|
18816
19910
|
});
|
|
18817
19911
|
const historyPolicy = getDispatchHistoryPolicy(action);
|
|
19912
|
+
const generatorSnapshot = [
|
|
19913
|
+
this.coreRuntime.activityIdGenerator.snapshot(),
|
|
19914
|
+
this.coreRuntime.linkIdGenerator.snapshot(),
|
|
19915
|
+
this.coreRuntime.uniqueCorrelativeIdGenerator.snapshot()
|
|
19916
|
+
];
|
|
18818
19917
|
this.coreRuntime.state.beginWriteCapture();
|
|
18819
19918
|
this.coreRuntime.customIdTracker.beginCustomIdTransaction();
|
|
18820
19919
|
let result;
|
|
18821
19920
|
try {
|
|
18822
|
-
result = await
|
|
19921
|
+
result = await performDispatch(action, options, {
|
|
18823
19922
|
adapter: this.coreRuntime.state,
|
|
18824
19923
|
ctx: pipelineContext,
|
|
18825
19924
|
scheduler: this.coreRuntime.scheduler,
|
|
@@ -18835,9 +19934,9 @@ var ScheduleCore = class {
|
|
|
18835
19934
|
)?.id ?? null,
|
|
18836
19935
|
now: this.coreRuntime.clock ? endOfLocalDay(this.coreRuntime.clock()) : null
|
|
18837
19936
|
});
|
|
18838
|
-
if (!result.ok) this._rollback();
|
|
19937
|
+
if (!result.ok) this._rollback(generatorSnapshot);
|
|
18839
19938
|
} catch (error) {
|
|
18840
|
-
this._rollback();
|
|
19939
|
+
this._rollback(generatorSnapshot);
|
|
18841
19940
|
throw error;
|
|
18842
19941
|
} finally {
|
|
18843
19942
|
this.coreRuntime.state.endWriteCapture();
|
|
@@ -18860,19 +19959,36 @@ var ScheduleCore = class {
|
|
|
18860
19959
|
Date.now()
|
|
18861
19960
|
);
|
|
18862
19961
|
}
|
|
18863
|
-
if (result.ok
|
|
18864
|
-
|
|
18865
|
-
this.
|
|
18866
|
-
|
|
18867
|
-
|
|
18868
|
-
|
|
19962
|
+
if (result.ok) {
|
|
19963
|
+
if (historyPolicy === "clear-on-success") {
|
|
19964
|
+
this._saveTracker.snapshotActivities(
|
|
19965
|
+
this.coreRuntime.state.getAllActivities()
|
|
19966
|
+
);
|
|
19967
|
+
this._saveTracker.snapshotLinks(this.getAllLinksView());
|
|
19968
|
+
this._undo.clear();
|
|
19969
|
+
} else if (action.kind === "activity-lookahead-sync" && action.acknowledgePersistedLookahead === true) {
|
|
19970
|
+
this._saveTracker.acknowledgePersistedLookahead(
|
|
19971
|
+
action.activityIds,
|
|
19972
|
+
(activityId) => this.coreRuntime.state.getActivity(activityId)
|
|
19973
|
+
);
|
|
19974
|
+
} else {
|
|
19975
|
+
this._saveTracker.recordChanges(
|
|
19976
|
+
result.changes.activities,
|
|
19977
|
+
result.changes.links,
|
|
19978
|
+
(activityId) => this.coreRuntime.state.getActivity(activityId),
|
|
19979
|
+
(linkId) => this.coreRuntime.state.getLink(linkId)
|
|
19980
|
+
);
|
|
19981
|
+
}
|
|
18869
19982
|
}
|
|
18870
19983
|
result = this._withReappliedViewState(action, result);
|
|
18871
|
-
if (!result.ok) return result;
|
|
19984
|
+
if (!result.ok) return { result, changedState: false };
|
|
18872
19985
|
if (dispatchChangesSchedulingState(action) && changeSetIsSubstantive(result.changes)) {
|
|
18873
|
-
this._recordScheduleMutation(
|
|
19986
|
+
this._recordScheduleMutation(
|
|
19987
|
+
options.skipAutoSchedule !== true && options.skipCriticalPath !== true && resolveRunCriticalPath(action)
|
|
19988
|
+
);
|
|
19989
|
+
return { result: toPublicDispatchResult(result), changedState: true };
|
|
18874
19990
|
}
|
|
18875
|
-
return toPublicDispatchResult(result);
|
|
19991
|
+
return { result: toPublicDispatchResult(result), changedState: false };
|
|
18876
19992
|
}
|
|
18877
19993
|
recomputeCriticalPath() {
|
|
18878
19994
|
const operation = this._enqueue(async () => ({
|
|
@@ -18882,7 +19998,11 @@ var ScheduleCore = class {
|
|
|
18882
19998
|
return operation;
|
|
18883
19999
|
}
|
|
18884
20000
|
isCriticalPathSettled() {
|
|
18885
|
-
return this._criticalPathRevision === this._scheduleRevision &&
|
|
20001
|
+
return this._criticalPathRevision === this._scheduleRevision && // An admitted mutation has not landed yet, so whatever is applied now is
|
|
20002
|
+
// about to be stale. Without this term `whenCriticalPathSettled` would
|
|
20003
|
+
// spin: it would keep arming calculations that `isCurrent` kills on their
|
|
20004
|
+
// first check, each one paying the project-wide deep copy first.
|
|
20005
|
+
this._pendingScheduleRevision === this._scheduleRevision && this._activeCriticalPath === null;
|
|
18886
20006
|
}
|
|
18887
20007
|
async whenCriticalPathSettled() {
|
|
18888
20008
|
while (!this.isCriticalPathSettled()) {
|
|
@@ -18890,7 +20010,11 @@ var ScheduleCore = class {
|
|
|
18890
20010
|
}
|
|
18891
20011
|
}
|
|
18892
20012
|
_withReappliedViewState(action, result) {
|
|
18893
|
-
if (!result.ok
|
|
20013
|
+
if (!result.ok) return result;
|
|
20014
|
+
if (action.kind === "visibility-set") {
|
|
20015
|
+
this.coreRuntime.state.setFilterProjection(null);
|
|
20016
|
+
}
|
|
20017
|
+
if (!reappliesViewState(action)) return result;
|
|
18894
20018
|
const merged = this._reapplyViewState(result.changes);
|
|
18895
20019
|
return merged === null ? result : { ...result, changes: merged };
|
|
18896
20020
|
}
|
|
@@ -18911,11 +20035,44 @@ var ScheduleCore = class {
|
|
|
18911
20035
|
*/
|
|
18912
20036
|
_reapplyViewState(changes) {
|
|
18913
20037
|
const withFilter = this._reapplyActiveFilter(changes);
|
|
18914
|
-
const
|
|
18915
|
-
const
|
|
18916
|
-
|
|
20038
|
+
const sequenced = this._emitTouchedBranchOrder(withFilter ?? changes);
|
|
20039
|
+
const withOrder = this._reapplyActiveOrder(
|
|
20040
|
+
sequenced.changes ?? withFilter ?? changes,
|
|
20041
|
+
sequenced.touchedParents
|
|
20042
|
+
);
|
|
20043
|
+
const reapplied = withOrder ?? sequenced.changes ?? withFilter;
|
|
20044
|
+
const finalChanges = reapplied ?? changes;
|
|
20045
|
+
const createdIds = finalChanges.activities.filter((change) => change.kind === "created").map((change) => String(change.id));
|
|
20046
|
+
if (createdIds.length === 0) return reapplied;
|
|
20047
|
+
const createdAndAncestors = new Set(createdIds);
|
|
20048
|
+
const filterProjection = this.coreRuntime.state.getFilterProjection();
|
|
20049
|
+
for (const createdId of createdIds) {
|
|
20050
|
+
if (filterProjection !== null) {
|
|
20051
|
+
filterProjection.pinnedVisibleIds.add(createdId);
|
|
20052
|
+
}
|
|
20053
|
+
let activityId = createdId;
|
|
20054
|
+
while (activityId !== null && activityId !== ROOT_PARENT_ID) {
|
|
20055
|
+
createdAndAncestors.add(activityId);
|
|
20056
|
+
if (filterProjection !== null) {
|
|
20057
|
+
filterProjection.visibleIds.add(activityId);
|
|
20058
|
+
filterProjection.visibleReferenceCounts.set(
|
|
20059
|
+
activityId,
|
|
20060
|
+
(filterProjection.visibleReferenceCounts.get(activityId) ?? 0) + 1
|
|
20061
|
+
);
|
|
20062
|
+
}
|
|
20063
|
+
activityId = this.coreRuntime.state.getParentId(activityId);
|
|
20064
|
+
}
|
|
20065
|
+
}
|
|
20066
|
+
const createdVisibility = applyVisibleSet(
|
|
20067
|
+
this.coreRuntime.state,
|
|
20068
|
+
createdAndAncestors,
|
|
20069
|
+
createdAndAncestors
|
|
18917
20070
|
);
|
|
18918
|
-
|
|
20071
|
+
if (createdVisibility.length === 0) return reapplied;
|
|
20072
|
+
return {
|
|
20073
|
+
...finalChanges,
|
|
20074
|
+
viewState: [...finalChanges.viewState ?? [], ...createdVisibility]
|
|
20075
|
+
};
|
|
18919
20076
|
}
|
|
18920
20077
|
/**
|
|
18921
20078
|
* Emits `order` for the branches this mutation resequenced, when no user order
|
|
@@ -18937,18 +20094,19 @@ var ScheduleCore = class {
|
|
|
18937
20094
|
*/
|
|
18938
20095
|
_emitTouchedBranchOrder(changes) {
|
|
18939
20096
|
const adapter = this.coreRuntime.state;
|
|
18940
|
-
|
|
18941
|
-
const touched = collectResequencedParents(
|
|
20097
|
+
const touchedParents = collectResequencedParents(
|
|
18942
20098
|
changes,
|
|
18943
20099
|
(activityId) => adapter.getParentId(activityId)
|
|
18944
20100
|
);
|
|
18945
|
-
if (
|
|
18946
|
-
|
|
18947
|
-
|
|
18948
|
-
|
|
18949
|
-
|
|
18950
|
-
|
|
18951
|
-
|
|
20101
|
+
if (adapter.getActiveOrder() !== null) {
|
|
20102
|
+
return { changes: null, touchedParents };
|
|
20103
|
+
}
|
|
20104
|
+
if (touchedParents.size === 0) {
|
|
20105
|
+
return { changes: null, touchedParents };
|
|
20106
|
+
}
|
|
20107
|
+
const order = collectBranchOrderForParents(adapter, touchedParents);
|
|
20108
|
+
if (order.length === 0) return { changes: null, touchedParents };
|
|
20109
|
+
return { changes: { ...changes, order }, touchedParents };
|
|
18952
20110
|
}
|
|
18953
20111
|
/**
|
|
18954
20112
|
* Re-sequences the grid after any mutation that could have changed a value the
|
|
@@ -18959,23 +20117,63 @@ var ScheduleCore = class {
|
|
|
18959
20117
|
* Production only re-sorts after a bar drag; diverging from that is a
|
|
18960
20118
|
* deliberate product decision, not an oversight.
|
|
18961
20119
|
*/
|
|
18962
|
-
_reapplyActiveOrder(changes) {
|
|
20120
|
+
_reapplyActiveOrder(changes, resequencedParents) {
|
|
18963
20121
|
const adapter = this.coreRuntime.state;
|
|
18964
20122
|
if (adapter.getActiveOrder() === null) return null;
|
|
18965
20123
|
adapter.invalidateDerivedOrder();
|
|
18966
|
-
|
|
20124
|
+
const hasIndirectOrderChanges = changes.links.length > 0 || changes.calendars.length > 0;
|
|
20125
|
+
if (hasIndirectOrderChanges) {
|
|
20126
|
+
return { ...changes, order: collectBranchOrder(adapter) };
|
|
20127
|
+
}
|
|
20128
|
+
const affectedParents = new Set(resequencedParents);
|
|
20129
|
+
for (const change of changes.activities) {
|
|
20130
|
+
if (change.kind === "deleted") {
|
|
20131
|
+
return { ...changes, order: collectBranchOrder(adapter) };
|
|
20132
|
+
}
|
|
20133
|
+
const parentId = adapter.getParentId(change.id);
|
|
20134
|
+
affectedParents.add(
|
|
20135
|
+
parentId === null ? ROOT_PARENT_ID : String(parentId)
|
|
20136
|
+
);
|
|
20137
|
+
}
|
|
20138
|
+
const order = collectBranchOrderForParents(adapter, affectedParents);
|
|
20139
|
+
if (order.length === 0) return null;
|
|
20140
|
+
return { ...changes, order };
|
|
18967
20141
|
}
|
|
18968
20142
|
_reapplyActiveFilter(changes) {
|
|
18969
|
-
const filter = this.coreRuntime.state.getActiveFilter();
|
|
18970
|
-
if (filter === null) return null;
|
|
18971
20143
|
const adapter = this.coreRuntime.state;
|
|
18972
|
-
const
|
|
18973
|
-
|
|
18974
|
-
|
|
20144
|
+
const filter = adapter.getActiveFilter();
|
|
20145
|
+
if (filter === null) return null;
|
|
20146
|
+
const context = buildFilterContext(this.coreRuntime.sector.hoursPerDay);
|
|
20147
|
+
const projection = adapter.getFilterProjection();
|
|
20148
|
+
const projectionIsCurrent = isCurrentFilterProjection(
|
|
20149
|
+
projection,
|
|
18975
20150
|
filter,
|
|
18976
|
-
context
|
|
18977
|
-
|
|
18978
|
-
const
|
|
20151
|
+
context
|
|
20152
|
+
);
|
|
20153
|
+
const changedActivities = changesRequireFilterProjectionRebuild(changes) ? null : collectChangedActivities(changes, adapter);
|
|
20154
|
+
let affectedIds;
|
|
20155
|
+
let visibleIds;
|
|
20156
|
+
const needsProjectionRebuild = changedActivities === null || !projectionIsCurrent;
|
|
20157
|
+
if (needsProjectionRebuild) {
|
|
20158
|
+
const rebuiltProjection = buildFilterProjection({
|
|
20159
|
+
activities: adapter.getAllActivities(),
|
|
20160
|
+
parentOf: (activityId) => adapter.getParentId(activityId),
|
|
20161
|
+
filter,
|
|
20162
|
+
context,
|
|
20163
|
+
...projectionIsCurrent ? { pinnedVisibleIds: projection.pinnedVisibleIds } : {}
|
|
20164
|
+
});
|
|
20165
|
+
adapter.setFilterProjection(rebuiltProjection);
|
|
20166
|
+
visibleIds = rebuiltProjection.visibleIds;
|
|
20167
|
+
affectedIds = adapter.getAllIds();
|
|
20168
|
+
} else {
|
|
20169
|
+
affectedIds = updateFilterProjection(
|
|
20170
|
+
projection,
|
|
20171
|
+
changedActivities,
|
|
20172
|
+
(activityId) => adapter.getParentId(activityId)
|
|
20173
|
+
);
|
|
20174
|
+
visibleIds = projection.visibleIds;
|
|
20175
|
+
}
|
|
20176
|
+
const viewState = applyVisibleSet(adapter, visibleIds, affectedIds);
|
|
18979
20177
|
if (viewState.length === 0) return null;
|
|
18980
20178
|
return {
|
|
18981
20179
|
...changes,
|
|
@@ -18984,6 +20182,10 @@ var ScheduleCore = class {
|
|
|
18984
20182
|
}
|
|
18985
20183
|
_recordScheduleMutation(criticalPathIsFresh) {
|
|
18986
20184
|
this._scheduleRevision++;
|
|
20185
|
+
this._pendingScheduleRevision = Math.max(
|
|
20186
|
+
this._pendingScheduleRevision,
|
|
20187
|
+
this._scheduleRevision
|
|
20188
|
+
);
|
|
18987
20189
|
if (this._activeCriticalPath) {
|
|
18988
20190
|
this._activeCriticalPath.cancellation.cancelled = true;
|
|
18989
20191
|
}
|
|
@@ -19014,23 +20216,30 @@ var ScheduleCore = class {
|
|
|
19014
20216
|
this.coreRuntime.baseCalendars
|
|
19015
20217
|
)
|
|
19016
20218
|
);
|
|
19017
|
-
const isCurrent = () => !cancellation.cancelled && this._status !== SCHEDULE_CORE_STATUS.DESTROYED && this._scheduleRevision === revision
|
|
20219
|
+
const isCurrent = () => !cancellation.cancelled && this._status !== SCHEDULE_CORE_STATUS.DESTROYED && this._scheduleRevision === revision && // A mutation admitted but not yet settled is enough to make this result
|
|
20220
|
+
// garbage. Without this term the calculation only learns it is obsolete
|
|
20221
|
+
// when the mutation finishes, which measured live is the same instant the
|
|
20222
|
+
// job itself ends.
|
|
20223
|
+
this._pendingScheduleRevision === this._scheduleRevision;
|
|
19018
20224
|
const promise = (async () => {
|
|
19019
20225
|
const calculatedFields = await computeCriticalPathFields(
|
|
19020
20226
|
isolatedState,
|
|
19021
20227
|
this.coreRuntime.sector.hoursPerDay,
|
|
19022
20228
|
isCurrent
|
|
19023
20229
|
);
|
|
19024
|
-
if (!isCurrent()) return null;
|
|
19025
|
-
const fieldsByActivity = calculatedFields ?? /* @__PURE__ */ new Map();
|
|
20230
|
+
if (!isCurrent() || calculatedFields === null) return null;
|
|
19026
20231
|
return this._enqueue(async () => {
|
|
19027
20232
|
if (!isCurrent()) return null;
|
|
19028
20233
|
this.coreRuntime.state.beginWriteCapture();
|
|
19029
20234
|
this.coreRuntime.customIdTracker.beginCustomIdTransaction();
|
|
19030
20235
|
let changes;
|
|
19031
20236
|
try {
|
|
19032
|
-
for (const [activityId, fields] of
|
|
19033
|
-
|
|
20237
|
+
for (const [activityId, fields] of calculatedFields) {
|
|
20238
|
+
setCriticalPathFieldsIfChanged(
|
|
20239
|
+
this.coreRuntime.state,
|
|
20240
|
+
activityId,
|
|
20241
|
+
fields
|
|
20242
|
+
);
|
|
19034
20243
|
}
|
|
19035
20244
|
changes = await assembleChangeSet(this.coreRuntime.state, {
|
|
19036
20245
|
source: { kind: "init" },
|
|
@@ -19092,47 +20301,17 @@ var ScheduleCore = class {
|
|
|
19092
20301
|
}
|
|
19093
20302
|
return { changes };
|
|
19094
20303
|
}
|
|
19095
|
-
_recomputeAfterHistoryRestore() {
|
|
19096
|
-
const state = this.coreRuntime.state;
|
|
19097
|
-
recomputeAllProgressRollup(state);
|
|
19098
|
-
recomputeCanonicalRealWork(state);
|
|
19099
|
-
emitRealCost(state);
|
|
19100
|
-
if (this.coreRuntime.clock) {
|
|
19101
|
-
const now = endOfLocalDay(this.coreRuntime.clock());
|
|
19102
|
-
applyExpectedProgressLive(state, now);
|
|
19103
|
-
let hasActiveBaseline2 = false;
|
|
19104
|
-
state.forEachActivity((activity) => {
|
|
19105
|
-
hasActiveBaseline2 ||= getActiveBaseline(activity) !== null;
|
|
19106
|
-
});
|
|
19107
|
-
if (hasActiveBaseline2) {
|
|
19108
|
-
runExpectedProgressBase(
|
|
19109
|
-
state,
|
|
19110
|
-
now,
|
|
19111
|
-
this.coreRuntime.baseCalendars.find(
|
|
19112
|
-
(calendar) => calendar.baseDefault
|
|
19113
|
-
)?.id ?? null
|
|
19114
|
-
);
|
|
19115
|
-
}
|
|
19116
|
-
applyStatusPass(state, this.coreRuntime.sector.statusCriteria);
|
|
19117
|
-
}
|
|
19118
|
-
}
|
|
19119
20304
|
undo(options = {}) {
|
|
20305
|
+
const admitted = this._admitScheduleMutation();
|
|
20306
|
+
let changedState = false;
|
|
19120
20307
|
const operation = this._enqueue(async () => {
|
|
19121
|
-
|
|
19122
|
-
|
|
19123
|
-
|
|
19124
|
-
|
|
19125
|
-
|
|
19126
|
-
|
|
19127
|
-
|
|
19128
|
-
this._undo.pushRedo(entry);
|
|
19129
|
-
this._undo.resetCoalesce();
|
|
19130
|
-
const changes = buildInverseChangeSet(
|
|
19131
|
-
this.coreRuntime.state,
|
|
19132
|
-
entry,
|
|
19133
|
-
"before"
|
|
19134
|
-
);
|
|
19135
|
-
return this._reapplyViewState(changes) ?? changes;
|
|
20308
|
+
try {
|
|
20309
|
+
return await this._runUndo(options, (changed) => {
|
|
20310
|
+
changedState = changed;
|
|
20311
|
+
});
|
|
20312
|
+
} finally {
|
|
20313
|
+
this._settleScheduleMutation(admitted, changedState);
|
|
20314
|
+
}
|
|
19136
20315
|
});
|
|
19137
20316
|
void operation.then(
|
|
19138
20317
|
(changes) => {
|
|
@@ -19149,23 +20328,45 @@ var ScheduleCore = class {
|
|
|
19149
20328
|
);
|
|
19150
20329
|
return operation;
|
|
19151
20330
|
}
|
|
19152
|
-
|
|
19153
|
-
|
|
20331
|
+
async _runUndo(options, markChanged) {
|
|
20332
|
+
{
|
|
19154
20333
|
this.assertReady();
|
|
19155
|
-
|
|
20334
|
+
if (options.expectedUndoDepth !== void 0 && this._undo.undoDepth() !== options.expectedUndoDepth) {
|
|
20335
|
+
return null;
|
|
20336
|
+
}
|
|
20337
|
+
const entry = this._undo.takeUndo();
|
|
19156
20338
|
if (!entry) return null;
|
|
19157
|
-
|
|
19158
|
-
this._recomputeAfterHistoryRestore();
|
|
20339
|
+
applyUndo(this.coreRuntime.state, entry);
|
|
19159
20340
|
this._recordScheduleMutation(false);
|
|
20341
|
+
markChanged(true);
|
|
19160
20342
|
if (needsResync(entry)) this._resyncCustomIdTrackerFromModel();
|
|
19161
|
-
this._undo.
|
|
20343
|
+
this._undo.pushRedo(entry);
|
|
19162
20344
|
this._undo.resetCoalesce();
|
|
19163
20345
|
const changes = buildInverseChangeSet(
|
|
19164
20346
|
this.coreRuntime.state,
|
|
19165
20347
|
entry,
|
|
19166
|
-
"
|
|
20348
|
+
"before"
|
|
20349
|
+
);
|
|
20350
|
+
this._saveTracker.recordChanges(
|
|
20351
|
+
changes.activities,
|
|
20352
|
+
changes.links,
|
|
20353
|
+
(activityId) => this.coreRuntime.state.getActivity(activityId),
|
|
20354
|
+
(linkId) => this.coreRuntime.state.getLink(linkId)
|
|
19167
20355
|
);
|
|
19168
20356
|
return this._reapplyViewState(changes) ?? changes;
|
|
20357
|
+
}
|
|
20358
|
+
}
|
|
20359
|
+
redo(options = {}) {
|
|
20360
|
+
const admitted = this._admitScheduleMutation();
|
|
20361
|
+
let changedState = false;
|
|
20362
|
+
const operation = this._enqueue(async () => {
|
|
20363
|
+
try {
|
|
20364
|
+
return await this._runRedo((changed) => {
|
|
20365
|
+
changedState = changed;
|
|
20366
|
+
});
|
|
20367
|
+
} finally {
|
|
20368
|
+
this._settleScheduleMutation(admitted, changedState);
|
|
20369
|
+
}
|
|
19169
20370
|
});
|
|
19170
20371
|
void operation.then(
|
|
19171
20372
|
(changes) => {
|
|
@@ -19182,6 +20383,29 @@ var ScheduleCore = class {
|
|
|
19182
20383
|
);
|
|
19183
20384
|
return operation;
|
|
19184
20385
|
}
|
|
20386
|
+
async _runRedo(markChanged) {
|
|
20387
|
+
this.assertReady();
|
|
20388
|
+
const entry = this._undo.takeRedo();
|
|
20389
|
+
if (!entry) return null;
|
|
20390
|
+
applyRedo(this.coreRuntime.state, entry);
|
|
20391
|
+
this._recordScheduleMutation(false);
|
|
20392
|
+
markChanged(true);
|
|
20393
|
+
if (needsResync(entry)) this._resyncCustomIdTrackerFromModel();
|
|
20394
|
+
this._undo.pushUndo(entry);
|
|
20395
|
+
this._undo.resetCoalesce();
|
|
20396
|
+
const changes = buildInverseChangeSet(
|
|
20397
|
+
this.coreRuntime.state,
|
|
20398
|
+
entry,
|
|
20399
|
+
"after"
|
|
20400
|
+
);
|
|
20401
|
+
this._saveTracker.recordChanges(
|
|
20402
|
+
changes.activities,
|
|
20403
|
+
changes.links,
|
|
20404
|
+
(activityId) => this.coreRuntime.state.getActivity(activityId),
|
|
20405
|
+
(linkId) => this.coreRuntime.state.getLink(linkId)
|
|
20406
|
+
);
|
|
20407
|
+
return this._reapplyViewState(changes) ?? changes;
|
|
20408
|
+
}
|
|
19185
20409
|
canUndo() {
|
|
19186
20410
|
return this._undo.canUndo();
|
|
19187
20411
|
}
|
|
@@ -19222,10 +20446,17 @@ var ScheduleCore = class {
|
|
|
19222
20446
|
);
|
|
19223
20447
|
}
|
|
19224
20448
|
}
|
|
19225
|
-
_rollback() {
|
|
20449
|
+
_rollback(generatorSnapshot) {
|
|
19226
20450
|
try {
|
|
19227
20451
|
this.coreRuntime.state.restoreFromCapture();
|
|
19228
20452
|
this.coreRuntime.customIdTracker.rollbackCustomIdTransaction();
|
|
20453
|
+
if (generatorSnapshot) {
|
|
20454
|
+
this.coreRuntime.activityIdGenerator.restore(generatorSnapshot[0]);
|
|
20455
|
+
this.coreRuntime.linkIdGenerator.restore(generatorSnapshot[1]);
|
|
20456
|
+
this.coreRuntime.uniqueCorrelativeIdGenerator.restore(
|
|
20457
|
+
generatorSnapshot[2]
|
|
20458
|
+
);
|
|
20459
|
+
}
|
|
19229
20460
|
} catch (restoreError) {
|
|
19230
20461
|
this._status = SCHEDULE_CORE_STATUS.POISONED;
|
|
19231
20462
|
this.coreRuntime.reporter.error(
|
|
@@ -19245,18 +20476,6 @@ function toPublicDispatchResult(result) {
|
|
|
19245
20476
|
return publicResult;
|
|
19246
20477
|
}
|
|
19247
20478
|
|
|
19248
|
-
// src/boundary/save/link-changes.ts
|
|
19249
|
-
function checkNoUpdatedLinks(baseline, current) {
|
|
19250
|
-
const baselineById = new Map(
|
|
19251
|
-
baseline.map((link) => [String(link.id), link])
|
|
19252
|
-
);
|
|
19253
|
-
return current.filter((link) => {
|
|
19254
|
-
const base = baselineById.get(String(link.id));
|
|
19255
|
-
if (!base) return false;
|
|
19256
|
-
return base.lag !== link.lag || base.type !== link.type;
|
|
19257
|
-
});
|
|
19258
|
-
}
|
|
19259
|
-
|
|
19260
20479
|
// src/boundary/save/unsaved.ts
|
|
19261
20480
|
var getUnsavedActivities = (activities = []) => (activities ?? []).filter((activity) => !activity.proplannerId);
|
|
19262
20481
|
|
|
@@ -19340,6 +20559,6 @@ var CREATION_KIND = {
|
|
|
19340
20559
|
ROOT: "root"
|
|
19341
20560
|
};
|
|
19342
20561
|
|
|
19343
|
-
export { ACTIVITY_TYPE, CALENDAR_UNIT, COLUMN, CONSTRAINT_TYPE2 as CONSTRAINT_TYPE, CONSTRAINT_TYPE_TO_LABEL, CREATION_KIND, DEFAULT_HOURS_PER_DAY, DISPATCH_ACTION_KIND, DISPATCH_ACTION_KINDS, DISPATCH_TRACK_EVENT, LINK_CODE_TO_TYPE, LINK_TYPE, LINK_TYPE_CODE, NEW_ACTIVITY_DEFAULTS, REJECTION_REASON, ROOT_PARENT_ID, ScheduleCore, WORK_TIME_DIRECTION, checkNoUpdatedLinks, computeExpectedProgress, expectedProgressFromBaseline, getActiveBaseline, getUnsavedActivities, isRootParent, normalizeParentKey, parseFromBackend, willRunCriticalPath, yieldToBrowser };
|
|
20562
|
+
export { ACTIVITY_TYPE, CALENDAR_UNIT, COLUMN, CONSTRAINT_TYPE2 as CONSTRAINT_TYPE, CONSTRAINT_TYPE_TO_LABEL, CREATION_KIND, DEFAULT_HOURS_PER_DAY, DISPATCH_ACTION_KIND, DISPATCH_ACTION_KINDS, DISPATCH_TRACK_EVENT, LINK_CODE_TO_TYPE, LINK_TYPE, LINK_TYPE_CODE, NEW_ACTIVITY_DEFAULTS, REJECTION_REASON, ROOT_PARENT_ID, SCHEDULE_CORE_STATUS, STATUS, ScheduleCore, WORK_TIME_DIRECTION, checkNoUpdatedLinks, computeExpectedProgress, expectedProgressFromBaseline, getActiveBaseline, getUnsavedActivities, isRootParent, normalizeParentKey, parseFromBackend, willRunCriticalPath, yieldToBrowser };
|
|
19344
20563
|
//# sourceMappingURL=index.js.map
|
|
19345
20564
|
//# sourceMappingURL=index.js.map
|