@outbuild-company/schedule-core 1.9.3 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cdn/schedule-core.global.js +1 -1
- package/dist/cdn/schedule-core.global.js.map +1 -1
- package/dist/index.cjs +126 -33
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -3
- package/dist/index.d.ts +10 -3
- package/dist/index.js +126 -33
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -338,8 +338,13 @@ var FIELD_REGISTRY = {
|
|
|
338
338
|
},
|
|
339
339
|
expectedProgressBaseline: {
|
|
340
340
|
valueKind: "number",
|
|
341
|
+
equalityPrecision: 2,
|
|
341
342
|
extract: (activity) => activity.expectedProgressBaseline
|
|
342
343
|
},
|
|
344
|
+
expectedProgress: {
|
|
345
|
+
valueKind: "number",
|
|
346
|
+
extract: (activity) => activity.expectedProgress
|
|
347
|
+
},
|
|
343
348
|
baselineDurationDays: {
|
|
344
349
|
valueKind: "number",
|
|
345
350
|
extract: (activity) => activity.baselineSnapshot?.durationDays ?? null
|
|
@@ -422,6 +427,9 @@ function toTargetDate(value) {
|
|
|
422
427
|
}
|
|
423
428
|
return new Date(Number.NaN);
|
|
424
429
|
}
|
|
430
|
+
function utcDayMs(date2) {
|
|
431
|
+
return Date.UTC(date2.getUTCFullYear(), date2.getUTCMonth(), date2.getUTCDate());
|
|
432
|
+
}
|
|
425
433
|
function matchString(value, target, operator) {
|
|
426
434
|
const isAbsent = value === null;
|
|
427
435
|
if (operator === "includes") {
|
|
@@ -434,24 +442,35 @@ function matchString(value, target, operator) {
|
|
|
434
442
|
if (operator === "isNot") return isAbsent || String(value) !== target;
|
|
435
443
|
return false;
|
|
436
444
|
}
|
|
437
|
-
function matchNumber(value, target, operator) {
|
|
445
|
+
function matchNumber(value, target, operator, equalityPrecision) {
|
|
438
446
|
if (value === null || typeof value !== "number") {
|
|
439
447
|
return operator === "notEquals";
|
|
440
448
|
}
|
|
441
|
-
|
|
442
|
-
if (operator === "
|
|
449
|
+
const equalityValue = equalityPrecision === void 0 ? value : Number(value.toFixed(equalityPrecision));
|
|
450
|
+
if (operator === "equals") return equalityValue === target;
|
|
451
|
+
if (operator === "notEquals") return equalityValue !== target;
|
|
443
452
|
if (operator === "greaterThan") return value > target;
|
|
444
453
|
if (operator === "lessThan") return value < target;
|
|
445
454
|
if (operator === "greaterOrEqual") return value >= target;
|
|
446
455
|
if (operator === "lessOrEqual") return value <= target;
|
|
447
456
|
return false;
|
|
448
457
|
}
|
|
458
|
+
function matchNumberBetween(value, minimum, maximum) {
|
|
459
|
+
return typeof value === "number" && value >= minimum && value <= maximum;
|
|
460
|
+
}
|
|
449
461
|
function matchDate(value, target, operator) {
|
|
450
462
|
if (!(value instanceof Date)) return false;
|
|
451
|
-
|
|
452
|
-
|
|
463
|
+
const valueDay = utcDayMs(value);
|
|
464
|
+
const targetDay = utcDayMs(target);
|
|
465
|
+
if (operator === "after") return valueDay > targetDay;
|
|
466
|
+
if (operator === "before") return valueDay < targetDay;
|
|
453
467
|
return false;
|
|
454
468
|
}
|
|
469
|
+
function matchDateBetween(value, minimum, maximum) {
|
|
470
|
+
if (!(value instanceof Date)) return false;
|
|
471
|
+
const day = utcDayMs(value);
|
|
472
|
+
return day >= utcDayMs(minimum) && day <= utcDayMs(maximum);
|
|
473
|
+
}
|
|
455
474
|
function matchIdArray(value, allowed, operator) {
|
|
456
475
|
const ids = Array.isArray(value) ? value : [];
|
|
457
476
|
const intersects = ids.some((id) => allowed.has(String(id)));
|
|
@@ -474,11 +493,33 @@ function matchCriterion(activity, criterion, context) {
|
|
|
474
493
|
if (descriptor === null) return false;
|
|
475
494
|
const value = descriptor.extract(activity, context);
|
|
476
495
|
const { operator } = criterion;
|
|
496
|
+
if (operator === "between") {
|
|
497
|
+
if (descriptor.valueKind === "number") {
|
|
498
|
+
return matchNumberBetween(
|
|
499
|
+
value,
|
|
500
|
+
Number(criterion.value),
|
|
501
|
+
Number(criterion.valueTo)
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
if (descriptor.valueKind === "date") {
|
|
505
|
+
return matchDateBetween(
|
|
506
|
+
value,
|
|
507
|
+
toTargetDate(criterion.value),
|
|
508
|
+
toTargetDate(criterion.valueTo)
|
|
509
|
+
);
|
|
510
|
+
}
|
|
511
|
+
return false;
|
|
512
|
+
}
|
|
477
513
|
if (descriptor.valueKind === "string") {
|
|
478
514
|
return matchString(value, String(criterion.value), operator);
|
|
479
515
|
}
|
|
480
516
|
if (descriptor.valueKind === "number") {
|
|
481
|
-
return matchNumber(
|
|
517
|
+
return matchNumber(
|
|
518
|
+
value,
|
|
519
|
+
Number(criterion.value),
|
|
520
|
+
operator,
|
|
521
|
+
descriptor.equalityPrecision
|
|
522
|
+
);
|
|
482
523
|
}
|
|
483
524
|
if (descriptor.valueKind === "date") {
|
|
484
525
|
return matchDate(value, toTargetDate(criterion.value), operator);
|
|
@@ -500,10 +541,10 @@ function matchesCriteria(activity, filter, context) {
|
|
|
500
541
|
);
|
|
501
542
|
}
|
|
502
543
|
function overlapsRange(activity, range) {
|
|
503
|
-
const taskStart = activity.startDate
|
|
504
|
-
const taskEnd = activity.endDate
|
|
505
|
-
const windowStart = range.start
|
|
506
|
-
const windowEnd = range.end
|
|
544
|
+
const taskStart = utcDayMs(activity.startDate);
|
|
545
|
+
const taskEnd = utcDayMs(activity.endDate);
|
|
546
|
+
const windowStart = utcDayMs(range.start);
|
|
547
|
+
const windowEnd = utcDayMs(range.end);
|
|
507
548
|
const fullyInside = taskStart >= windowStart && taskEnd <= windowEnd;
|
|
508
549
|
const startsInside = taskStart >= windowStart && taskStart <= windowEnd;
|
|
509
550
|
const windowStartsInside = windowStart >= taskStart && windowStart <= taskEnd;
|
|
@@ -653,9 +694,10 @@ var OPERATORS_BY_KIND = {
|
|
|
653
694
|
"greaterThan",
|
|
654
695
|
"lessThan",
|
|
655
696
|
"greaterOrEqual",
|
|
656
|
-
"lessOrEqual"
|
|
697
|
+
"lessOrEqual",
|
|
698
|
+
"between"
|
|
657
699
|
]),
|
|
658
|
-
date: /* @__PURE__ */ new Set(["after", "before"]),
|
|
700
|
+
date: /* @__PURE__ */ new Set(["after", "before", "between"]),
|
|
659
701
|
"id-array": /* @__PURE__ */ new Set(["someOf", "notSomeOf"]),
|
|
660
702
|
enum: /* @__PURE__ */ new Set(["someOf", "notSomeOf"]),
|
|
661
703
|
boolean: /* @__PURE__ */ new Set(["someOf", "notSomeOf"]),
|
|
@@ -686,6 +728,9 @@ function normalizeCriterion(criterion) {
|
|
|
686
728
|
if (!OPERATORS_BY_KIND[descriptor.valueKind].has(criterion.operator)) {
|
|
687
729
|
return { ok: false, reason: "unknown_operator" };
|
|
688
730
|
}
|
|
731
|
+
if (criterion.operator === "between") {
|
|
732
|
+
return normalizeBetweenCriterion(criterion, descriptor.valueKind);
|
|
733
|
+
}
|
|
689
734
|
if (descriptor.valueKind === "number") {
|
|
690
735
|
const value = normalizeNumberValue(criterion.value);
|
|
691
736
|
return value === null ? { ok: false, reason: "invalid_value" } : {
|
|
@@ -726,6 +771,31 @@ function normalizeCriterion(criterion) {
|
|
|
726
771
|
}
|
|
727
772
|
return { ok: true, criterion };
|
|
728
773
|
}
|
|
774
|
+
function normalizeBetweenCriterion(criterion, valueKind) {
|
|
775
|
+
if (valueKind === "number") {
|
|
776
|
+
const value = normalizeNumberValue(criterion.value);
|
|
777
|
+
const valueTo = normalizeNumberValue(criterion.valueTo);
|
|
778
|
+
if (value === null || valueTo === null || value > valueTo) {
|
|
779
|
+
return { ok: false, reason: "invalid_value" };
|
|
780
|
+
}
|
|
781
|
+
return {
|
|
782
|
+
ok: true,
|
|
783
|
+
criterion: { ...criterion, value, valueTo }
|
|
784
|
+
};
|
|
785
|
+
}
|
|
786
|
+
if (valueKind === "date") {
|
|
787
|
+
const value = normalizeDateValue(criterion.value);
|
|
788
|
+
const valueTo = normalizeDateValue(criterion.valueTo);
|
|
789
|
+
if (value === null || valueTo === null || value.getTime() > valueTo.getTime()) {
|
|
790
|
+
return { ok: false, reason: "invalid_value" };
|
|
791
|
+
}
|
|
792
|
+
return {
|
|
793
|
+
ok: true,
|
|
794
|
+
criterion: { ...criterion, value, valueTo }
|
|
795
|
+
};
|
|
796
|
+
}
|
|
797
|
+
return { ok: false, reason: "unknown_operator" };
|
|
798
|
+
}
|
|
729
799
|
function validateValueForKind(criterion, valueKind) {
|
|
730
800
|
const { value } = criterion;
|
|
731
801
|
if (valueKind === "boolean") {
|
|
@@ -1623,13 +1693,19 @@ function resolveExpansionAnchors(originalLink, adapter) {
|
|
|
1623
1693
|
userLag: originalLink.lag ?? 0,
|
|
1624
1694
|
sourceEndpointIsStart,
|
|
1625
1695
|
targetLag: targetEndpointIsFinish ? -endpointSpanHours(target, targetBounds, adapter) : 0,
|
|
1626
|
-
summarySourceId: originalLink.type === LINK_TYPE.START_TO_START && sourceBounds ? originalLink.source : void 0
|
|
1696
|
+
summarySourceId: originalLink.type === LINK_TYPE.START_TO_START && sourceBounds ? originalLink.source : void 0,
|
|
1697
|
+
finishAnchoredSummaryTargetId: targetEndpointIsFinish && targetBounds ? originalLink.target : void 0
|
|
1627
1698
|
};
|
|
1628
1699
|
}
|
|
1629
1700
|
function pushOffsetPreservingLinks(expanded, sourceIds, leafIds, originalLink, adapter, virtualIdCounter, linksByActivity) {
|
|
1630
1701
|
const anchors = resolveExpansionAnchors(originalLink, adapter);
|
|
1631
1702
|
const { source, sourceBounds, targetStart, userLag } = anchors;
|
|
1632
|
-
const {
|
|
1703
|
+
const {
|
|
1704
|
+
sourceEndpointIsStart,
|
|
1705
|
+
targetLag,
|
|
1706
|
+
summarySourceId,
|
|
1707
|
+
finishAnchoredSummaryTargetId
|
|
1708
|
+
} = anchors;
|
|
1633
1709
|
let counter = virtualIdCounter;
|
|
1634
1710
|
for (const srcId of sourceIds) {
|
|
1635
1711
|
const sourceLag = sourceEndpointIsStart ? sourceLagForLeaf(srcId, source, sourceBounds, adapter) : 0;
|
|
@@ -1652,7 +1728,7 @@ function pushOffsetPreservingLinks(expanded, sourceIds, leafIds, originalLink, a
|
|
|
1652
1728
|
targetLag,
|
|
1653
1729
|
userLag + offTarget,
|
|
1654
1730
|
summarySourceId,
|
|
1655
|
-
offTarget !== 0 && targetLag === 0 ? originalLink.target : void 0
|
|
1731
|
+
finishAnchoredSummaryTargetId ?? (offTarget !== 0 && targetLag === 0 ? originalLink.target : void 0)
|
|
1656
1732
|
)
|
|
1657
1733
|
);
|
|
1658
1734
|
counter += 1;
|
|
@@ -2100,7 +2176,7 @@ async function asapPass(orderedIds, links, adapter, options, isCurrent, plans) {
|
|
|
2100
2176
|
if (!maxStart || result.successorStart > maxStart) {
|
|
2101
2177
|
maxStart = result.successorStart;
|
|
2102
2178
|
drivingLinkId = String(link.id);
|
|
2103
|
-
drivingOffsetIsStale = link._summaryTargetId !== void 0 && !predecessorMovedThisRun;
|
|
2179
|
+
drivingOffsetIsStale = link._summaryTargetId !== void 0 && !predecessorMovedThisRun && (link._targetLag === 0 || options.preventSummaryTargetPullback === true);
|
|
2104
2180
|
}
|
|
2105
2181
|
}
|
|
2106
2182
|
const staleOffsetWouldPullBack = maxStart !== null && drivingOffsetIsStale && maxStart < activity.startDate;
|
|
@@ -9963,7 +10039,11 @@ async function runPostMutation(deps, args) {
|
|
|
9963
10039
|
if (passes.has(DERIVED_PASS.AUTOSCHEDULE)) {
|
|
9964
10040
|
await refreshMutatedParentBounds(deps.adapter, args);
|
|
9965
10041
|
}
|
|
9966
|
-
const schedule = passes.has(DERIVED_PASS.AUTOSCHEDULE) ? await runAutoschedule(
|
|
10042
|
+
const schedule = passes.has(DERIVED_PASS.AUTOSCHEDULE) ? await runAutoschedule(
|
|
10043
|
+
deps,
|
|
10044
|
+
args.autoscheduleFrom,
|
|
10045
|
+
args.preventSummaryTargetPullback
|
|
10046
|
+
) : emptySchedule();
|
|
9967
10047
|
await rollUpParentBounds(
|
|
9968
10048
|
deps.adapter,
|
|
9969
10049
|
args,
|
|
@@ -10034,8 +10114,11 @@ function collectFieldProgressInvalidations(adapter, beforeById, dirtySeeds, affe
|
|
|
10034
10114
|
}
|
|
10035
10115
|
}
|
|
10036
10116
|
}
|
|
10037
|
-
async function runAutoschedule(deps, autoscheduleFrom) {
|
|
10117
|
+
async function runAutoschedule(deps, autoscheduleFrom, preventSummaryTargetPullback = false) {
|
|
10038
10118
|
const options = autoscheduleFrom === "roots" ? {} : { triggerId: autoscheduleFrom };
|
|
10119
|
+
if (preventSummaryTargetPullback) {
|
|
10120
|
+
options.preventSummaryTargetPullback = true;
|
|
10121
|
+
}
|
|
10039
10122
|
const result = await deps.scheduler.schedule(options);
|
|
10040
10123
|
const outcome = captureScheduledRows(deps.adapter, result.updatedIds);
|
|
10041
10124
|
applyResults(deps.adapter, result);
|
|
@@ -11504,14 +11587,21 @@ async function createActivityCore(action, deps, opts = {}) {
|
|
|
11504
11587
|
recomputeUsedCostCascadeForActivity(newId, adapter);
|
|
11505
11588
|
recomputeCostCascadeForActivity(newId, adapter);
|
|
11506
11589
|
}
|
|
11507
|
-
|
|
11590
|
+
const correlativeShifts = recomputeCorrelatives(
|
|
11508
11591
|
adapter,
|
|
11509
11592
|
newId,
|
|
11510
|
-
beforeSnap,
|
|
11511
11593
|
initialTouched,
|
|
11512
11594
|
opts
|
|
11513
11595
|
);
|
|
11514
|
-
return {
|
|
11596
|
+
return {
|
|
11597
|
+
ok: true,
|
|
11598
|
+
newId,
|
|
11599
|
+
parent,
|
|
11600
|
+
newActivity,
|
|
11601
|
+
beforeSnap,
|
|
11602
|
+
initialTouched,
|
|
11603
|
+
correlativeShifts
|
|
11604
|
+
};
|
|
11515
11605
|
}
|
|
11516
11606
|
function validateCreateTarget(action, adapter) {
|
|
11517
11607
|
const isRoot = isRootParent(action.parentId);
|
|
@@ -11606,20 +11696,16 @@ function applyParentMutations(action, newId, parent, adapter, parentWasLeaf) {
|
|
|
11606
11696
|
);
|
|
11607
11697
|
}
|
|
11608
11698
|
}
|
|
11609
|
-
function
|
|
11610
|
-
if (opts.skipCorrelativeRecompute) return;
|
|
11611
|
-
const
|
|
11612
|
-
|
|
11613
|
-
foldCorrelativeShifts(
|
|
11614
|
-
adapter,
|
|
11615
|
-
correlativeShifts,
|
|
11616
|
-
/* @__PURE__ */ new Set([String(newId)]),
|
|
11617
|
-
beforeSnap,
|
|
11618
|
-
initialTouched
|
|
11699
|
+
function recomputeCorrelatives(adapter, newId, initialTouched, opts) {
|
|
11700
|
+
if (opts.skipCorrelativeRecompute) return [];
|
|
11701
|
+
const shifts = recomputeCorrelativeIds(adapter).filter(
|
|
11702
|
+
(shift) => shift.activityId !== String(newId)
|
|
11619
11703
|
);
|
|
11704
|
+
for (const shift of shifts) initialTouched.add(shift.activityId);
|
|
11705
|
+
return shifts;
|
|
11620
11706
|
}
|
|
11621
11707
|
async function buildCreateChangeSet(adapter, action, coreResult, scheduledIds, hoursPerDay) {
|
|
11622
|
-
const { newId, newActivity, beforeSnap, initialTouched } = coreResult;
|
|
11708
|
+
const { newId, newActivity, beforeSnap, initialTouched, correlativeShifts } = coreResult;
|
|
11623
11709
|
const trackingEvent = {
|
|
11624
11710
|
name: DISPATCH_TRACK_EVENT.ACTIVITY_CREATION,
|
|
11625
11711
|
properties: {
|
|
@@ -11636,6 +11722,7 @@ async function buildCreateChangeSet(adapter, action, coreResult, scheduledIds, h
|
|
|
11636
11722
|
beforeSnap,
|
|
11637
11723
|
touchedIds: initialTouched,
|
|
11638
11724
|
scheduledIds,
|
|
11725
|
+
correlativeShifts,
|
|
11639
11726
|
trackingEvents: [trackingEvent]});
|
|
11640
11727
|
}
|
|
11641
11728
|
async function dispatchActivityCreate(action, options, deps) {
|
|
@@ -11664,8 +11751,9 @@ async function dispatchActivityCreate(action, options, deps) {
|
|
|
11664
11751
|
},
|
|
11665
11752
|
{
|
|
11666
11753
|
action,
|
|
11667
|
-
autoscheduleFrom:
|
|
11754
|
+
autoscheduleFrom: newId,
|
|
11668
11755
|
recomputeParentsFrom: [newId],
|
|
11756
|
+
preventSummaryTargetPullback: true,
|
|
11669
11757
|
now: deps.now,
|
|
11670
11758
|
options
|
|
11671
11759
|
}
|
|
@@ -21352,6 +21440,11 @@ var ScheduleCore = class _ScheduleCore {
|
|
|
21352
21440
|
this.assertReady();
|
|
21353
21441
|
return this.coreRuntime.state.hiddenIds().map(String);
|
|
21354
21442
|
}
|
|
21443
|
+
getVisibleActivityIds() {
|
|
21444
|
+
this.assertReady();
|
|
21445
|
+
const hiddenIds = new Set(this.coreRuntime.state.hiddenIds().map(String));
|
|
21446
|
+
return this.coreRuntime.state.getAllIds().map(String).filter((activityId) => !hiddenIds.has(activityId));
|
|
21447
|
+
}
|
|
21355
21448
|
getActiveFilter() {
|
|
21356
21449
|
this.assertReady();
|
|
21357
21450
|
return cloneDomainValue(this.coreRuntime.state.getActiveFilter());
|