@outbuild-company/schedule-core 1.26.0 → 1.26.1
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 +17 -0
- package/dist/build-fingerprint.json +5 -0
- package/dist/cdn/schedule-core.global.js +1 -1
- package/dist/cdn/schedule-core.global.js.map +1 -1
- package/dist/index.cjs +1263 -635
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1263 -635
- package/dist/index.js.map +1 -1
- package/package.json +14 -9
package/dist/index.cjs
CHANGED
|
@@ -1,16 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
// src/activity-types/constants.ts
|
|
4
|
-
var ACTIVITY_TYPE = {
|
|
5
|
-
TASK: "task",
|
|
6
|
-
PROJECT: "project",
|
|
7
|
-
MILESTONE: "milestone"
|
|
8
|
-
};
|
|
9
|
-
var ACTIVITY_TYPES = Object.values(ACTIVITY_TYPE);
|
|
10
|
-
function isActivityType(value) {
|
|
11
|
-
return ACTIVITY_TYPES.includes(value);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
3
|
// src/types.ts
|
|
15
4
|
var NOTIFICATION_TYPE = {
|
|
16
5
|
CONSTRAINT: "constraint"};
|
|
@@ -692,7 +681,10 @@ function createLinksApi(engine) {
|
|
|
692
681
|
}
|
|
693
682
|
function createScheduleNamespaces(engine) {
|
|
694
683
|
const applyBaselinePoints2 = (points, options) => engine.dispatch(
|
|
695
|
-
{
|
|
684
|
+
{
|
|
685
|
+
kind: DISPATCH_ACTION_KIND.BASELINE_APPLY,
|
|
686
|
+
points
|
|
687
|
+
},
|
|
696
688
|
options
|
|
697
689
|
);
|
|
698
690
|
return {
|
|
@@ -1076,6 +1068,17 @@ function dispatchVisibilitySet(action, deps) {
|
|
|
1076
1068
|
return { ok: true, changes };
|
|
1077
1069
|
}
|
|
1078
1070
|
|
|
1071
|
+
// src/activity-types/constants.ts
|
|
1072
|
+
var ACTIVITY_TYPE = {
|
|
1073
|
+
TASK: "task",
|
|
1074
|
+
PROJECT: "project",
|
|
1075
|
+
MILESTONE: "milestone"
|
|
1076
|
+
};
|
|
1077
|
+
var ACTIVITY_TYPES = Object.values(ACTIVITY_TYPE);
|
|
1078
|
+
function isActivityType(value) {
|
|
1079
|
+
return ACTIVITY_TYPES.includes(value);
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1079
1082
|
// src/autoscheduler/constants.ts
|
|
1080
1083
|
var TIMING = {
|
|
1081
1084
|
YIELD_SLICE_MS: 8
|
|
@@ -2442,6 +2445,7 @@ var ACTIVITY_PROPERTY = {
|
|
|
2442
2445
|
DURATION_HOURS: "durationHours",
|
|
2443
2446
|
CONSTRAINT_TYPE: "constraintType",
|
|
2444
2447
|
CONSTRAINT_DATE: "constraintDate",
|
|
2448
|
+
CALENDAR_ID: "calendarId",
|
|
2445
2449
|
PROGRESS: "progress",
|
|
2446
2450
|
COST: "cost",
|
|
2447
2451
|
USED_COST: "usedCost",
|
|
@@ -2572,6 +2576,17 @@ function filterTopoOrder(order, scopedIds) {
|
|
|
2572
2576
|
return filtered;
|
|
2573
2577
|
}
|
|
2574
2578
|
|
|
2579
|
+
// src/constants/progress.ts
|
|
2580
|
+
var NOT_STARTED_PROGRESS = 0;
|
|
2581
|
+
var COMPLETED_PROGRESS = 100;
|
|
2582
|
+
var MAX_TOLERATED_PROGRESS = COMPLETED_PROGRESS + Number.EPSILON * COMPLETED_PROGRESS * 2;
|
|
2583
|
+
function isCompletedProgress(progress) {
|
|
2584
|
+
return progress >= COMPLETED_PROGRESS && progress <= MAX_TOLERATED_PROGRESS;
|
|
2585
|
+
}
|
|
2586
|
+
function isAutoSchedulingEnabledForProgress(progress) {
|
|
2587
|
+
return progress === NOT_STARTED_PROGRESS;
|
|
2588
|
+
}
|
|
2589
|
+
|
|
2575
2590
|
// src/autoscheduler/utils/parent-link-expansion.ts
|
|
2576
2591
|
function isSummary2(id, adapter) {
|
|
2577
2592
|
const activity = adapter.getActivity(id);
|
|
@@ -2751,12 +2766,8 @@ function deriveSummaryBoundsWithDates(summaryId, adapter, resolveDates) {
|
|
|
2751
2766
|
if (earliestStart === null || latestEnd === null) return null;
|
|
2752
2767
|
return { startDate: earliestStart, endDate: latestEnd };
|
|
2753
2768
|
}
|
|
2754
|
-
function deriveSummaryBounds(summaryId, adapter) {
|
|
2755
|
-
return deriveSummaryBoundsWithDates(summaryId, adapter,
|
|
2756
|
-
const leaf = adapter.getActivity(leafId);
|
|
2757
|
-
if (!leaf) return null;
|
|
2758
|
-
return { startDate: leaf.startDate, endDate: leaf.endDate };
|
|
2759
|
-
});
|
|
2769
|
+
function deriveSummaryBounds(summaryId, adapter, resolveDates = (leafId) => adapter.getActivity(leafId)) {
|
|
2770
|
+
return deriveSummaryBoundsWithDates(summaryId, adapter, resolveDates);
|
|
2760
2771
|
}
|
|
2761
2772
|
function endpointSpanHours(endpoint, bounds, adapter) {
|
|
2762
2773
|
if (!endpoint) return 0;
|
|
@@ -2782,31 +2793,48 @@ function hasIncomingRawLink(leafId, linksByActivity) {
|
|
|
2782
2793
|
const bucket = linksByActivity.get(leafKey) ?? [];
|
|
2783
2794
|
return bucket.some((rawLink) => String(rawLink.target) === leafKey);
|
|
2784
2795
|
}
|
|
2785
|
-
function targetOffsetForLeaf(leafId, targetStart,
|
|
2786
|
-
if (hasIncomingRawLink(leafId, linksByActivity))
|
|
2796
|
+
function targetOffsetForLeaf(leafId, targetStart, adapter, linksByActivity, targetEndpointIsFinish) {
|
|
2797
|
+
if (!targetEndpointIsFinish && hasIncomingRawLink(leafId, linksByActivity))
|
|
2798
|
+
return 0;
|
|
2787
2799
|
const leaf = adapter.getActivity(leafId);
|
|
2788
|
-
if (!targetStart || !leaf
|
|
2800
|
+
if (!targetStart || !leaf) return 0;
|
|
2789
2801
|
return adapter.calculateDuration({
|
|
2790
2802
|
startDate: targetStart,
|
|
2791
2803
|
endDate: leaf.startDate,
|
|
2792
|
-
task:
|
|
2804
|
+
task: leaf
|
|
2793
2805
|
});
|
|
2794
2806
|
}
|
|
2795
2807
|
function resolveExpansionAnchors(originalLink, adapter) {
|
|
2796
2808
|
const source = adapter.getActivity(originalLink.source);
|
|
2797
2809
|
const target = adapter.getActivity(originalLink.target);
|
|
2798
2810
|
const sourceBounds = deriveSummaryBounds(originalLink.source, adapter);
|
|
2799
|
-
const
|
|
2811
|
+
const fullTargetBounds = deriveSummaryBounds(originalLink.target, adapter);
|
|
2812
|
+
const targetBounds = deriveSummaryBoundsWithDates(
|
|
2813
|
+
originalLink.target,
|
|
2814
|
+
adapter,
|
|
2815
|
+
(leafId) => {
|
|
2816
|
+
const leaf = adapter.getActivity(leafId);
|
|
2817
|
+
if (!leaf) return null;
|
|
2818
|
+
const hasFixedDate = leaf.constraintDate !== null && (leaf.constraintType === CONSTRAINT_TYPE.MSO || leaf.constraintType === CONSTRAINT_TYPE.MFO);
|
|
2819
|
+
const canSchedule = leaf.autoScheduling && leaf.progress !== COMPLETED_PROGRESS && !hasFixedDate;
|
|
2820
|
+
if (!canSchedule) return null;
|
|
2821
|
+
return { startDate: leaf.startDate, endDate: leaf.endDate };
|
|
2822
|
+
}
|
|
2823
|
+
);
|
|
2800
2824
|
const sourceEndpointIsStart = originalLink.type === LINK_TYPE.START_TO_START || originalLink.type === LINK_TYPE.START_TO_FINISH;
|
|
2801
2825
|
const targetEndpointIsFinish = originalLink.type === LINK_TYPE.FINISH_TO_FINISH || originalLink.type === LINK_TYPE.START_TO_FINISH;
|
|
2802
2826
|
return {
|
|
2803
2827
|
source,
|
|
2804
2828
|
sourceBounds,
|
|
2805
2829
|
targetStart: targetBounds?.startDate ?? target?.startDate,
|
|
2830
|
+
targetBounds,
|
|
2831
|
+
hasFrozenTargetStart: Boolean(
|
|
2832
|
+
fullTargetBounds && targetBounds && fullTargetBounds.startDate < targetBounds.startDate
|
|
2833
|
+
),
|
|
2834
|
+
targetEndpointIsFinish,
|
|
2806
2835
|
userLag: originalLink.lag ?? 0,
|
|
2807
2836
|
sourceEndpointIsStart,
|
|
2808
|
-
|
|
2809
|
-
summarySourceId: originalLink.type === LINK_TYPE.START_TO_START && sourceBounds ? originalLink.source : void 0,
|
|
2837
|
+
summarySourceId: sourceEndpointIsStart && sourceBounds ? originalLink.source : void 0,
|
|
2810
2838
|
finishAnchoredSummaryTargetId: targetEndpointIsFinish && targetBounds ? originalLink.target : void 0
|
|
2811
2839
|
};
|
|
2812
2840
|
}
|
|
@@ -2815,7 +2843,9 @@ function pushOffsetPreservingLinks(expanded, sourceIds, leafIds, originalLink, a
|
|
|
2815
2843
|
const { source, sourceBounds, targetStart, userLag } = anchors;
|
|
2816
2844
|
const {
|
|
2817
2845
|
sourceEndpointIsStart,
|
|
2818
|
-
|
|
2846
|
+
targetBounds,
|
|
2847
|
+
targetEndpointIsFinish,
|
|
2848
|
+
hasFrozenTargetStart,
|
|
2819
2849
|
summarySourceId,
|
|
2820
2850
|
finishAnchoredSummaryTargetId
|
|
2821
2851
|
} = anchors;
|
|
@@ -2824,12 +2854,13 @@ function pushOffsetPreservingLinks(expanded, sourceIds, leafIds, originalLink, a
|
|
|
2824
2854
|
const sourceLag = sourceEndpointIsStart ? sourceLagForLeaf(srcId, source, sourceBounds, adapter) : 0;
|
|
2825
2855
|
for (const tgtId of leafIds) {
|
|
2826
2856
|
if (String(srcId) === String(tgtId)) continue;
|
|
2857
|
+
const targetLag = targetEndpointIsFinish ? -endpointSpanHours(adapter.getActivity(tgtId), targetBounds, adapter) : 0;
|
|
2827
2858
|
const offTarget = targetOffsetForLeaf(
|
|
2828
2859
|
tgtId,
|
|
2829
2860
|
targetStart,
|
|
2830
|
-
source,
|
|
2831
2861
|
adapter,
|
|
2832
|
-
linksByActivity
|
|
2862
|
+
linksByActivity,
|
|
2863
|
+
targetEndpointIsFinish
|
|
2833
2864
|
);
|
|
2834
2865
|
expanded.push(
|
|
2835
2866
|
buildVirtualLink(
|
|
@@ -2841,7 +2872,8 @@ function pushOffsetPreservingLinks(expanded, sourceIds, leafIds, originalLink, a
|
|
|
2841
2872
|
targetLag,
|
|
2842
2873
|
userLag + offTarget,
|
|
2843
2874
|
summarySourceId,
|
|
2844
|
-
finishAnchoredSummaryTargetId ?? (offTarget !== 0 && targetLag === 0 ? originalLink.target : void 0)
|
|
2875
|
+
finishAnchoredSummaryTargetId ?? ((offTarget !== 0 || hasFrozenTargetStart) && targetLag === 0 ? originalLink.target : void 0),
|
|
2876
|
+
targetBounds ? originalLink.target : void 0
|
|
2845
2877
|
)
|
|
2846
2878
|
);
|
|
2847
2879
|
counter += 1;
|
|
@@ -2849,7 +2881,7 @@ function pushOffsetPreservingLinks(expanded, sourceIds, leafIds, originalLink, a
|
|
|
2849
2881
|
}
|
|
2850
2882
|
return counter;
|
|
2851
2883
|
}
|
|
2852
|
-
function buildVirtualLink(originalLink, sourceId, targetId, counter, sourceLag, targetLag, trueLag, summarySourceId, offsetSummaryTargetId) {
|
|
2884
|
+
function buildVirtualLink(originalLink, sourceId, targetId, counter, sourceLag, targetLag, trueLag, summarySourceId, offsetSummaryTargetId, lagActivityId) {
|
|
2853
2885
|
return {
|
|
2854
2886
|
id: `virtual_${originalLink.id}_${counter}`,
|
|
2855
2887
|
source: sourceId,
|
|
@@ -2858,6 +2890,7 @@ function buildVirtualLink(originalLink, sourceId, targetId, counter, sourceLag,
|
|
|
2858
2890
|
lag: originalLink.lag,
|
|
2859
2891
|
freeSlackHours: null,
|
|
2860
2892
|
isCritical: false,
|
|
2893
|
+
...lagActivityId === void 0 ? {} : { _lagActivityId: lagActivityId },
|
|
2861
2894
|
_sourceLag: sourceLag,
|
|
2862
2895
|
_targetLag: targetLag,
|
|
2863
2896
|
_trueLag: trueLag,
|
|
@@ -2928,17 +2961,6 @@ function findConnectedGroupForTrigger(triggerId, links) {
|
|
|
2928
2961
|
return { activityIds, links: groupLinks };
|
|
2929
2962
|
}
|
|
2930
2963
|
|
|
2931
|
-
// src/constants/progress.ts
|
|
2932
|
-
var NOT_STARTED_PROGRESS = 0;
|
|
2933
|
-
var COMPLETED_PROGRESS = 100;
|
|
2934
|
-
var MAX_TOLERATED_PROGRESS = COMPLETED_PROGRESS + Number.EPSILON * COMPLETED_PROGRESS * 2;
|
|
2935
|
-
function isCompletedProgress(progress) {
|
|
2936
|
-
return progress >= COMPLETED_PROGRESS && progress <= MAX_TOLERATED_PROGRESS;
|
|
2937
|
-
}
|
|
2938
|
-
function isAutoSchedulingEnabledForProgress(progress) {
|
|
2939
|
-
return progress === NOT_STARTED_PROGRESS;
|
|
2940
|
-
}
|
|
2941
|
-
|
|
2942
2964
|
// src/autoscheduler/engine/link-calculator.ts
|
|
2943
2965
|
var MILLISECONDS_PER_HOUR = 36e5;
|
|
2944
2966
|
var INSTANT_MILLISECONDS = 1;
|
|
@@ -3016,11 +3038,15 @@ function normalize(predecessor, successor, link) {
|
|
|
3016
3038
|
};
|
|
3017
3039
|
}
|
|
3018
3040
|
}
|
|
3019
|
-
function summaryAnchoredSourceLag(link, predecessor, adapter) {
|
|
3041
|
+
function summaryAnchoredSourceLag(link, predecessor, adapter, resolveDates) {
|
|
3020
3042
|
if (link._summarySourceId === void 0) return null;
|
|
3021
3043
|
const summarySource = adapter.getActivity(link._summarySourceId);
|
|
3022
3044
|
if (!summarySource) return null;
|
|
3023
|
-
const summaryBounds = deriveSummaryBounds(
|
|
3045
|
+
const summaryBounds = deriveSummaryBounds(
|
|
3046
|
+
link._summarySourceId,
|
|
3047
|
+
adapter,
|
|
3048
|
+
resolveDates
|
|
3049
|
+
);
|
|
3024
3050
|
if (!summaryBounds) return null;
|
|
3025
3051
|
return -adapter.calculateDuration({
|
|
3026
3052
|
startDate: summaryBounds.startDate,
|
|
@@ -3065,7 +3091,7 @@ function reverseRelationshipLagAnchor(successor, relationshipLagTask, adapter) {
|
|
|
3065
3091
|
task: relationshipLagTask
|
|
3066
3092
|
});
|
|
3067
3093
|
}
|
|
3068
|
-
function calculateSuccessorStartFromLink(predecessor, successor, link, adapter, trueLagTask = successor) {
|
|
3094
|
+
function calculateSuccessorStartFromLink(predecessor, successor, link, adapter, trueLagTask = successor, resolveDates) {
|
|
3069
3095
|
const {
|
|
3070
3096
|
sourceLag: frozenSourceLag,
|
|
3071
3097
|
targetLag,
|
|
@@ -3073,11 +3099,12 @@ function calculateSuccessorStartFromLink(predecessor, successor, link, adapter,
|
|
|
3073
3099
|
isFS,
|
|
3074
3100
|
isFF
|
|
3075
3101
|
} = normalize(predecessor, successor, link);
|
|
3076
|
-
const sourceLag = summaryAnchoredSourceLag(link, predecessor, adapter) ?? frozenSourceLag;
|
|
3102
|
+
const sourceLag = summaryAnchoredSourceLag(link, predecessor, adapter, resolveDates) ?? frozenSourceLag;
|
|
3103
|
+
const lagActivity = link._lagActivityId === void 0 ? null : adapter.getActivity(link._lagActivityId);
|
|
3077
3104
|
const totalLag = sourceLag + targetLag + trueLag;
|
|
3078
3105
|
const isZeroDurationSuccessor = successor.durationHours === 0;
|
|
3079
3106
|
const hasLag = isZeroDurationSuccessor ? totalLag !== 0 : sourceLag !== 0 || targetLag !== 0 || trueLag !== 0;
|
|
3080
|
-
if (!hasLag) {
|
|
3107
|
+
if (!hasLag && (!lagActivity || isZeroDurationSuccessor && sourceLag === 0 && targetLag === 0 && trueLag === 0)) {
|
|
3081
3108
|
return noLagSuccessorStart(
|
|
3082
3109
|
predecessor,
|
|
3083
3110
|
successor,
|
|
@@ -3086,7 +3113,7 @@ function calculateSuccessorStartFromLink(predecessor, successor, link, adapter,
|
|
|
3086
3113
|
isFS || isFF
|
|
3087
3114
|
);
|
|
3088
3115
|
}
|
|
3089
|
-
const baseTask = isFS ? successor : predecessor;
|
|
3116
|
+
const baseTask = isFS ? lagActivity ?? successor : predecessor;
|
|
3090
3117
|
let date2 = relationshipLagAnchor(predecessor, baseTask, trueLagTask, adapter);
|
|
3091
3118
|
if (sourceLag !== 0) {
|
|
3092
3119
|
date2 = adapter.calculateEndDate({
|
|
@@ -3095,15 +3122,30 @@ function calculateSuccessorStartFromLink(predecessor, successor, link, adapter,
|
|
|
3095
3122
|
task: predecessor
|
|
3096
3123
|
});
|
|
3097
3124
|
}
|
|
3098
|
-
if (
|
|
3099
|
-
date2 = adapter
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3125
|
+
if (lagActivity) {
|
|
3126
|
+
date2 = addTrueLag(date2, link.lag ?? 0, lagActivity, adapter);
|
|
3127
|
+
date2 = adapter.getClosestWorkTime({
|
|
3128
|
+
date: date2,
|
|
3129
|
+
dir: isFS || link.type === LINK_TYPE.START_TO_START ? "future" : "past",
|
|
3130
|
+
task: lagActivity
|
|
3103
3131
|
});
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3132
|
+
const leafOffset = targetLag + trueLag - (link.lag ?? 0);
|
|
3133
|
+
if (leafOffset !== 0) {
|
|
3134
|
+
date2 = adapter.calculateEndDate({
|
|
3135
|
+
startDate: date2,
|
|
3136
|
+
durationHours: leafOffset,
|
|
3137
|
+
task: successor
|
|
3138
|
+
});
|
|
3139
|
+
}
|
|
3140
|
+
} else {
|
|
3141
|
+
if (targetLag !== 0) {
|
|
3142
|
+
date2 = adapter.calculateEndDate({
|
|
3143
|
+
startDate: date2,
|
|
3144
|
+
durationHours: targetLag,
|
|
3145
|
+
task: successor
|
|
3146
|
+
});
|
|
3147
|
+
}
|
|
3148
|
+
if (trueLag !== 0) date2 = addTrueLag(date2, trueLag, trueLagTask, adapter);
|
|
3107
3149
|
}
|
|
3108
3150
|
if (successor.durationHours === 0) {
|
|
3109
3151
|
if (isFS || isFF) {
|
|
@@ -3143,16 +3185,25 @@ function calculatePredecessorEndFromLink(successor, predecessor, link, adapter,
|
|
|
3143
3185
|
successor,
|
|
3144
3186
|
link
|
|
3145
3187
|
);
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3188
|
+
const lagActivity = link._lagActivityId === void 0 ? null : adapter.getActivity(link._lagActivityId);
|
|
3189
|
+
let date2 = lagActivity ? new Date(successor.startDate) : reverseRelationshipLagAnchor(successor, trueLagTask, adapter);
|
|
3190
|
+
if (lagActivity) {
|
|
3191
|
+
const leafOffset = targetLag + trueLag - (link.lag ?? 0);
|
|
3192
|
+
if (leafOffset !== 0)
|
|
3193
|
+
date2 = adapter.calculateEndDate({
|
|
3194
|
+
startDate: date2,
|
|
3195
|
+
durationHours: -leafOffset,
|
|
3196
|
+
task: successor
|
|
3197
|
+
});
|
|
3198
|
+
date2 = addTrueLag(date2, -(link.lag ?? 0), lagActivity, adapter);
|
|
3199
|
+
} else {
|
|
3200
|
+
if (trueLag !== 0) date2 = addTrueLag(date2, -trueLag, trueLagTask, adapter);
|
|
3201
|
+
if (targetLag !== 0)
|
|
3202
|
+
date2 = adapter.calculateEndDate({
|
|
3203
|
+
startDate: date2,
|
|
3204
|
+
durationHours: -targetLag,
|
|
3205
|
+
task: successor
|
|
3206
|
+
});
|
|
3156
3207
|
}
|
|
3157
3208
|
if (sourceLag !== 0) {
|
|
3158
3209
|
date2 = adapter.calculateEndDate({
|
|
@@ -3254,8 +3305,71 @@ function shouldSkipLagForMultiDrag(predecessorId, flags, draggedIds) {
|
|
|
3254
3305
|
return flags.dragWithMultiple && isPredecessorBeingDragged(predecessorId, draggedIds);
|
|
3255
3306
|
}
|
|
3256
3307
|
|
|
3308
|
+
// src/autoscheduler/engine/summary-finish-groups.ts
|
|
3309
|
+
function collectSummaryFinishGroups(links, adapter, resolveDates) {
|
|
3310
|
+
const groups = /* @__PURE__ */ new Map();
|
|
3311
|
+
for (const link of links) {
|
|
3312
|
+
if (link.type !== LINK_TYPE.FINISH_TO_FINISH && link.type !== LINK_TYPE.START_TO_FINISH)
|
|
3313
|
+
continue;
|
|
3314
|
+
const summaryId = link._summaryTargetId;
|
|
3315
|
+
if (summaryId === void 0) continue;
|
|
3316
|
+
if (groups.has(summaryId)) continue;
|
|
3317
|
+
let independentlyDriven = false;
|
|
3318
|
+
const starts = /* @__PURE__ */ new Map();
|
|
3319
|
+
let movableEnd = null;
|
|
3320
|
+
let movableLeafId = null;
|
|
3321
|
+
const bounds = deriveSummaryBounds(summaryId, adapter, (id) => {
|
|
3322
|
+
const leaf = adapter.getActivity(id);
|
|
3323
|
+
if (!leaf) return null;
|
|
3324
|
+
const dates = resolveDates(id);
|
|
3325
|
+
starts.set(id, dates.startDate);
|
|
3326
|
+
if (!leaf.autoScheduling || leaf.progress === COMPLETED_PROGRESS || leaf.constraintType !== CONSTRAINT_TYPE.ASAP)
|
|
3327
|
+
independentlyDriven = true;
|
|
3328
|
+
for (const linkId of adapter.getIncomingLinkIds(id)) {
|
|
3329
|
+
const incoming = adapter.getLink(linkId);
|
|
3330
|
+
if (incoming && String(incoming.source) !== String(summaryId) && !adapter.isChildOf(incoming.source, summaryId))
|
|
3331
|
+
independentlyDriven = true;
|
|
3332
|
+
}
|
|
3333
|
+
const hasFixedDate = leaf.constraintDate !== null && (leaf.constraintType === CONSTRAINT_TYPE.MSO || leaf.constraintType === CONSTRAINT_TYPE.MFO);
|
|
3334
|
+
const movable = leaf.autoScheduling && leaf.progress !== COMPLETED_PROGRESS && !hasFixedDate;
|
|
3335
|
+
if (movable && (movableEnd === null || dates.endDate > movableEnd || dates.endDate.getTime() === movableEnd.getTime() && id < (movableLeafId ?? id))) {
|
|
3336
|
+
movableEnd = dates.endDate;
|
|
3337
|
+
movableLeafId = id;
|
|
3338
|
+
}
|
|
3339
|
+
return dates;
|
|
3340
|
+
});
|
|
3341
|
+
const drivingLeafIds = /* @__PURE__ */ new Set();
|
|
3342
|
+
const pending = movableLeafId === null ? [] : [movableLeafId];
|
|
3343
|
+
while (pending.length > 0) {
|
|
3344
|
+
const id = pending.pop();
|
|
3345
|
+
if (drivingLeafIds.has(id)) continue;
|
|
3346
|
+
drivingLeafIds.add(id);
|
|
3347
|
+
for (const linkId of [
|
|
3348
|
+
...adapter.getIncomingLinkIds(id),
|
|
3349
|
+
...adapter.getOutgoingLinkIds(id)
|
|
3350
|
+
]) {
|
|
3351
|
+
const link2 = adapter.getLink(linkId);
|
|
3352
|
+
if (!link2) continue;
|
|
3353
|
+
const neighbor = String(link2.source) === String(id) ? link2.target : link2.source;
|
|
3354
|
+
if (starts.has(neighbor) && !drivingLeafIds.has(neighbor))
|
|
3355
|
+
pending.push(neighbor);
|
|
3356
|
+
}
|
|
3357
|
+
}
|
|
3358
|
+
groups.set(
|
|
3359
|
+
summaryId,
|
|
3360
|
+
independentlyDriven && bounds ? {
|
|
3361
|
+
endDate: bounds.endDate,
|
|
3362
|
+
movableEnd,
|
|
3363
|
+
starts,
|
|
3364
|
+
drivingLeafIds
|
|
3365
|
+
} : null
|
|
3366
|
+
);
|
|
3367
|
+
}
|
|
3368
|
+
return groups;
|
|
3369
|
+
}
|
|
3370
|
+
|
|
3257
3371
|
// src/autoscheduler/engine/asap-pass.ts
|
|
3258
|
-
async function asapPass(orderedIds, links, adapter, options, isCurrent, plans) {
|
|
3372
|
+
async function asapPass(orderedIds, links, adapter, options, isCurrent, plans, deferSummaryFinishes = false) {
|
|
3259
3373
|
const incomingLinks = /* @__PURE__ */ new Map();
|
|
3260
3374
|
for (const link of links) {
|
|
3261
3375
|
const key = String(link.target);
|
|
@@ -3271,6 +3385,11 @@ async function asapPass(orderedIds, links, adapter, options, isCurrent, plans) {
|
|
|
3271
3385
|
if (snap) return { startDate: snap.startDate, endDate: snap.endDate };
|
|
3272
3386
|
return { startDate: /* @__PURE__ */ new Date(), endDate: /* @__PURE__ */ new Date() };
|
|
3273
3387
|
};
|
|
3388
|
+
const summaryFinishes = collectSummaryFinishGroups(
|
|
3389
|
+
links,
|
|
3390
|
+
adapter,
|
|
3391
|
+
getActivityDates
|
|
3392
|
+
);
|
|
3274
3393
|
const flags = adapter.getFlags();
|
|
3275
3394
|
const draggedIds = options.draggedIds ?? [];
|
|
3276
3395
|
let sliceStart = performance.now();
|
|
@@ -3307,21 +3426,60 @@ async function asapPass(orderedIds, links, adapter, options, isCurrent, plans) {
|
|
|
3307
3426
|
startDate: multiDragDates.startDate,
|
|
3308
3427
|
endDate: multiDragDates.endDate
|
|
3309
3428
|
};
|
|
3310
|
-
|
|
3429
|
+
let effectiveLink = shouldSkipLagForMultiDrag(
|
|
3311
3430
|
link.source,
|
|
3312
3431
|
flags,
|
|
3313
3432
|
draggedIds
|
|
3314
3433
|
) ? { ...link, lag: 0 } : link;
|
|
3434
|
+
const summaryFinish = effectiveLink._summaryTargetId === void 0 || effectiveLink.type !== LINK_TYPE.FINISH_TO_FINISH && effectiveLink.type !== LINK_TYPE.START_TO_FINISH ? null : summaryFinishes.get(effectiveLink._summaryTargetId);
|
|
3435
|
+
if (summaryFinish) {
|
|
3436
|
+
if (deferSummaryFinishes) continue;
|
|
3437
|
+
const requiredFinish = calculateSuccessorStartFromLink(
|
|
3438
|
+
adjustedPred,
|
|
3439
|
+
{ ...activity, durationHours: 0 },
|
|
3440
|
+
{ ...effectiveLink, _targetLag: 0, _trueLag: effectiveLink.lag },
|
|
3441
|
+
adapter,
|
|
3442
|
+
activity,
|
|
3443
|
+
getActivityDates
|
|
3444
|
+
).successorStart;
|
|
3445
|
+
const lagActivity = adapter.getActivity(effectiveLink._summaryTargetId) ?? activity;
|
|
3446
|
+
const satisfied = summaryFinish.endDate >= requiredFinish || adapter.calculateDuration({
|
|
3447
|
+
startDate: summaryFinish.endDate,
|
|
3448
|
+
endDate: requiredFinish,
|
|
3449
|
+
task: lagActivity
|
|
3450
|
+
}) === 0;
|
|
3451
|
+
if (satisfied || summaryFinish.movableEnd === null || !summaryFinish.drivingLeafIds.has(activityId))
|
|
3452
|
+
continue;
|
|
3453
|
+
effectiveLink = {
|
|
3454
|
+
...effectiveLink,
|
|
3455
|
+
_targetLag: -adapter.calculateDuration({
|
|
3456
|
+
startDate: summaryFinish.starts.get(activityId) ?? activity.startDate,
|
|
3457
|
+
endDate: summaryFinish.movableEnd,
|
|
3458
|
+
task: activity
|
|
3459
|
+
}),
|
|
3460
|
+
_trueLag: effectiveLink.lag
|
|
3461
|
+
};
|
|
3462
|
+
}
|
|
3463
|
+
let summarySourceMovedThisRun = false;
|
|
3315
3464
|
const result = calculateSuccessorStartFromLink(
|
|
3316
3465
|
adjustedPred,
|
|
3317
3466
|
activity,
|
|
3318
3467
|
effectiveLink,
|
|
3319
|
-
adapter
|
|
3468
|
+
adapter,
|
|
3469
|
+
activity,
|
|
3470
|
+
(id) => {
|
|
3471
|
+
const dates = getActivityDates(id);
|
|
3472
|
+
const snapshot = adapter.getActivity(id);
|
|
3473
|
+
if (snapshot && (dates.startDate.getTime() !== snapshot.startDate.getTime() || dates.endDate.getTime() !== snapshot.endDate.getTime())) {
|
|
3474
|
+
summarySourceMovedThisRun = true;
|
|
3475
|
+
}
|
|
3476
|
+
return dates;
|
|
3477
|
+
}
|
|
3320
3478
|
);
|
|
3321
3479
|
if (!maxStart || result.successorStart > maxStart) {
|
|
3322
3480
|
maxStart = result.successorStart;
|
|
3323
3481
|
drivingLinkId = String(link.id);
|
|
3324
|
-
drivingOffsetIsStale = link._summaryTargetId !== void 0 && !predecessorMovedThisRun && (link._targetLag === 0 || options.preventSummaryTargetPullback === true);
|
|
3482
|
+
drivingOffsetIsStale = link._summaryTargetId !== void 0 && !predecessorMovedThisRun && !summarySourceMovedThisRun && (link._targetLag === 0 || options.preventSummaryTargetPullback === true);
|
|
3325
3483
|
}
|
|
3326
3484
|
}
|
|
3327
3485
|
const staleOffsetWouldPullBack = maxStart !== null && drivingOffsetIsStale && maxStart < activity.startDate;
|
|
@@ -4552,14 +4710,26 @@ var AutoScheduler = class {
|
|
|
4552
4710
|
return { ...emptyResult, cancelled: true };
|
|
4553
4711
|
}
|
|
4554
4712
|
const phaseAsap = startPhase("schedule.asapPass");
|
|
4555
|
-
const
|
|
4713
|
+
const hasSummaryFinishLinks = scopedLinks.some(
|
|
4714
|
+
(link) => link._summaryTargetId !== void 0 && (link.type === LINK_TYPE.FINISH_TO_FINISH || link.type === LINK_TYPE.START_TO_FINISH)
|
|
4715
|
+
);
|
|
4716
|
+
const initialAsapPlans = await asapPass(
|
|
4556
4717
|
topoResult.ordered,
|
|
4557
4718
|
scopedLinks,
|
|
4558
4719
|
this.adapter,
|
|
4559
4720
|
options,
|
|
4560
4721
|
isCurrent,
|
|
4561
|
-
plans
|
|
4722
|
+
plans,
|
|
4723
|
+
hasSummaryFinishLinks
|
|
4562
4724
|
);
|
|
4725
|
+
const asapPlans = hasSummaryFinishLinks ? await asapPass(
|
|
4726
|
+
topoResult.ordered,
|
|
4727
|
+
scopedLinks,
|
|
4728
|
+
this.adapter,
|
|
4729
|
+
options,
|
|
4730
|
+
isCurrent,
|
|
4731
|
+
initialAsapPlans
|
|
4732
|
+
) : initialAsapPlans;
|
|
4563
4733
|
endPhase(phaseAsap);
|
|
4564
4734
|
if ((await yieldBetweenPhases(isCurrent)).aborted) {
|
|
4565
4735
|
return { ...emptyResult, cancelled: true };
|
|
@@ -4721,14 +4891,16 @@ function roundProgressPerLevel(value) {
|
|
|
4721
4891
|
}
|
|
4722
4892
|
|
|
4723
4893
|
// src/propagations/upward/progress-rollup.ts
|
|
4724
|
-
function recomputeAllProgressRollup(adapter) {
|
|
4894
|
+
function recomputeAllProgressRollup(adapter, criterion) {
|
|
4895
|
+
const zeroCostBasis = /* @__PURE__ */ new Map();
|
|
4725
4896
|
for (const parentId of parentsDeepestFirst(adapter)) {
|
|
4726
|
-
rollupParent(parentId, adapter);
|
|
4897
|
+
rollupParent(parentId, adapter, criterion, zeroCostBasis);
|
|
4727
4898
|
}
|
|
4728
4899
|
}
|
|
4729
|
-
function recomputeProgressRollupForParents(parentIdsDeepestFirst, adapter) {
|
|
4900
|
+
function recomputeProgressRollupForParents(parentIdsDeepestFirst, adapter, criterion) {
|
|
4901
|
+
const zeroCostBasis = /* @__PURE__ */ new Map();
|
|
4730
4902
|
for (const parentId of parentIdsDeepestFirst) {
|
|
4731
|
-
rollupParent(parentId, adapter);
|
|
4903
|
+
rollupParent(parentId, adapter, criterion, zeroCostBasis);
|
|
4732
4904
|
}
|
|
4733
4905
|
}
|
|
4734
4906
|
function parentsDeepestFirst(adapter) {
|
|
@@ -4752,7 +4924,7 @@ function depthOf(id, adapter) {
|
|
|
4752
4924
|
}
|
|
4753
4925
|
return depth;
|
|
4754
4926
|
}
|
|
4755
|
-
function rollupParent(parentId, adapter) {
|
|
4927
|
+
function rollupParent(parentId, adapter, criterion, zeroCostBasis) {
|
|
4756
4928
|
const childIds = adapter.getChildren(parentId);
|
|
4757
4929
|
if (childIds.length === 0) return;
|
|
4758
4930
|
const children = [];
|
|
@@ -4764,12 +4936,20 @@ function rollupParent(parentId, adapter) {
|
|
|
4764
4936
|
ponderator: Number(child.ponderator ?? 0)
|
|
4765
4937
|
});
|
|
4766
4938
|
}
|
|
4767
|
-
applyWeightedProgressRollup(
|
|
4939
|
+
applyWeightedProgressRollup(
|
|
4940
|
+
parentId,
|
|
4941
|
+
children,
|
|
4942
|
+
adapter,
|
|
4943
|
+
criterion,
|
|
4944
|
+
zeroCostBasis
|
|
4945
|
+
);
|
|
4768
4946
|
}
|
|
4769
|
-
function applyWeightedProgressRollup(parentId, children, adapter) {
|
|
4947
|
+
function applyWeightedProgressRollup(parentId, children, adapter, criterion, zeroCostBasis = /* @__PURE__ */ new Map()) {
|
|
4770
4948
|
const parent = adapter.getActivity(parentId);
|
|
4771
4949
|
if (!parent) return;
|
|
4772
|
-
const
|
|
4950
|
+
const weightedProgress = computeWeightedProgressRollup(children);
|
|
4951
|
+
const hasZeroCostBasis = weightedProgress === null && criterion === ACTIVITY_PONDERATOR_CRITERION.COST && hasOnlyZeroBaselineCosts(parentId, adapter, zeroCostBasis) === true;
|
|
4952
|
+
const rollup = hasZeroCostBasis ? 0 : weightedProgress;
|
|
4773
4953
|
if (rollup === null) {
|
|
4774
4954
|
const fallback = adapter.getProgressFallback(parentId);
|
|
4775
4955
|
if (fallback !== null) {
|
|
@@ -4786,6 +4966,43 @@ function applyWeightedProgressRollup(parentId, children, adapter) {
|
|
|
4786
4966
|
roundProgressPerLevel(rollup)
|
|
4787
4967
|
);
|
|
4788
4968
|
}
|
|
4969
|
+
function hasOnlyZeroBaselineCosts(parentId, adapter, zeroCostBasis) {
|
|
4970
|
+
const pending = [...adapter.getChildren(parentId)];
|
|
4971
|
+
let hasBaseline = false;
|
|
4972
|
+
while (pending.length > 0) {
|
|
4973
|
+
const activityId = pending.pop();
|
|
4974
|
+
const cachedBasis = zeroCostBasis.get(activityId);
|
|
4975
|
+
if (cachedBasis === false) {
|
|
4976
|
+
zeroCostBasis.set(parentId, false);
|
|
4977
|
+
return false;
|
|
4978
|
+
}
|
|
4979
|
+
if (cachedBasis !== void 0) {
|
|
4980
|
+
hasBaseline ||= cachedBasis === true;
|
|
4981
|
+
continue;
|
|
4982
|
+
}
|
|
4983
|
+
const activity = adapter.getActivity(activityId);
|
|
4984
|
+
if (!activity) continue;
|
|
4985
|
+
const children = adapter.getChildren(activityId);
|
|
4986
|
+
if (children.length > 0) {
|
|
4987
|
+
pending.push(...children);
|
|
4988
|
+
continue;
|
|
4989
|
+
}
|
|
4990
|
+
const basis2 = zeroBaselineCost(activity);
|
|
4991
|
+
hasBaseline ||= basis2 !== null;
|
|
4992
|
+
if (basis2 === false) {
|
|
4993
|
+
zeroCostBasis.set(parentId, false);
|
|
4994
|
+
return false;
|
|
4995
|
+
}
|
|
4996
|
+
}
|
|
4997
|
+
const basis = hasBaseline ? true : null;
|
|
4998
|
+
zeroCostBasis.set(parentId, basis);
|
|
4999
|
+
return basis;
|
|
5000
|
+
}
|
|
5001
|
+
function zeroBaselineCost(activity) {
|
|
5002
|
+
const baseline = getActiveBaseline(activity);
|
|
5003
|
+
if (!baseline) return null;
|
|
5004
|
+
return activity.type === ACTIVITY_TYPE.MILESTONE || baseline.cost === 0;
|
|
5005
|
+
}
|
|
4789
5006
|
function setExplicitSummaryProgressFallbacks(activityId, progress, adapter) {
|
|
4790
5007
|
const pending = [activityId];
|
|
4791
5008
|
while (pending.length > 0) {
|
|
@@ -4812,7 +5029,8 @@ async function updateParentBoundsFromChildren(adapter, dirtyIds, recomputeProgre
|
|
|
4812
5029
|
const parents = dirtyIds ? findAncestorsOfDirty(adapter, dirtyIds) : findAllParents(adapter);
|
|
4813
5030
|
const progressMode = recomputeProgress ? options.progressMode ?? PARENT_PROGRESS_MODE.FREEZE_WITHOUT_CONTRIBUTION : PARENT_PROGRESS_MODE.SKIP;
|
|
4814
5031
|
await recomputeParentsCooperatively(parents, adapter, progressMode, {
|
|
4815
|
-
recomputeRealWork: options.recomputeRealWork ?? false
|
|
5032
|
+
recomputeRealWork: options.recomputeRealWork ?? false,
|
|
5033
|
+
criterion: options.criterion
|
|
4816
5034
|
});
|
|
4817
5035
|
}
|
|
4818
5036
|
function recomputeSingleParentDisplayBounds(parentId, adapter) {
|
|
@@ -4821,6 +5039,7 @@ function recomputeSingleParentDisplayBounds(parentId, adapter) {
|
|
|
4821
5039
|
async function recomputeParentsCooperatively(parents, adapter, progressMode, options = {
|
|
4822
5040
|
recomputeRealWork: false
|
|
4823
5041
|
}) {
|
|
5042
|
+
const zeroCostBasis = /* @__PURE__ */ new Map();
|
|
4824
5043
|
const YIELD_EVERY_N_PARENTS = 200;
|
|
4825
5044
|
let processed = 0;
|
|
4826
5045
|
for (const parentId of parents) {
|
|
@@ -4828,7 +5047,9 @@ async function recomputeParentsCooperatively(parents, adapter, progressMode, opt
|
|
|
4828
5047
|
parentId,
|
|
4829
5048
|
adapter,
|
|
4830
5049
|
progressMode,
|
|
4831
|
-
options.recomputeRealWork
|
|
5050
|
+
options.recomputeRealWork,
|
|
5051
|
+
options.criterion,
|
|
5052
|
+
zeroCostBasis
|
|
4832
5053
|
);
|
|
4833
5054
|
processed += 1;
|
|
4834
5055
|
if (processed % YIELD_EVERY_N_PARENTS === 0) {
|
|
@@ -4902,7 +5123,7 @@ function aggregateChildren(childrenIds, adapter, includeRealWork) {
|
|
|
4902
5123
|
}
|
|
4903
5124
|
return { minStart, maxEnd, realWorkSum, weightedChildren };
|
|
4904
5125
|
}
|
|
4905
|
-
function recomputeParentFromChildren(parentId, adapter, progressMode = PARENT_PROGRESS_MODE.FREEZE_WITHOUT_CONTRIBUTION, recomputeRealWork = false) {
|
|
5126
|
+
function recomputeParentFromChildren(parentId, adapter, progressMode = PARENT_PROGRESS_MODE.FREEZE_WITHOUT_CONTRIBUTION, recomputeRealWork = false, criterion, zeroCostBasis = /* @__PURE__ */ new Map()) {
|
|
4906
5127
|
const parent = adapter.getActivity(parentId);
|
|
4907
5128
|
if (!parent) return;
|
|
4908
5129
|
const childrenIds = adapter.getChildren(parentId);
|
|
@@ -4918,7 +5139,13 @@ function recomputeParentFromChildren(parentId, adapter, progressMode = PARENT_PR
|
|
|
4918
5139
|
adapter.setActivityField(parentId, "endDate", newEnd);
|
|
4919
5140
|
adapter.setActivityField(parentId, "durationHours", durationHours);
|
|
4920
5141
|
if (progressMode !== PARENT_PROGRESS_MODE.SKIP) {
|
|
4921
|
-
applyWeightedProgressRollup(
|
|
5142
|
+
applyWeightedProgressRollup(
|
|
5143
|
+
parentId,
|
|
5144
|
+
aggregate.weightedChildren,
|
|
5145
|
+
adapter,
|
|
5146
|
+
criterion,
|
|
5147
|
+
zeroCostBasis
|
|
5148
|
+
);
|
|
4922
5149
|
}
|
|
4923
5150
|
if (recomputeRealWork) {
|
|
4924
5151
|
adapter.setActivityField(parentId, "realWorkHours", aggregate.realWorkSum);
|
|
@@ -5250,9 +5477,13 @@ var POST_PROCESSOR = {
|
|
|
5250
5477
|
};
|
|
5251
5478
|
|
|
5252
5479
|
// src/columns/shared/error-codes.ts
|
|
5480
|
+
var PARSE_ERROR = {
|
|
5481
|
+
EMPTY_CALENDAR: "empty_calendar"};
|
|
5253
5482
|
var VALIDATION_REASON = {
|
|
5254
5483
|
UNCHANGED: "unchanged",
|
|
5255
|
-
NEGATIVE_DURATION: "negative_duration"
|
|
5484
|
+
NEGATIVE_DURATION: "negative_duration",
|
|
5485
|
+
UNKNOWN_CALENDAR: "unknown_calendar"
|
|
5486
|
+
};
|
|
5256
5487
|
var EDIT_DENIAL_REASON = {
|
|
5257
5488
|
COMPLETED: "completed",
|
|
5258
5489
|
SUMMARY: "summary",
|
|
@@ -5545,7 +5776,7 @@ var costPipeline = {
|
|
|
5545
5776
|
parseInput(rawValue) {
|
|
5546
5777
|
if (String(rawValue).trim() === "") return parsed(0);
|
|
5547
5778
|
const numericValue = parseFloat(String(rawValue));
|
|
5548
|
-
if (Number.
|
|
5779
|
+
if (!Number.isFinite(numericValue)) return parseError("not_a_number");
|
|
5549
5780
|
return parsed(numericValue);
|
|
5550
5781
|
},
|
|
5551
5782
|
validate() {
|
|
@@ -5595,7 +5826,7 @@ var usedCostPipeline = {
|
|
|
5595
5826
|
parseInput(rawValue) {
|
|
5596
5827
|
if (String(rawValue).trim() === "") return parsed(0);
|
|
5597
5828
|
const numericValue = parseFloat(String(rawValue));
|
|
5598
|
-
if (Number.
|
|
5829
|
+
if (!Number.isFinite(numericValue)) return parseError("not_a_number");
|
|
5599
5830
|
return parsed(numericValue);
|
|
5600
5831
|
},
|
|
5601
5832
|
validate() {
|
|
@@ -5648,7 +5879,7 @@ var hhWorkTimePipeline = {
|
|
|
5648
5879
|
parseInput(rawValue) {
|
|
5649
5880
|
if (String(rawValue).trim() === "") return parsed(0, rawValue);
|
|
5650
5881
|
const numericValue = parseFloat(String(rawValue));
|
|
5651
|
-
if (Number.
|
|
5882
|
+
if (!Number.isFinite(numericValue)) return parseError("not_a_number");
|
|
5652
5883
|
return parsed(numericValue);
|
|
5653
5884
|
},
|
|
5654
5885
|
validate() {
|
|
@@ -6046,27 +6277,33 @@ function isUnconstrained(activity) {
|
|
|
6046
6277
|
|
|
6047
6278
|
// src/columns/calendar-id/calendar-id-pipeline.ts
|
|
6048
6279
|
var calendarIdPipeline = {
|
|
6049
|
-
targetField:
|
|
6280
|
+
targetField: ACTIVITY_PROPERTY.CALENDAR_ID,
|
|
6050
6281
|
canEdit() {
|
|
6051
6282
|
return canEdit();
|
|
6052
6283
|
},
|
|
6053
6284
|
parseInput(rawValue) {
|
|
6285
|
+
if (rawValue === null) return parsed(null);
|
|
6054
6286
|
const value = String(rawValue).trim();
|
|
6055
|
-
if (isEmpty(value)) return parseError(
|
|
6287
|
+
if (isEmpty(value)) return parseError(PARSE_ERROR.EMPTY_CALENDAR);
|
|
6056
6288
|
return parsed(value);
|
|
6057
6289
|
},
|
|
6058
6290
|
validate(activity, _oldValue, newValue, ctx) {
|
|
6059
|
-
|
|
6060
|
-
|
|
6061
|
-
|
|
6062
|
-
|
|
6291
|
+
const calendarId = newValue === null ? ctx.getDefaultCalendarId() : newValue;
|
|
6292
|
+
if (isUnchangedCalendar(activity.calendarId, calendarId) && (newValue !== null || activity.assignedDefaultCalendar))
|
|
6293
|
+
return invalid(VALIDATION_REASON.UNCHANGED);
|
|
6294
|
+
if (calendarId === null || !ctx.hasCalendar(calendarId))
|
|
6295
|
+
return invalid(VALIDATION_REASON.UNKNOWN_CALENDAR);
|
|
6063
6296
|
return valid();
|
|
6064
6297
|
},
|
|
6065
6298
|
transform(activity, newValue, ctx) {
|
|
6066
|
-
|
|
6067
|
-
|
|
6068
|
-
|
|
6069
|
-
|
|
6299
|
+
const calendarId = newValue === null ? ctx.getDefaultCalendarId() : newValue;
|
|
6300
|
+
return fieldChanges(
|
|
6301
|
+
buildCalendarPatch(activity, calendarId, newValue === null, ctx),
|
|
6302
|
+
{
|
|
6303
|
+
autoSchedule: true,
|
|
6304
|
+
postProcessors: []
|
|
6305
|
+
}
|
|
6306
|
+
);
|
|
6070
6307
|
},
|
|
6071
6308
|
trackEvent: COLUMN_TRACK_EVENT.CALENDAR_ASSIGNMENT
|
|
6072
6309
|
};
|
|
@@ -6076,12 +6313,12 @@ function isEmpty(value) {
|
|
|
6076
6313
|
function isUnchangedCalendar(currentId, newId) {
|
|
6077
6314
|
return currentId === newId;
|
|
6078
6315
|
}
|
|
6079
|
-
function buildCalendarPatch(activity, newCalendarId, ctx) {
|
|
6316
|
+
function buildCalendarPatch(activity, newCalendarId, assignedDefaultCalendar, ctx) {
|
|
6080
6317
|
const fields = {
|
|
6081
6318
|
calendarId: newCalendarId,
|
|
6082
|
-
assignedDefaultCalendar
|
|
6319
|
+
assignedDefaultCalendar
|
|
6083
6320
|
};
|
|
6084
|
-
const newCalendar = ctx.calendars.getCalendar(newCalendarId);
|
|
6321
|
+
const newCalendar = newCalendarId === null ? null : ctx.calendars.getCalendar(newCalendarId);
|
|
6085
6322
|
if (newCalendar) {
|
|
6086
6323
|
const startIsWorking = newCalendar.isWorkTime(activity.startDate, "hour");
|
|
6087
6324
|
const calendarStart = newCalendar.getClosestWorkTime({
|
|
@@ -6291,6 +6528,7 @@ var P6_ACTIVITY_TYPE = {
|
|
|
6291
6528
|
TASK: "task",
|
|
6292
6529
|
LEVEL_OF_EFFORT: "level_of_effort",
|
|
6293
6530
|
START_MILESTONE: "start_milestone",
|
|
6531
|
+
WBS_SUMMARY: "wbs_summary",
|
|
6294
6532
|
RESOURCE_DEPENDENT: "resource_dependent"
|
|
6295
6533
|
};
|
|
6296
6534
|
var P6_EXECUTION_STATUS = {
|
|
@@ -6456,9 +6694,10 @@ var actualStartPipeline = {
|
|
|
6456
6694
|
transform(activity, newValue, ctx) {
|
|
6457
6695
|
if (newValue === null) return actualStartChanges(activity, null);
|
|
6458
6696
|
const calendar = resolveActivityCalendar(activity, ctx);
|
|
6697
|
+
const firstAssignment = activity.p6?.actualStart == null;
|
|
6459
6698
|
return actualStartChanges(
|
|
6460
6699
|
activity,
|
|
6461
|
-
defaultActualStartTime(newValue, calendar)
|
|
6700
|
+
firstAssignment ? defaultActualStartTime(newValue, calendar) : new Date(newValue)
|
|
6462
6701
|
);
|
|
6463
6702
|
}
|
|
6464
6703
|
};
|
|
@@ -6467,9 +6706,10 @@ var actualFinishPipeline = {
|
|
|
6467
6706
|
transform(activity, newValue, ctx) {
|
|
6468
6707
|
if (newValue === null) return actualFinishChanges(activity, null);
|
|
6469
6708
|
const calendar = resolveActivityCalendar(activity, ctx);
|
|
6709
|
+
const firstAssignment = activity.p6?.actualFinish == null;
|
|
6470
6710
|
return actualFinishChanges(
|
|
6471
6711
|
activity,
|
|
6472
|
-
defaultActualFinishTime(newValue, calendar)
|
|
6712
|
+
firstAssignment ? defaultActualFinishTime(newValue, calendar) : new Date(newValue)
|
|
6473
6713
|
);
|
|
6474
6714
|
}
|
|
6475
6715
|
};
|
|
@@ -12412,7 +12652,7 @@ function collectInsertedIds(captured) {
|
|
|
12412
12652
|
}
|
|
12413
12653
|
|
|
12414
12654
|
// src/propagations/downward/recompute-ponderator-for-parent.ts
|
|
12415
|
-
function recomputePonderatorsForParent(parentId, criterion, adapter) {
|
|
12655
|
+
function recomputePonderatorsForParent(parentId, criterion, adapter, basisById = /* @__PURE__ */ new Map()) {
|
|
12416
12656
|
if (!parentId || parentId === ROOT_PARENT_ID) return;
|
|
12417
12657
|
const childIds = adapter.getChildren(parentId);
|
|
12418
12658
|
if (childIds.length === 0) return;
|
|
@@ -12420,15 +12660,21 @@ function recomputePonderatorsForParent(parentId, criterion, adapter) {
|
|
|
12420
12660
|
const baselineScopedIds = /* @__PURE__ */ new Set();
|
|
12421
12661
|
let denominator = 0;
|
|
12422
12662
|
for (const childId of childIds) {
|
|
12423
|
-
const
|
|
12424
|
-
|
|
12425
|
-
|
|
12426
|
-
|
|
12663
|
+
const basis = baselineWeightingBasis(
|
|
12664
|
+
String(childId),
|
|
12665
|
+
criterion,
|
|
12666
|
+
adapter,
|
|
12667
|
+
basisById
|
|
12668
|
+
);
|
|
12669
|
+
pesoById.set(String(childId), basis.magnitude);
|
|
12670
|
+
denominator += basis.magnitude;
|
|
12671
|
+
if (basis.hasActiveBaseline) {
|
|
12427
12672
|
baselineScopedIds.add(String(childId));
|
|
12428
12673
|
}
|
|
12429
12674
|
}
|
|
12430
12675
|
const relationValue = denominator ? 100 / denominator : 0;
|
|
12431
|
-
const
|
|
12676
|
+
const hasEqualShare = criterion !== ACTIVITY_PONDERATOR_CRITERION.COST && baselineScopedIds.size > 0;
|
|
12677
|
+
const zeroMagnitudeShare = hasEqualShare ? 100 / baselineScopedIds.size : 0;
|
|
12432
12678
|
for (const childId of childIds) {
|
|
12433
12679
|
const child = adapter.getActivity(childId);
|
|
12434
12680
|
if (!child) continue;
|
|
@@ -12453,39 +12699,39 @@ function assignedPonderator(childId, child, pesoById, baselineScopedIds, denomin
|
|
|
12453
12699
|
}
|
|
12454
12700
|
return !Array.isArray(child.baselinePoints) || child.baselinePoints.length === 0 ? 0 : null;
|
|
12455
12701
|
}
|
|
12456
|
-
function
|
|
12457
|
-
const
|
|
12458
|
-
|
|
12459
|
-
|
|
12460
|
-
|
|
12461
|
-
|
|
12462
|
-
|
|
12463
|
-
|
|
12464
|
-
|
|
12465
|
-
|
|
12466
|
-
|
|
12467
|
-
|
|
12468
|
-
|
|
12469
|
-
|
|
12470
|
-
|
|
12471
|
-
|
|
12472
|
-
|
|
12473
|
-
|
|
12474
|
-
|
|
12475
|
-
|
|
12476
|
-
|
|
12477
|
-
|
|
12478
|
-
if (!child) continue;
|
|
12479
|
-
if (child.type === ACTIVITY_TYPE.PROJECT) {
|
|
12480
|
-
sum2 += sumRecursiveBaselineMagnitude(String(childId), criterion, adapter);
|
|
12702
|
+
function baselineWeightingBasis(activityId, criterion, adapter, basisById) {
|
|
12703
|
+
const pending = [
|
|
12704
|
+
{ id: activityId, expanded: false }
|
|
12705
|
+
];
|
|
12706
|
+
while (pending.length > 0) {
|
|
12707
|
+
const { id, expanded } = pending.pop();
|
|
12708
|
+
if (basisById.has(id)) continue;
|
|
12709
|
+
const activity = adapter.getActivity(id);
|
|
12710
|
+
const baseline = getActiveBaseline(activity);
|
|
12711
|
+
if (activity?.type !== ACTIVITY_TYPE.PROJECT) {
|
|
12712
|
+
basisById.set(id, {
|
|
12713
|
+
magnitude: baseline && activity?.type !== ACTIVITY_TYPE.MILESTONE ? baselineMagnitude(baseline, criterion) : 0,
|
|
12714
|
+
hasActiveBaseline: baseline !== null
|
|
12715
|
+
});
|
|
12716
|
+
continue;
|
|
12717
|
+
}
|
|
12718
|
+
const children = adapter.getChildren(id);
|
|
12719
|
+
if (!expanded) {
|
|
12720
|
+
pending.push({ id, expanded: true });
|
|
12721
|
+
children.forEach((childId) => {
|
|
12722
|
+
pending.push({ id: String(childId), expanded: false });
|
|
12723
|
+
});
|
|
12481
12724
|
continue;
|
|
12482
12725
|
}
|
|
12483
|
-
const
|
|
12484
|
-
|
|
12485
|
-
|
|
12726
|
+
const basis = { magnitude: 0, hasActiveBaseline: baseline !== null };
|
|
12727
|
+
for (const childId of children) {
|
|
12728
|
+
const child = basisById.get(String(childId));
|
|
12729
|
+
basis.magnitude += child.magnitude;
|
|
12730
|
+
basis.hasActiveBaseline ||= child.hasActiveBaseline;
|
|
12486
12731
|
}
|
|
12732
|
+
basisById.set(id, basis);
|
|
12487
12733
|
}
|
|
12488
|
-
return
|
|
12734
|
+
return basisById.get(activityId);
|
|
12489
12735
|
}
|
|
12490
12736
|
function baselineMagnitude(baseline, criterion) {
|
|
12491
12737
|
if (criterion === ACTIVITY_PONDERATOR_CRITERION.COST) {
|
|
@@ -12501,10 +12747,72 @@ function toNumber(v) {
|
|
|
12501
12747
|
return typeof n === "number" && Number.isFinite(n) ? n : 0;
|
|
12502
12748
|
}
|
|
12503
12749
|
|
|
12750
|
+
// src/dispatch/shared/structural-ponderators.ts
|
|
12751
|
+
function recomputeStructuralPonderators(adapter, criterion) {
|
|
12752
|
+
const journal = adapter.peekWriteCapture();
|
|
12753
|
+
if (!journal) return;
|
|
12754
|
+
const parents = /* @__PURE__ */ new Map();
|
|
12755
|
+
const removedParents = /* @__PURE__ */ new Map();
|
|
12756
|
+
for (const operation of journal.ops) {
|
|
12757
|
+
if (operation.kind === WRITE_OPERATION_KIND.REMOVE) {
|
|
12758
|
+
removedParents.set(operation.activityId, operation.before.parentId);
|
|
12759
|
+
}
|
|
12760
|
+
}
|
|
12761
|
+
const collectParents = (parentId, lostBaseline) => {
|
|
12762
|
+
let current = parentId;
|
|
12763
|
+
while (current !== null && !isRootParent(current)) {
|
|
12764
|
+
const existing = parents.get(current);
|
|
12765
|
+
if (existing === true || existing === lostBaseline) break;
|
|
12766
|
+
parents.set(current, lostBaseline);
|
|
12767
|
+
current = removedParents.has(current) ? removedParents.get(current) ?? null : adapter.getParentId(current);
|
|
12768
|
+
}
|
|
12769
|
+
};
|
|
12770
|
+
for (const [activityId, before] of journal.before) {
|
|
12771
|
+
const after = adapter.getActivity(activityId);
|
|
12772
|
+
const parentChanged = after && before.parentId !== after.parentId;
|
|
12773
|
+
if (!parentChanged || !after) continue;
|
|
12774
|
+
const hasBaseline = getActiveBaseline(before) !== null || hasBaselineInBranch(activityId, adapter);
|
|
12775
|
+
collectParents(before.parentId, hasBaseline);
|
|
12776
|
+
collectParents(after.parentId, false);
|
|
12777
|
+
}
|
|
12778
|
+
for (const operation of journal.ops) {
|
|
12779
|
+
if (operation.kind === WRITE_OPERATION_KIND.REMOVE) {
|
|
12780
|
+
if (getActiveBaseline(operation.before))
|
|
12781
|
+
collectParents(operation.before.parentId, true);
|
|
12782
|
+
} else if (operation.kind === WRITE_OPERATION_KIND.INSERT) {
|
|
12783
|
+
const inserted = adapter.getActivity(operation.activityId);
|
|
12784
|
+
if (inserted && hasBaselineInBranch(inserted.id, adapter))
|
|
12785
|
+
collectParents(inserted.parentId, false);
|
|
12786
|
+
}
|
|
12787
|
+
}
|
|
12788
|
+
for (const [parentId, lostBaseline] of parents) {
|
|
12789
|
+
if (lostBaseline || hasBaselineInBranch(parentId, adapter)) {
|
|
12790
|
+
recomputePonderatorsForParent(parentId, criterion, adapter);
|
|
12791
|
+
}
|
|
12792
|
+
}
|
|
12793
|
+
}
|
|
12794
|
+
function hasBaselineInBranch(activityId, adapter) {
|
|
12795
|
+
const pending = [activityId];
|
|
12796
|
+
while (pending.length > 0) {
|
|
12797
|
+
const current = pending.pop();
|
|
12798
|
+
if (current === void 0) continue;
|
|
12799
|
+
const activity = adapter.getActivity(current);
|
|
12800
|
+
if (activity && getActiveBaseline(activity)) return true;
|
|
12801
|
+
pending.push(...adapter.getChildren(current));
|
|
12802
|
+
}
|
|
12803
|
+
return false;
|
|
12804
|
+
}
|
|
12805
|
+
|
|
12504
12806
|
// src/dispatch/shared/post-mutation.ts
|
|
12505
12807
|
var AUTOSCHEDULE_SCOPE = { ROOTS: "roots" };
|
|
12506
12808
|
async function runPostMutation(deps, args) {
|
|
12507
|
-
|
|
12809
|
+
const isConversion = args.action.kind === DISPATCH_ACTION_KIND.ACTIVITY_LOOKAHEAD_CONVERT;
|
|
12810
|
+
if (!isConversion) {
|
|
12811
|
+
recomputeStructuralPonderators(
|
|
12812
|
+
deps.adapter,
|
|
12813
|
+
deps.sector.activityCreter ?? ACTIVITY_PONDERATOR_CRITERION.DURATION
|
|
12814
|
+
);
|
|
12815
|
+
}
|
|
12508
12816
|
const progressInvalidation = resolveProgressInvalidation(deps.adapter);
|
|
12509
12817
|
const effectiveArgs = resolveTransactionAutoscheduleArgs(deps.adapter, args);
|
|
12510
12818
|
const passes = resolvePasses(
|
|
@@ -12525,7 +12833,8 @@ async function runPostMutation(deps, args) {
|
|
|
12525
12833
|
effectiveArgs,
|
|
12526
12834
|
schedule.scheduledIds,
|
|
12527
12835
|
passes,
|
|
12528
|
-
progressInvalidation
|
|
12836
|
+
progressInvalidation,
|
|
12837
|
+
deps.sector.activityCreter ?? ACTIVITY_PONDERATOR_CRITERION.DURATION
|
|
12529
12838
|
);
|
|
12530
12839
|
await runDerivedRecomputes(deps, passes, args.now);
|
|
12531
12840
|
synchronizeInactiveDataDateDrafts(deps.adapter);
|
|
@@ -12574,37 +12883,6 @@ function collectLinkMutationTargets(adapter) {
|
|
|
12574
12883
|
}
|
|
12575
12884
|
return targets;
|
|
12576
12885
|
}
|
|
12577
|
-
function recomputePromotedSummaryPonderators(deps) {
|
|
12578
|
-
const journal = deps.adapter.peekWriteCapture();
|
|
12579
|
-
if (!journal) return;
|
|
12580
|
-
const visited = /* @__PURE__ */ new Set();
|
|
12581
|
-
const criterion = deps.sector.activityCreter ?? ACTIVITY_PONDERATOR_CRITERION.DURATION;
|
|
12582
|
-
for (const [activityId, before] of journal.before) {
|
|
12583
|
-
const after = deps.adapter.getActivity(activityId);
|
|
12584
|
-
if (before.type === ACTIVITY_TYPE.PROJECT || after?.type !== ACTIVITY_TYPE.PROJECT || getActiveBaseline(after) || !hasActiveBaselineDescendant(activityId, deps.adapter)) {
|
|
12585
|
-
continue;
|
|
12586
|
-
}
|
|
12587
|
-
let current = activityId;
|
|
12588
|
-
while (current !== null && !isRootParent(current)) {
|
|
12589
|
-
if (!visited.has(current)) {
|
|
12590
|
-
recomputePonderatorsForParent(current, criterion, deps.adapter);
|
|
12591
|
-
visited.add(current);
|
|
12592
|
-
}
|
|
12593
|
-
current = deps.adapter.getParentId(current);
|
|
12594
|
-
}
|
|
12595
|
-
}
|
|
12596
|
-
}
|
|
12597
|
-
function hasActiveBaselineDescendant(activityId, adapter) {
|
|
12598
|
-
const pending = [...adapter.getChildren(activityId)];
|
|
12599
|
-
while (pending.length > 0) {
|
|
12600
|
-
const childId = pending.pop();
|
|
12601
|
-
if (childId === void 0) continue;
|
|
12602
|
-
const child = adapter.getActivity(childId);
|
|
12603
|
-
if (child && getActiveBaseline(child)) return true;
|
|
12604
|
-
pending.push(...adapter.getChildren(childId));
|
|
12605
|
-
}
|
|
12606
|
-
return false;
|
|
12607
|
-
}
|
|
12608
12886
|
async function dispatchScheduleAutoSchedule(action, options, deps) {
|
|
12609
12887
|
if (action.activityId !== void 0 && !deps.adapter.activityExists(action.activityId)) {
|
|
12610
12888
|
return { ok: false, reason: REJECTION_REASON.ACTIVITY_NOT_FOUND };
|
|
@@ -12757,7 +13035,7 @@ async function refreshMutatedParentBounds(adapter, args) {
|
|
|
12757
13035
|
if (mutated.size === 0) return;
|
|
12758
13036
|
await updateParentBoundsFromChildren(adapter, mutated, false);
|
|
12759
13037
|
}
|
|
12760
|
-
async function rollUpParentBounds(adapter, args, scheduledIds, passes, progressInvalidation) {
|
|
13038
|
+
async function rollUpParentBounds(adapter, args, scheduledIds, passes, progressInvalidation, criterion) {
|
|
12761
13039
|
if (passes.has(DERIVED_PASS.PARENT_PROGRESS)) {
|
|
12762
13040
|
restoreDemotedProgressFallbacks(
|
|
12763
13041
|
adapter,
|
|
@@ -12774,6 +13052,7 @@ async function rollUpParentBounds(adapter, args, scheduledIds, passes, progressI
|
|
|
12774
13052
|
passes.has(DERIVED_PASS.PARENT_PROGRESS),
|
|
12775
13053
|
{
|
|
12776
13054
|
recomputeRealWork: passes.has(DERIVED_PASS.REAL_WORK),
|
|
13055
|
+
criterion,
|
|
12777
13056
|
progressMode: "freeze-when-no-contribution"
|
|
12778
13057
|
}
|
|
12779
13058
|
);
|
|
@@ -13023,6 +13302,8 @@ function buildLinkChangesForBatch(applied, beforeLinks, adapter) {
|
|
|
13023
13302
|
after: Number(afterLink.lag)
|
|
13024
13303
|
};
|
|
13025
13304
|
}
|
|
13305
|
+
const unchangedLink = beforeLink !== void 0 && Object.keys(fields).length === 0;
|
|
13306
|
+
if (unchangedLink) continue;
|
|
13026
13307
|
out.push({
|
|
13027
13308
|
id: String(op.linkId),
|
|
13028
13309
|
kind: ENTITY_CHANGE_KIND.UPDATED,
|
|
@@ -16126,6 +16407,69 @@ function hasInvalidPersistedProgress(action) {
|
|
|
16126
16407
|
return progress !== void 0 && (action.activityIds.length !== 1 || !Number.isFinite(progress) || progress < 0 || progress > 100);
|
|
16127
16408
|
}
|
|
16128
16409
|
|
|
16410
|
+
// src/dispatch/shared/lookahead-conversion-progress.ts
|
|
16411
|
+
function buildConversionProgressSnapshots(activities, criterion) {
|
|
16412
|
+
const snapshots = new Map(
|
|
16413
|
+
activities.map((activity) => [
|
|
16414
|
+
activity.id,
|
|
16415
|
+
structuredCloneActivity(activity)
|
|
16416
|
+
])
|
|
16417
|
+
);
|
|
16418
|
+
const childrenByParent = /* @__PURE__ */ new Map();
|
|
16419
|
+
for (const activity of activities) {
|
|
16420
|
+
if (activity.parentId === null) continue;
|
|
16421
|
+
const siblings = childrenByParent.get(activity.parentId) ?? [];
|
|
16422
|
+
siblings.push(activity);
|
|
16423
|
+
childrenByParent.set(activity.parentId, siblings);
|
|
16424
|
+
}
|
|
16425
|
+
const magnitudes = /* @__PURE__ */ new Map();
|
|
16426
|
+
for (const activity of [...activities].reverse()) {
|
|
16427
|
+
const children = childrenByParent.get(activity.id) ?? [];
|
|
16428
|
+
const isSummary3 = children.length > 0;
|
|
16429
|
+
const magnitude = isSummary3 ? children.reduce(
|
|
16430
|
+
(sum2, child) => sum2 + requiredMagnitude(magnitudes, child.id),
|
|
16431
|
+
0
|
|
16432
|
+
) : liveMagnitude(activity, criterion);
|
|
16433
|
+
magnitudes.set(activity.id, magnitude);
|
|
16434
|
+
if (!isSummary3) continue;
|
|
16435
|
+
const hasMagnitude = magnitude > 0;
|
|
16436
|
+
const permitsEqualShare = criterion !== ACTIVITY_PONDERATOR_CRITERION.COST;
|
|
16437
|
+
for (const child of children) {
|
|
16438
|
+
const snapshot2 = requiredSnapshot(snapshots, child.id);
|
|
16439
|
+
const ponderator = hasMagnitude ? 100 * requiredMagnitude(magnitudes, child.id) / magnitude : permitsEqualShare ? 100 / children.length : 0;
|
|
16440
|
+
snapshots.set(child.id, { ...snapshot2, ponderator });
|
|
16441
|
+
}
|
|
16442
|
+
const weightedChildren = children.map(
|
|
16443
|
+
(child) => requiredSnapshot(snapshots, child.id)
|
|
16444
|
+
);
|
|
16445
|
+
const progress = computeWeightedProgressRollup(weightedChildren);
|
|
16446
|
+
const snapshot = requiredSnapshot(snapshots, activity.id);
|
|
16447
|
+
snapshots.set(activity.id, {
|
|
16448
|
+
...snapshot,
|
|
16449
|
+
progress: roundProgressPerLevel(progress ?? 0)
|
|
16450
|
+
});
|
|
16451
|
+
}
|
|
16452
|
+
return snapshots;
|
|
16453
|
+
}
|
|
16454
|
+
function liveMagnitude(activity, criterion) {
|
|
16455
|
+
if (activity.type === ACTIVITY_TYPE.PROJECT) return 0;
|
|
16456
|
+
if (criterion === ACTIVITY_PONDERATOR_CRITERION.COST) return activity.cost;
|
|
16457
|
+
if (criterion === ACTIVITY_PONDERATOR_CRITERION.WORK_HOURS)
|
|
16458
|
+
return activity.workHours;
|
|
16459
|
+
return activity.durationHours;
|
|
16460
|
+
}
|
|
16461
|
+
function requiredMagnitude(magnitudes, activityId) {
|
|
16462
|
+
const magnitude = magnitudes.get(activityId);
|
|
16463
|
+
if (magnitude === void 0)
|
|
16464
|
+
throw new Error(`Missing conversion magnitude ${activityId}`);
|
|
16465
|
+
return magnitude;
|
|
16466
|
+
}
|
|
16467
|
+
function requiredSnapshot(snapshots, activityId) {
|
|
16468
|
+
const snapshot = snapshots.get(activityId);
|
|
16469
|
+
if (!snapshot) throw new Error(`Missing conversion snapshot ${activityId}`);
|
|
16470
|
+
return snapshot;
|
|
16471
|
+
}
|
|
16472
|
+
|
|
16129
16473
|
// src/dispatch/handlers/activity-lookahead-convert.ts
|
|
16130
16474
|
function buildLookaheadConversionPlan(input, deps) {
|
|
16131
16475
|
const { adapter } = deps;
|
|
@@ -16140,7 +16484,11 @@ function buildLookaheadConversionPlan(input, deps) {
|
|
|
16140
16484
|
(activityId) => requested.has(activityId) && !hasAncestorInSet(activityId, requested, adapter)
|
|
16141
16485
|
);
|
|
16142
16486
|
const branches = conversionRootIds.map(
|
|
16143
|
-
(rootId) => planConversionBranch(
|
|
16487
|
+
(rootId) => planConversionBranch(
|
|
16488
|
+
rootId,
|
|
16489
|
+
adapter,
|
|
16490
|
+
input.criterion ?? deps.sector.activityCreter ?? ACTIVITY_PONDERATOR_CRITERION.DURATION
|
|
16491
|
+
)
|
|
16144
16492
|
);
|
|
16145
16493
|
const conversionGroups = branches.map(
|
|
16146
16494
|
({ conversionRootId, convertedActivities }) => ({
|
|
@@ -16215,7 +16563,7 @@ async function dispatchActivityLookaheadConvert(action, options, deps) {
|
|
|
16215
16563
|
});
|
|
16216
16564
|
return buildConversionResult(plan, context, changes);
|
|
16217
16565
|
}
|
|
16218
|
-
function planConversionBranch(rootId, adapter) {
|
|
16566
|
+
function planConversionBranch(rootId, adapter, criterion) {
|
|
16219
16567
|
const root = requiredActivity(rootId, adapter);
|
|
16220
16568
|
const branch = collectDescendantIds([rootId], adapter);
|
|
16221
16569
|
branch.delete(rootId);
|
|
@@ -16232,15 +16580,19 @@ function planConversionBranch(rootId, adapter) {
|
|
|
16232
16580
|
(activity) => activity.type === ACTIVITY_TYPE.MILESTONE
|
|
16233
16581
|
);
|
|
16234
16582
|
const persistedIds = collectPersistedIds(root, convertible);
|
|
16583
|
+
const progressSnapshots = buildConversionProgressSnapshots(
|
|
16584
|
+
[root, ...convertible],
|
|
16585
|
+
criterion
|
|
16586
|
+
);
|
|
16587
|
+
const rootSnapshot = progressSnapshots.get(root.id);
|
|
16588
|
+
if (!rootSnapshot) throw new Error(`Missing conversion snapshot ${root.id}`);
|
|
16235
16589
|
return {
|
|
16236
16590
|
conversionRootId: rootId,
|
|
16237
|
-
convertedActivities:
|
|
16238
|
-
(activity) => buildConvertedSnapshot(activity, persistedIds)
|
|
16239
|
-
),
|
|
16591
|
+
convertedActivities: [...progressSnapshots.values()].filter((activity) => activity.id !== rootId).map((activity) => buildConvertedSnapshot(activity, persistedIds)),
|
|
16240
16592
|
milestoneMoves: buildMilestoneMoves(root, milestones),
|
|
16241
16593
|
activityIdsToDelete: convertible.map((activity) => activity.id),
|
|
16242
16594
|
formerParent: {
|
|
16243
|
-
activity:
|
|
16595
|
+
activity: rootSnapshot,
|
|
16244
16596
|
hasConvertedActivities: convertible.length > 0
|
|
16245
16597
|
}
|
|
16246
16598
|
};
|
|
@@ -16324,10 +16676,12 @@ function applyFormerParentState(plan, deletedIds, adapter) {
|
|
|
16324
16676
|
idsRemoved: deletedIds
|
|
16325
16677
|
});
|
|
16326
16678
|
adapter.setActivityFields(activity.id, {
|
|
16679
|
+
progress: activity.progress,
|
|
16327
16680
|
isLookahead: activity.isLookahead || hasConvertedActivities,
|
|
16328
16681
|
hasLookaheadTasks: activity.hasLookaheadTasks || hasConvertedActivities,
|
|
16329
16682
|
...cleanup?.fields ?? {}
|
|
16330
16683
|
});
|
|
16684
|
+
adapter.setProgressFallback(activity.id, null);
|
|
16331
16685
|
}
|
|
16332
16686
|
}
|
|
16333
16687
|
function recomputeConversionRollups(plan, adapter) {
|
|
@@ -17406,8 +17760,9 @@ function isDateColumn(column) {
|
|
|
17406
17760
|
return column === COLUMN.START_DATE || column === COLUMN.END_DATE;
|
|
17407
17761
|
}
|
|
17408
17762
|
async function dispatchDatesBatch(action, options, deps) {
|
|
17409
|
-
|
|
17410
|
-
|
|
17763
|
+
const rejection = validateBatchEdits(action, deps);
|
|
17764
|
+
if (rejection !== null) {
|
|
17765
|
+
return { ok: false, reason: rejection };
|
|
17411
17766
|
}
|
|
17412
17767
|
const { adapter, scheduler, sector } = deps;
|
|
17413
17768
|
const verdicts = [];
|
|
@@ -17483,6 +17838,17 @@ async function dispatchDatesBatch(action, options, deps) {
|
|
|
17483
17838
|
})
|
|
17484
17839
|
};
|
|
17485
17840
|
}
|
|
17841
|
+
function validateBatchEdits(action, deps) {
|
|
17842
|
+
const hasInvalidColumn = action.edits.some(
|
|
17843
|
+
(edit) => !isDateColumn(edit.column)
|
|
17844
|
+
);
|
|
17845
|
+
if (hasInvalidColumn) return REJECTION_REASON.INVALID_VALUE;
|
|
17846
|
+
const hasMissingActivity = action.edits.some(
|
|
17847
|
+
(edit) => deps.ctx.activityReader.getActivity(edit.activityId) === null
|
|
17848
|
+
);
|
|
17849
|
+
if (hasMissingActivity) return REJECTION_REASON.ACTIVITY_NOT_FOUND;
|
|
17850
|
+
return null;
|
|
17851
|
+
}
|
|
17486
17852
|
function applyOneEdit(edit, deps, options) {
|
|
17487
17853
|
const { ctx } = deps;
|
|
17488
17854
|
const activityId = edit.activityId;
|
|
@@ -18222,12 +18588,13 @@ function applyBaselineOverlay(state, points, now, reporter, defaultBaseCalendarI
|
|
|
18222
18588
|
|
|
18223
18589
|
// src/propagations/downward/recompute-all-ponderators.ts
|
|
18224
18590
|
function recomputeAllPonderators(criterion, adapter) {
|
|
18591
|
+
const basisById = /* @__PURE__ */ new Map();
|
|
18225
18592
|
adapter.forEachActivity((_a, id) => {
|
|
18226
18593
|
adapter.setActivityField(id, COLUMN.PONDERATOR, 0);
|
|
18227
18594
|
});
|
|
18228
18595
|
adapter.forEachActivity((_a, id) => {
|
|
18229
18596
|
if (adapter.getChildren(id).length > 0) {
|
|
18230
|
-
recomputePonderatorsForParent(String(id), criterion, adapter);
|
|
18597
|
+
recomputePonderatorsForParent(String(id), criterion, adapter, basisById);
|
|
18231
18598
|
}
|
|
18232
18599
|
});
|
|
18233
18600
|
}
|
|
@@ -18235,7 +18602,7 @@ function recomputeAllPonderators(criterion, adapter) {
|
|
|
18235
18602
|
// src/dispatch/shared/baseline-weighted-fields.ts
|
|
18236
18603
|
function recomputeBaselineWeightedFields(deps, criterion) {
|
|
18237
18604
|
recomputeAllPonderators(criterion, deps.adapter);
|
|
18238
|
-
recomputeAllProgressRollup(deps.adapter);
|
|
18605
|
+
recomputeAllProgressRollup(deps.adapter, criterion);
|
|
18239
18606
|
if (deps.now) {
|
|
18240
18607
|
runExpectedProgressBase(
|
|
18241
18608
|
deps.adapter,
|
|
@@ -18279,7 +18646,8 @@ async function dispatchBaselineApply(action, deps) {
|
|
|
18279
18646
|
action.points,
|
|
18280
18647
|
deps.now,
|
|
18281
18648
|
deps.reporter,
|
|
18282
|
-
deps.defaultBaseCalendarId ?? null
|
|
18649
|
+
deps.defaultBaseCalendarId ?? null,
|
|
18650
|
+
void 0
|
|
18283
18651
|
);
|
|
18284
18652
|
applyBaselineVariancePass(deps.adapter, deps.sector.hoursPerDay);
|
|
18285
18653
|
if (activeBaselineSignature(deps) !== activeBaselineBefore) {
|
|
@@ -19010,7 +19378,10 @@ function dispatchCellCopy(action, deps) {
|
|
|
19010
19378
|
if (!pipeline) {
|
|
19011
19379
|
return { ok: false, reason: REJECTION_REASON.NO_PIPELINE_FOR_COLUMN };
|
|
19012
19380
|
}
|
|
19013
|
-
const canonicalValue = readPipelineTargetValue(
|
|
19381
|
+
const canonicalValue = readPipelineTargetValue(
|
|
19382
|
+
activity,
|
|
19383
|
+
pipeline.targetField
|
|
19384
|
+
);
|
|
19014
19385
|
if (action.column === COLUMN.DURATION && !Number.isFinite(canonicalValue)) {
|
|
19015
19386
|
return { ok: false, reason: REJECTION_REASON.INVALID_VALUE };
|
|
19016
19387
|
}
|
|
@@ -19336,6 +19707,7 @@ function coerceActivityFieldValue(field, value) {
|
|
|
19336
19707
|
}
|
|
19337
19708
|
|
|
19338
19709
|
// src/calendar/adapter.ts
|
|
19710
|
+
var WORK_CALENDAR_UNIT = { MINUTE: "minute" };
|
|
19339
19711
|
function createWorkCalendarAdapter(instance, options = {}) {
|
|
19340
19712
|
const defaultUnit = options.defaultUnit ?? CALENDAR_UNIT.HOUR;
|
|
19341
19713
|
return {
|
|
@@ -19356,11 +19728,18 @@ function wrapWorkCalendar(calendar, defaultUnit) {
|
|
|
19356
19728
|
});
|
|
19357
19729
|
},
|
|
19358
19730
|
calculateEndDate(start, durationHours) {
|
|
19359
|
-
|
|
19360
|
-
|
|
19731
|
+
const fractionalHours = defaultUnit === CALENDAR_UNIT.HOUR && !Number.isInteger(durationHours);
|
|
19732
|
+
const sourceRemainder = start.getUTCSeconds() * 1e3 + start.getUTCMilliseconds();
|
|
19733
|
+
const shouldPreserveSourcePrecision = fractionalHours && sourceRemainder !== 0 && calendar.isWorkTime({ date: start, unit: WORK_CALENDAR_UNIT.MINUTE });
|
|
19734
|
+
const calculationStart = shouldPreserveSourcePrecision ? new Date(start.getTime() - sourceRemainder) : start;
|
|
19735
|
+
const end = fractionalHours ? calculateFractionalEndDate(calendar, calculationStart, durationHours) : calendar.calculateEndDate({
|
|
19736
|
+
start_date: calculationStart,
|
|
19361
19737
|
duration: durationHours,
|
|
19362
19738
|
unit: defaultUnit
|
|
19363
19739
|
});
|
|
19740
|
+
if (!shouldPreserveSourcePrecision) return end;
|
|
19741
|
+
const workingEnd = nextWorkingMinute(calendar, end);
|
|
19742
|
+
return new Date(workingEnd.getTime() + sourceRemainder);
|
|
19364
19743
|
},
|
|
19365
19744
|
calculateDuration(start, end) {
|
|
19366
19745
|
return calendar.calculateDuration({
|
|
@@ -19377,6 +19756,91 @@ function wrapWorkCalendar(calendar, defaultUnit) {
|
|
|
19377
19756
|
}
|
|
19378
19757
|
};
|
|
19379
19758
|
}
|
|
19759
|
+
function calculateFractionalEndDate(calendar, start, durationHours) {
|
|
19760
|
+
const roundedMinutes = Math.round(Math.abs(durationHours) * 60);
|
|
19761
|
+
const shouldUseWorkingPrefixes = roundedMinutes > 0 && calendar.isWorkTime({ date: start, unit: WORK_CALENDAR_UNIT.MINUTE });
|
|
19762
|
+
if (!shouldUseWorkingPrefixes)
|
|
19763
|
+
return calendar.calculateEndDate({
|
|
19764
|
+
start_date: start,
|
|
19765
|
+
duration: durationHours * 60,
|
|
19766
|
+
unit: WORK_CALENDAR_UNIT.MINUTE
|
|
19767
|
+
});
|
|
19768
|
+
let end = start;
|
|
19769
|
+
let remainingMinutes = roundedMinutes;
|
|
19770
|
+
const direction = durationHours < 0 ? -1 : 1;
|
|
19771
|
+
while (remainingMinutes > 0) {
|
|
19772
|
+
const reference = direction < 0 ? new Date(end.getTime() - 1) : end;
|
|
19773
|
+
if (!calendar.isWorkTime({ date: reference, unit: WORK_CALENDAR_UNIT.MINUTE })) {
|
|
19774
|
+
end = direction < 0 ? calendar.getClosestWorkTime({
|
|
19775
|
+
date: reference,
|
|
19776
|
+
dir: WORK_TIME_DIRECTION.PAST,
|
|
19777
|
+
unit: WORK_CALENDAR_UNIT.MINUTE
|
|
19778
|
+
}) : nextWorkingMinute(calendar, end);
|
|
19779
|
+
}
|
|
19780
|
+
const prefix = calculateWorkingMinutePrefix(
|
|
19781
|
+
calendar,
|
|
19782
|
+
end,
|
|
19783
|
+
Math.min(remainingMinutes, 60),
|
|
19784
|
+
direction
|
|
19785
|
+
);
|
|
19786
|
+
end = prefix.end;
|
|
19787
|
+
remainingMinutes -= prefix.minutes;
|
|
19788
|
+
}
|
|
19789
|
+
return end;
|
|
19790
|
+
}
|
|
19791
|
+
function calculateWorkingMinutePrefix(calendar, start, maximumMinutes, direction) {
|
|
19792
|
+
const fullPrefix = calendar.calculateEndDate({
|
|
19793
|
+
start_date: start,
|
|
19794
|
+
duration: direction * maximumMinutes,
|
|
19795
|
+
unit: WORK_CALENDAR_UNIT.MINUTE
|
|
19796
|
+
});
|
|
19797
|
+
const isFullPrefixContiguous = fullPrefix.getTime() === start.getTime() + direction * maximumMinutes * 6e4;
|
|
19798
|
+
if (isFullPrefixContiguous)
|
|
19799
|
+
return { end: fullPrefix, minutes: maximumMinutes };
|
|
19800
|
+
let minutes = 0;
|
|
19801
|
+
let limit = maximumMinutes - 1;
|
|
19802
|
+
let end = start;
|
|
19803
|
+
while (minutes < limit) {
|
|
19804
|
+
const testedMinutes = Math.ceil((minutes + limit) / 2);
|
|
19805
|
+
const candidate = calendar.calculateEndDate({
|
|
19806
|
+
start_date: start,
|
|
19807
|
+
duration: direction * testedMinutes,
|
|
19808
|
+
unit: WORK_CALENDAR_UNIT.MINUTE
|
|
19809
|
+
});
|
|
19810
|
+
const isContiguousWorkingTime = candidate.getTime() === start.getTime() + direction * testedMinutes * 6e4;
|
|
19811
|
+
if (isContiguousWorkingTime) {
|
|
19812
|
+
minutes = testedMinutes;
|
|
19813
|
+
end = candidate;
|
|
19814
|
+
} else {
|
|
19815
|
+
limit = testedMinutes - 1;
|
|
19816
|
+
}
|
|
19817
|
+
}
|
|
19818
|
+
if (minutes === 0)
|
|
19819
|
+
throw new Error("Calendar cannot calculate a working-minute prefix");
|
|
19820
|
+
return { end, minutes };
|
|
19821
|
+
}
|
|
19822
|
+
function nextWorkingMinute(calendar, date2) {
|
|
19823
|
+
if (calendar.isWorkTime({ date: date2, unit: WORK_CALENDAR_UNIT.MINUTE }))
|
|
19824
|
+
return date2;
|
|
19825
|
+
const nextWorkingDay2 = calendar.calculateEndDate({
|
|
19826
|
+
start_date: date2,
|
|
19827
|
+
duration: 1,
|
|
19828
|
+
unit: CALENDAR_UNIT.DAY
|
|
19829
|
+
});
|
|
19830
|
+
const nextDayStart = new Date(nextWorkingDay2);
|
|
19831
|
+
nextDayStart.setUTCHours(0, 0, 0, 0);
|
|
19832
|
+
const nextShiftStart = calendar.getClosestWorkTime({
|
|
19833
|
+
date: nextDayStart,
|
|
19834
|
+
dir: WORK_TIME_DIRECTION.FUTURE,
|
|
19835
|
+
unit: WORK_CALENDAR_UNIT.MINUTE
|
|
19836
|
+
});
|
|
19837
|
+
const closest = calendar.getClosestWorkTime({
|
|
19838
|
+
date: date2,
|
|
19839
|
+
dir: WORK_TIME_DIRECTION.FUTURE,
|
|
19840
|
+
unit: WORK_CALENDAR_UNIT.MINUTE
|
|
19841
|
+
});
|
|
19842
|
+
return new Date(Math.min(closest.getTime(), nextShiftStart.getTime()));
|
|
19843
|
+
}
|
|
19380
19844
|
function isArray(obj) {
|
|
19381
19845
|
if (Array.isArray) {
|
|
19382
19846
|
return Array.isArray(obj);
|
|
@@ -23478,13 +23942,263 @@ function computeProjectWorkHours(calendars) {
|
|
|
23478
23942
|
return { startHour: earliestTime(starts), endHour: latestTime(ends) };
|
|
23479
23943
|
}
|
|
23480
23944
|
|
|
23481
|
-
// src/
|
|
23482
|
-
|
|
23483
|
-
|
|
23484
|
-
|
|
23485
|
-
|
|
23486
|
-
|
|
23487
|
-
|
|
23945
|
+
// src/boundary/backend/constants.ts
|
|
23946
|
+
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
23947
|
+
var EXCEPTION_DATE_FORMAT_REGEX = /^(\d{4})[/-](\d{1,2})[/-](\d{1,2})/;
|
|
23948
|
+
var WEEKDAYS_PER_WEEK = 7;
|
|
23949
|
+
var CALENDAR_FALLBACK_WORKING_DAYS = [false, true, true, true, true, true, false];
|
|
23950
|
+
var WORKING_DAY_TRUE_VALUES = /* @__PURE__ */ new Set([
|
|
23951
|
+
"1",
|
|
23952
|
+
"true"
|
|
23953
|
+
]);
|
|
23954
|
+
var DEFAULT_ACTIVITY_CRETER = ACTIVITY_PONDERATOR_CRITERION.DURATION;
|
|
23955
|
+
var DEFAULT_CONSTRAINT_TYPE = CONSTRAINT_TYPE.ASAP;
|
|
23956
|
+
var CONSTRAINT_LABEL_MAP = {
|
|
23957
|
+
ASAP: CONSTRAINT_TYPE.ASAP,
|
|
23958
|
+
ALAP: CONSTRAINT_TYPE.ALAP,
|
|
23959
|
+
SNET: CONSTRAINT_TYPE.SNET,
|
|
23960
|
+
SNLT: CONSTRAINT_TYPE.SNLT,
|
|
23961
|
+
FNET: CONSTRAINT_TYPE.FNET,
|
|
23962
|
+
FNLT: CONSTRAINT_TYPE.FNLT,
|
|
23963
|
+
MSO: CONSTRAINT_TYPE.MSO,
|
|
23964
|
+
MFO: CONSTRAINT_TYPE.MFO,
|
|
23965
|
+
"AS SOON AS POSSIBLE": CONSTRAINT_TYPE.ASAP,
|
|
23966
|
+
"AS LATE AS POSSIBLE": CONSTRAINT_TYPE.ALAP,
|
|
23967
|
+
"START NO EARLIER THAN": CONSTRAINT_TYPE.SNET,
|
|
23968
|
+
"START NO LATER THAN": CONSTRAINT_TYPE.SNLT,
|
|
23969
|
+
"FINISH NO EARLIER THAN": CONSTRAINT_TYPE.FNET,
|
|
23970
|
+
"FINISH NO LATER THAN": CONSTRAINT_TYPE.FNLT,
|
|
23971
|
+
"MUST START ON": CONSTRAINT_TYPE.MSO,
|
|
23972
|
+
"MUST FINISH ON": CONSTRAINT_TYPE.MFO
|
|
23973
|
+
};
|
|
23974
|
+
|
|
23975
|
+
// src/boundary/backend/normalize-calendar.ts
|
|
23976
|
+
function normalizeCalendars(schedulingCalendars, sectorCalendars, rawBaseCalendars, exceptionRange = null) {
|
|
23977
|
+
const hasSchedulingCalendars = schedulingCalendars !== void 0 && schedulingCalendars.length > 0;
|
|
23978
|
+
const source = hasSchedulingCalendars ? schedulingCalendars : sectorCalendars ?? [];
|
|
23979
|
+
const calendars = source.map(
|
|
23980
|
+
(calendar) => parseSchedulingCalendar(calendar, exceptionRange)
|
|
23981
|
+
);
|
|
23982
|
+
const baseCalendars = (rawBaseCalendars ?? []).map(
|
|
23983
|
+
(calendar) => parseBaseCalendar(calendar, exceptionRange)
|
|
23984
|
+
);
|
|
23985
|
+
return {
|
|
23986
|
+
calendars,
|
|
23987
|
+
baseCalendars,
|
|
23988
|
+
knownCalendarIds: new Set(calendars.map((calendar) => calendar.id)),
|
|
23989
|
+
defaultCalendarId: pickDefaultCalendarId(calendars)
|
|
23990
|
+
};
|
|
23991
|
+
}
|
|
23992
|
+
function pickDefaultCalendarId(calendars) {
|
|
23993
|
+
let firstCalendarId = null;
|
|
23994
|
+
for (const calendar of calendars) {
|
|
23995
|
+
firstCalendarId ??= calendar.id;
|
|
23996
|
+
if (calendar.is_default) return calendar.id;
|
|
23997
|
+
}
|
|
23998
|
+
return firstCalendarId;
|
|
23999
|
+
}
|
|
24000
|
+
function buildCalendar(raw, shape) {
|
|
24001
|
+
const workingMask = parseWorkingDays(raw.working_days);
|
|
24002
|
+
const { days, hours } = parseWorktimeDays(raw, workingMask);
|
|
24003
|
+
const dates = parseExceptionDays(
|
|
24004
|
+
shape.exceptionsSource,
|
|
24005
|
+
shape.exceptionRange
|
|
24006
|
+
);
|
|
24007
|
+
const worktime = { days, hours };
|
|
24008
|
+
if (dates) worktime.dates = dates;
|
|
24009
|
+
return {
|
|
24010
|
+
id: `${String(raw.id)}${shape.idSuffix}`,
|
|
24011
|
+
name: raw.name,
|
|
24012
|
+
is_default: shape.isDefault,
|
|
24013
|
+
...shape.baseDefault !== void 0 ? { baseDefault: shape.baseDefault } : {},
|
|
24014
|
+
worktime
|
|
24015
|
+
};
|
|
24016
|
+
}
|
|
24017
|
+
function parseSchedulingCalendar(raw, exceptionRange) {
|
|
24018
|
+
const rawBaseDefault = raw.baseDefault;
|
|
24019
|
+
const baseDefault = typeof rawBaseDefault === "boolean" ? rawBaseDefault : void 0;
|
|
24020
|
+
return buildCalendar(raw, {
|
|
24021
|
+
idSuffix: "",
|
|
24022
|
+
isDefault: Boolean(raw.is_default),
|
|
24023
|
+
baseDefault,
|
|
24024
|
+
exceptionsSource: raw.exceptiondays,
|
|
24025
|
+
exceptionRange
|
|
24026
|
+
});
|
|
24027
|
+
}
|
|
24028
|
+
function parseBaseCalendar(raw, exceptionRange) {
|
|
24029
|
+
return buildCalendar(raw, {
|
|
24030
|
+
idSuffix: "-base",
|
|
24031
|
+
isDefault: false,
|
|
24032
|
+
baseDefault: Boolean(raw.is_default),
|
|
24033
|
+
exceptionsSource: raw.baseexceptiondays ?? raw.exceptiondays,
|
|
24034
|
+
exceptionRange
|
|
24035
|
+
});
|
|
24036
|
+
}
|
|
24037
|
+
function parseExceptionDays(exceptions, range) {
|
|
24038
|
+
if (!Array.isArray(exceptions) || exceptions.length === 0) return null;
|
|
24039
|
+
const map = {};
|
|
24040
|
+
for (const exception of exceptions) {
|
|
24041
|
+
if (!exception) continue;
|
|
24042
|
+
const rangeKeys = expandRangeToUtcKeys(
|
|
24043
|
+
exception.from_date,
|
|
24044
|
+
exception.to_date,
|
|
24045
|
+
range
|
|
24046
|
+
);
|
|
24047
|
+
if (rangeKeys.length === 0) continue;
|
|
24048
|
+
const value = exceptionToDateValue(exception);
|
|
24049
|
+
if (value === void 0) continue;
|
|
24050
|
+
for (const key of rangeKeys) map[key] = value;
|
|
24051
|
+
}
|
|
24052
|
+
return Object.keys(map).length > 0 ? map : null;
|
|
24053
|
+
}
|
|
24054
|
+
function expandRangeToUtcKeys(from, to, range) {
|
|
24055
|
+
const fromTs = parseExceptionDate(from);
|
|
24056
|
+
const toTs = parseExceptionDate(to);
|
|
24057
|
+
if (fromTs === null || toTs === null) return [];
|
|
24058
|
+
if (range && (toTs < range.start || fromTs > range.end)) return [];
|
|
24059
|
+
const keys = [];
|
|
24060
|
+
let cursor = range ? Math.max(fromTs, range.start) : fromTs;
|
|
24061
|
+
const last = range ? Math.min(toTs, range.end) : toTs;
|
|
24062
|
+
while (cursor <= last) {
|
|
24063
|
+
keys.push(String(cursor));
|
|
24064
|
+
cursor += DAY_MS;
|
|
24065
|
+
}
|
|
24066
|
+
return keys;
|
|
24067
|
+
}
|
|
24068
|
+
function parseExceptionDate(raw) {
|
|
24069
|
+
if (typeof raw !== "string") return null;
|
|
24070
|
+
const match = EXCEPTION_DATE_FORMAT_REGEX.exec(raw.trim());
|
|
24071
|
+
if (!match) return null;
|
|
24072
|
+
const year = Number(match[1]);
|
|
24073
|
+
const month = Number(match[2]);
|
|
24074
|
+
const day = Number(match[3]);
|
|
24075
|
+
const isValidDate4 = Number.isFinite(year) && Number.isFinite(month) && Number.isFinite(day);
|
|
24076
|
+
if (!isValidDate4) return null;
|
|
24077
|
+
return Date.UTC(year, month - 1, day);
|
|
24078
|
+
}
|
|
24079
|
+
function exceptionToDateValue(exception) {
|
|
24080
|
+
if (exception.workable === false) return false;
|
|
24081
|
+
const shifts = exception.shifts;
|
|
24082
|
+
if (Array.isArray(shifts) && shifts.length > 0) {
|
|
24083
|
+
const windows = extractExceptionWindows(shifts);
|
|
24084
|
+
if (windows.length > 0) return windows;
|
|
24085
|
+
}
|
|
24086
|
+
return void 0;
|
|
24087
|
+
}
|
|
24088
|
+
var TIME_OF_DAY = /^\d{1,2}:\d{2}$/;
|
|
24089
|
+
function extractExceptionWindows(shifts) {
|
|
24090
|
+
const windows = [];
|
|
24091
|
+
for (const shift of shifts) {
|
|
24092
|
+
const csvs = splitShiftString(shift?.shift_string);
|
|
24093
|
+
if (!csvs) continue;
|
|
24094
|
+
const isCompactWindow = !csvs.startsCsv.includes(",") && !csvs.endsCsv.includes(",");
|
|
24095
|
+
if (isCompactWindow) {
|
|
24096
|
+
const start = csvs.startsCsv.trim();
|
|
24097
|
+
const end = csvs.endsCsv.trim();
|
|
24098
|
+
const isUsableWindow = !isMissingValue(start) && !isMissingValue(end) && TIME_OF_DAY.test(start) && TIME_OF_DAY.test(end);
|
|
24099
|
+
if (isUsableWindow) windows.push(`${start}-${end}`);
|
|
24100
|
+
continue;
|
|
24101
|
+
}
|
|
24102
|
+
const perDay = shiftCsvToPerDayWindows(csvs.startsCsv, csvs.endsCsv);
|
|
24103
|
+
const firstWindow = perDay.find((window2) => window2 !== null);
|
|
24104
|
+
if (firstWindow) windows.push(firstWindow);
|
|
24105
|
+
}
|
|
24106
|
+
windows.sort(compareWindowByStart);
|
|
24107
|
+
return windows;
|
|
24108
|
+
}
|
|
24109
|
+
function windowStartMinutes(window2) {
|
|
24110
|
+
const dash = window2.indexOf("-");
|
|
24111
|
+
const start = dash > 0 ? window2.slice(0, dash) : window2;
|
|
24112
|
+
const [hour, minute] = start.split(":");
|
|
24113
|
+
return (Number(hour) || 0) * 60 + (Number(minute) || 0);
|
|
24114
|
+
}
|
|
24115
|
+
function compareWindowByStart(first, second) {
|
|
24116
|
+
return windowStartMinutes(first) - windowStartMinutes(second);
|
|
24117
|
+
}
|
|
24118
|
+
function parseWorktimeDays(raw, workingMask) {
|
|
24119
|
+
const windowsByDay = Array.from({ length: 7 }, () => []);
|
|
24120
|
+
const addCsvPair = (startsCsv, endsCsv) => {
|
|
24121
|
+
const perDay = shiftCsvToPerDayWindows(startsCsv, endsCsv);
|
|
24122
|
+
for (let i = 0; i < 7; i += 1) {
|
|
24123
|
+
const window2 = perDay[i];
|
|
24124
|
+
const dayWindows = windowsByDay[i];
|
|
24125
|
+
if (window2 && dayWindows) dayWindows.push(window2);
|
|
24126
|
+
}
|
|
24127
|
+
};
|
|
24128
|
+
const hasNestedShifts = Array.isArray(raw.shifts) && raw.shifts.length > 0;
|
|
24129
|
+
const hasFlatShift = typeof raw.shift_start === "string" && typeof raw.shift_end === "string";
|
|
24130
|
+
if (hasNestedShifts) {
|
|
24131
|
+
for (const shift of raw.shifts) {
|
|
24132
|
+
const csvs = splitShiftString(shift?.shift_string);
|
|
24133
|
+
if (csvs) addCsvPair(csvs.startsCsv, csvs.endsCsv);
|
|
24134
|
+
}
|
|
24135
|
+
} else if (hasFlatShift) {
|
|
24136
|
+
addCsvPair(raw.shift_start, raw.shift_end);
|
|
24137
|
+
}
|
|
24138
|
+
for (const dayWindows of windowsByDay) dayWindows.sort(compareWindowByStart);
|
|
24139
|
+
const firstWorkingWindows = windowsByDay.find(
|
|
24140
|
+
(windows, i) => Boolean(workingMask[i]) && windows.length > 0
|
|
24141
|
+
);
|
|
24142
|
+
const defaultHours = firstWorkingWindows ?? [];
|
|
24143
|
+
const days = workingMask.map((isWorking, i) => {
|
|
24144
|
+
if (!isWorking) return false;
|
|
24145
|
+
const dayWindows = windowsByDay[i];
|
|
24146
|
+
return dayWindows && dayWindows.length > 0 ? dayWindows : defaultHours;
|
|
24147
|
+
});
|
|
24148
|
+
return { days, hours: defaultHours };
|
|
24149
|
+
}
|
|
24150
|
+
function shiftCsvToPerDayWindows(startsCsv, endsCsv) {
|
|
24151
|
+
const empty = Array.from(
|
|
24152
|
+
{ length: WEEKDAYS_PER_WEEK },
|
|
24153
|
+
() => null
|
|
24154
|
+
);
|
|
24155
|
+
if (typeof startsCsv !== "string" || typeof endsCsv !== "string") {
|
|
24156
|
+
return empty;
|
|
24157
|
+
}
|
|
24158
|
+
const starts = startsCsv.split(",").map((value) => value.trim());
|
|
24159
|
+
const ends = endsCsv.split(",").map((value) => value.trim());
|
|
24160
|
+
const isAlignedWeek = starts.length === ends.length && starts.length > 0 && starts.length <= WEEKDAYS_PER_WEEK;
|
|
24161
|
+
if (!isAlignedWeek) return empty;
|
|
24162
|
+
const windows = [...empty];
|
|
24163
|
+
for (let i = 0; i < starts.length; i += 1) {
|
|
24164
|
+
const start = starts[i];
|
|
24165
|
+
const end = ends[i];
|
|
24166
|
+
if (isMissingValue(start) || isMissingValue(end)) continue;
|
|
24167
|
+
windows[i] = `${start}-${end}`;
|
|
24168
|
+
}
|
|
24169
|
+
return windows;
|
|
24170
|
+
}
|
|
24171
|
+
function splitShiftString(raw) {
|
|
24172
|
+
if (typeof raw !== "string") return null;
|
|
24173
|
+
const dash = raw.indexOf("-");
|
|
24174
|
+
if (dash <= 0) return null;
|
|
24175
|
+
return {
|
|
24176
|
+
startsCsv: raw.slice(0, dash),
|
|
24177
|
+
endsCsv: raw.slice(dash + 1)
|
|
24178
|
+
};
|
|
24179
|
+
}
|
|
24180
|
+
function parseWorkingDays(csv) {
|
|
24181
|
+
if (typeof csv !== "string") return [...CALENDAR_FALLBACK_WORKING_DAYS];
|
|
24182
|
+
const parts = csv.split(",").map((value) => value.trim());
|
|
24183
|
+
if (parts.length !== WEEKDAYS_PER_WEEK) {
|
|
24184
|
+
return [...CALENDAR_FALLBACK_WORKING_DAYS];
|
|
24185
|
+
}
|
|
24186
|
+
return parts.map((part) => WORKING_DAY_TRUE_VALUES.has(part));
|
|
24187
|
+
}
|
|
24188
|
+
var MISSING_SHIFT_VALUES = /* @__PURE__ */ new Set(["false", "null"]);
|
|
24189
|
+
function isMissingValue(value) {
|
|
24190
|
+
return !value || MISSING_SHIFT_VALUES.has(value);
|
|
24191
|
+
}
|
|
24192
|
+
|
|
24193
|
+
// src/internal/state/pipeline-context.ts
|
|
24194
|
+
function buildPipelineContext(adapter, options) {
|
|
24195
|
+
return {
|
|
24196
|
+
calendars: adapter.calendarReader,
|
|
24197
|
+
hasCalendar: (calendarId) => options.calendars.has(calendarId),
|
|
24198
|
+
getDefaultCalendarId: () => pickDefaultCalendarId(options.calendars.values()),
|
|
24199
|
+
hierarchy: createStateBackedHierarchyReader(adapter),
|
|
24200
|
+
activityReader: createStateBackedActivityReader(adapter),
|
|
24201
|
+
dateFormat: options.dateFormat ?? "YYYY-MM-DD",
|
|
23488
24202
|
customHours: options.customHours ?? {},
|
|
23489
24203
|
hoursPerDay: options.hoursPerDay
|
|
23490
24204
|
};
|
|
@@ -24767,36 +25481,6 @@ var SaveTracker = class _SaveTracker {
|
|
|
24767
25481
|
}
|
|
24768
25482
|
};
|
|
24769
25483
|
|
|
24770
|
-
// src/boundary/backend/constants.ts
|
|
24771
|
-
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
24772
|
-
var EXCEPTION_DATE_FORMAT_REGEX = /^(\d{4})[/-](\d{1,2})[/-](\d{1,2})/;
|
|
24773
|
-
var WEEKDAYS_PER_WEEK = 7;
|
|
24774
|
-
var CALENDAR_FALLBACK_WORKING_DAYS = [false, true, true, true, true, true, false];
|
|
24775
|
-
var WORKING_DAY_TRUE_VALUES = /* @__PURE__ */ new Set([
|
|
24776
|
-
"1",
|
|
24777
|
-
"true"
|
|
24778
|
-
]);
|
|
24779
|
-
var DEFAULT_ACTIVITY_CRETER = ACTIVITY_PONDERATOR_CRITERION.DURATION;
|
|
24780
|
-
var DEFAULT_CONSTRAINT_TYPE = CONSTRAINT_TYPE.ASAP;
|
|
24781
|
-
var CONSTRAINT_LABEL_MAP = {
|
|
24782
|
-
ASAP: CONSTRAINT_TYPE.ASAP,
|
|
24783
|
-
ALAP: CONSTRAINT_TYPE.ALAP,
|
|
24784
|
-
SNET: CONSTRAINT_TYPE.SNET,
|
|
24785
|
-
SNLT: CONSTRAINT_TYPE.SNLT,
|
|
24786
|
-
FNET: CONSTRAINT_TYPE.FNET,
|
|
24787
|
-
FNLT: CONSTRAINT_TYPE.FNLT,
|
|
24788
|
-
MSO: CONSTRAINT_TYPE.MSO,
|
|
24789
|
-
MFO: CONSTRAINT_TYPE.MFO,
|
|
24790
|
-
"AS SOON AS POSSIBLE": CONSTRAINT_TYPE.ASAP,
|
|
24791
|
-
"AS LATE AS POSSIBLE": CONSTRAINT_TYPE.ALAP,
|
|
24792
|
-
"START NO EARLIER THAN": CONSTRAINT_TYPE.SNET,
|
|
24793
|
-
"START NO LATER THAN": CONSTRAINT_TYPE.SNLT,
|
|
24794
|
-
"FINISH NO EARLIER THAN": CONSTRAINT_TYPE.FNET,
|
|
24795
|
-
"FINISH NO LATER THAN": CONSTRAINT_TYPE.FNLT,
|
|
24796
|
-
"MUST START ON": CONSTRAINT_TYPE.MSO,
|
|
24797
|
-
"MUST FINISH ON": CONSTRAINT_TYPE.MFO
|
|
24798
|
-
};
|
|
24799
|
-
|
|
24800
25484
|
// src/boundary/backend/normalize-activity.ts
|
|
24801
25485
|
function normalizeActivities(rawActivities, context) {
|
|
24802
25486
|
const hiddenIds = [];
|
|
@@ -24915,332 +25599,115 @@ function parseBaselinePoints(raw, reporter, recordDiagnostic, activityId, isMile
|
|
|
24915
25599
|
record: recordDiagnostic,
|
|
24916
25600
|
sampleId: activityId
|
|
24917
25601
|
},
|
|
24918
|
-
isMilestone
|
|
24919
|
-
)
|
|
24920
|
-
).filter((point) => point !== null);
|
|
24921
|
-
}
|
|
24922
|
-
function parseActivity(raw, context) {
|
|
24923
|
-
const calendarId = resolveCalendarId2(
|
|
24924
|
-
raw.calendarId,
|
|
24925
|
-
context.knownCalendarIds,
|
|
24926
|
-
context.defaultCalendarId
|
|
24927
|
-
);
|
|
24928
|
-
const inheritedDefaultCalendar = raw.calendarId == null || !context.knownCalendarIds.has(String(raw.calendarId));
|
|
24929
|
-
const progress = parseProgress(
|
|
24930
|
-
raw.progress,
|
|
24931
|
-
context.reporter,
|
|
24932
|
-
context.recordDiagnostic,
|
|
24933
|
-
String(raw.unique_id)
|
|
24934
|
-
);
|
|
24935
|
-
const { constraintType, constraintDate } = resolveConstraint(
|
|
24936
|
-
raw,
|
|
24937
|
-
context.reporter,
|
|
24938
|
-
context.recordDiagnostic
|
|
24939
|
-
);
|
|
24940
|
-
const isMilestone = raw.type === ACTIVITY_TYPE.MILESTONE;
|
|
24941
|
-
const startDate = parseBackendDate(raw.start_date);
|
|
24942
|
-
const endDate = isMilestone ? startDate : parseBackendDate(raw.end_date);
|
|
24943
|
-
const durationDays = isMilestone ? 0 : Number(raw.duration);
|
|
24944
|
-
const isCritical = parseCriticality(raw, context.reporter);
|
|
24945
|
-
return {
|
|
24946
|
-
id: String(raw.unique_id),
|
|
24947
|
-
proplannerId: normalizePersistedActivityId(raw.id),
|
|
24948
|
-
parentId: parseParentId(raw.parent_id),
|
|
24949
|
-
name: raw.name,
|
|
24950
|
-
description: raw.description ?? "",
|
|
24951
|
-
type: raw.type,
|
|
24952
|
-
startDate,
|
|
24953
|
-
endDate,
|
|
24954
|
-
durationHours: durationToHours(durationDays, context.hoursPerDay),
|
|
24955
|
-
constraintType,
|
|
24956
|
-
constraintDate,
|
|
24957
|
-
autoScheduling: isAutoSchedulingEnabledForProgress(progress),
|
|
24958
|
-
calendarId,
|
|
24959
|
-
assignedDefaultCalendar: calendarId != null && inheritedDefaultCalendar,
|
|
24960
|
-
dateOrigin: raw.date_origin == null ? null : parseBackendDate(raw.date_origin),
|
|
24961
|
-
progress,
|
|
24962
|
-
cost: Number(raw.cost),
|
|
24963
|
-
usedCost: Number(raw.used_cost ?? 0),
|
|
24964
|
-
realCost: Number(raw.real_cost ?? 0),
|
|
24965
|
-
workHours: Number(raw.hhWorkTime),
|
|
24966
|
-
realWorkHours: Number(raw.real_work ?? 0),
|
|
24967
|
-
ponderator: Number(raw.ponderator ?? 0),
|
|
24968
|
-
hasCustomPonderator: raw.hasCustomPonderator,
|
|
24969
|
-
correlativeId: raw.correlative_id,
|
|
24970
|
-
uniqueCorrelativeId: raw.unique_correlative_id,
|
|
24971
|
-
customId: normalizeCustomId(raw),
|
|
24972
|
-
subcontractId: raw.subcontractId,
|
|
24973
|
-
isLookahead: raw.isOnLookahead,
|
|
24974
|
-
hasLookaheadTasks: Array.isArray(raw.tasks) && raw.tasks.length > 0,
|
|
24975
|
-
newActivityIds: parseNewActivityIds(raw.newActivitiesArray),
|
|
24976
|
-
hasNewActivities: raw.hasNewActivities ?? false,
|
|
24977
|
-
...raw.isNewActivity === true ? { isNewActivity: true } : {},
|
|
24978
|
-
pendingRequestIds: parseIdList(raw.pendingRequests),
|
|
24979
|
-
responsableIds: parseIdList(raw.responsables),
|
|
24980
|
-
tagIds: parseIdList(raw.tags),
|
|
24981
|
-
baselinePoints: parseBaselinePoints(
|
|
24982
|
-
raw.baseline_points,
|
|
24983
|
-
context.reporter,
|
|
24984
|
-
context.recordDiagnostic,
|
|
24985
|
-
String(raw.unique_id),
|
|
24986
|
-
isMilestone
|
|
24987
|
-
),
|
|
24988
|
-
baselineSnapshot: null,
|
|
24989
|
-
baselineVarianceDays: null,
|
|
24990
|
-
recursiveDurationHours: durationToHours(
|
|
24991
|
-
Number(raw.sumOfDurationRecursively ?? 0),
|
|
24992
|
-
context.hoursPerDay
|
|
24993
|
-
),
|
|
24994
|
-
calendarDuration: computeCalendarDuration({
|
|
24995
|
-
type: raw.type,
|
|
24996
|
-
startDate,
|
|
24997
|
-
endDate
|
|
24998
|
-
}),
|
|
24999
|
-
isCritical,
|
|
25000
|
-
freeSlackHours: null,
|
|
25001
|
-
expectedProgress: null,
|
|
25002
|
-
expectedProgressBaseline: null,
|
|
25003
|
-
status: null,
|
|
25004
|
-
criticalPath: null
|
|
25005
|
-
};
|
|
25006
|
-
}
|
|
25007
|
-
function normalizeCustomId(raw) {
|
|
25008
|
-
return raw.has_childs ? null : raw.custom_id;
|
|
25009
|
-
}
|
|
25010
|
-
function forceRootProjectToRoot(activities) {
|
|
25011
|
-
const rootProject = activities.find(
|
|
25012
|
-
(activity) => activity.correlativeId === 0 && activity.type === ACTIVITY_TYPE.PROJECT
|
|
25013
|
-
);
|
|
25014
|
-
if (rootProject) rootProject.parentId = null;
|
|
25015
|
-
}
|
|
25016
|
-
function reparentOrphansToRoot(activities, ids, reporter, recordDiagnostic) {
|
|
25017
|
-
for (const activity of activities) {
|
|
25018
|
-
if (activity.parentId === null) continue;
|
|
25019
|
-
if (!ids.has(activity.parentId)) {
|
|
25020
|
-
reporter.warn(
|
|
25021
|
-
`[parseFromBackend] activity "${activity.id}" references unknown parent "${activity.parentId}" \u2014 re-parenting to root (null)`
|
|
25022
|
-
);
|
|
25023
|
-
recordDiagnostic(LOAD_DIAGNOSTIC_CODE.ORPHAN_ACTIVITY, activity.id);
|
|
25024
|
-
activity.parentId = null;
|
|
25025
|
-
}
|
|
25026
|
-
}
|
|
25027
|
-
}
|
|
25028
|
-
|
|
25029
|
-
// src/boundary/backend/normalize-calendar.ts
|
|
25030
|
-
function normalizeCalendars(schedulingCalendars, sectorCalendars, rawBaseCalendars, exceptionRange = null) {
|
|
25031
|
-
const hasSchedulingCalendars = schedulingCalendars !== void 0 && schedulingCalendars.length > 0;
|
|
25032
|
-
const source = hasSchedulingCalendars ? schedulingCalendars : sectorCalendars ?? [];
|
|
25033
|
-
const calendars = source.map(
|
|
25034
|
-
(calendar) => parseSchedulingCalendar(calendar, exceptionRange)
|
|
25035
|
-
);
|
|
25036
|
-
const baseCalendars = (rawBaseCalendars ?? []).map(
|
|
25037
|
-
(calendar) => parseBaseCalendar(calendar, exceptionRange)
|
|
25038
|
-
);
|
|
25039
|
-
return {
|
|
25040
|
-
calendars,
|
|
25041
|
-
baseCalendars,
|
|
25042
|
-
knownCalendarIds: new Set(calendars.map((calendar) => calendar.id)),
|
|
25043
|
-
defaultCalendarId: pickDefaultCalendarId(calendars)
|
|
25044
|
-
};
|
|
25045
|
-
}
|
|
25046
|
-
function pickDefaultCalendarId(calendars) {
|
|
25047
|
-
const flaggedDefault = calendars.find((calendar) => calendar.is_default);
|
|
25048
|
-
if (flaggedDefault) return flaggedDefault.id;
|
|
25049
|
-
const firstCalendar = calendars[0];
|
|
25050
|
-
if (firstCalendar) return firstCalendar.id;
|
|
25051
|
-
return null;
|
|
25052
|
-
}
|
|
25053
|
-
function buildCalendar(raw, shape) {
|
|
25054
|
-
const workingMask = parseWorkingDays(raw.working_days);
|
|
25055
|
-
const { days, hours } = parseWorktimeDays(raw, workingMask);
|
|
25056
|
-
const dates = parseExceptionDays(
|
|
25057
|
-
shape.exceptionsSource,
|
|
25058
|
-
shape.exceptionRange
|
|
25059
|
-
);
|
|
25060
|
-
const worktime = { days, hours };
|
|
25061
|
-
if (dates) worktime.dates = dates;
|
|
25062
|
-
return {
|
|
25063
|
-
id: `${String(raw.id)}${shape.idSuffix}`,
|
|
25064
|
-
name: raw.name,
|
|
25065
|
-
is_default: shape.isDefault,
|
|
25066
|
-
...shape.baseDefault !== void 0 ? { baseDefault: shape.baseDefault } : {},
|
|
25067
|
-
worktime
|
|
25068
|
-
};
|
|
25069
|
-
}
|
|
25070
|
-
function parseSchedulingCalendar(raw, exceptionRange) {
|
|
25071
|
-
const rawBaseDefault = raw.baseDefault;
|
|
25072
|
-
const baseDefault = typeof rawBaseDefault === "boolean" ? rawBaseDefault : void 0;
|
|
25073
|
-
return buildCalendar(raw, {
|
|
25074
|
-
idSuffix: "",
|
|
25075
|
-
isDefault: Boolean(raw.is_default),
|
|
25076
|
-
baseDefault,
|
|
25077
|
-
exceptionsSource: raw.exceptiondays,
|
|
25078
|
-
exceptionRange
|
|
25079
|
-
});
|
|
25080
|
-
}
|
|
25081
|
-
function parseBaseCalendar(raw, exceptionRange) {
|
|
25082
|
-
return buildCalendar(raw, {
|
|
25083
|
-
idSuffix: "-base",
|
|
25084
|
-
isDefault: false,
|
|
25085
|
-
baseDefault: Boolean(raw.is_default),
|
|
25086
|
-
exceptionsSource: raw.baseexceptiondays ?? raw.exceptiondays,
|
|
25087
|
-
exceptionRange
|
|
25088
|
-
});
|
|
25089
|
-
}
|
|
25090
|
-
function parseExceptionDays(exceptions, range) {
|
|
25091
|
-
if (!Array.isArray(exceptions) || exceptions.length === 0) return null;
|
|
25092
|
-
const map = {};
|
|
25093
|
-
for (const exception of exceptions) {
|
|
25094
|
-
if (!exception) continue;
|
|
25095
|
-
const rangeKeys = expandRangeToUtcKeys(
|
|
25096
|
-
exception.from_date,
|
|
25097
|
-
exception.to_date,
|
|
25098
|
-
range
|
|
25099
|
-
);
|
|
25100
|
-
if (rangeKeys.length === 0) continue;
|
|
25101
|
-
const value = exceptionToDateValue(exception);
|
|
25102
|
-
if (value === void 0) continue;
|
|
25103
|
-
for (const key of rangeKeys) map[key] = value;
|
|
25104
|
-
}
|
|
25105
|
-
return Object.keys(map).length > 0 ? map : null;
|
|
25106
|
-
}
|
|
25107
|
-
function expandRangeToUtcKeys(from, to, range) {
|
|
25108
|
-
const fromTs = parseExceptionDate(from);
|
|
25109
|
-
const toTs = parseExceptionDate(to);
|
|
25110
|
-
if (fromTs === null || toTs === null) return [];
|
|
25111
|
-
if (range && (toTs < range.start || fromTs > range.end)) return [];
|
|
25112
|
-
const keys = [];
|
|
25113
|
-
let cursor = range ? Math.max(fromTs, range.start) : fromTs;
|
|
25114
|
-
const last = range ? Math.min(toTs, range.end) : toTs;
|
|
25115
|
-
while (cursor <= last) {
|
|
25116
|
-
keys.push(String(cursor));
|
|
25117
|
-
cursor += DAY_MS;
|
|
25118
|
-
}
|
|
25119
|
-
return keys;
|
|
25120
|
-
}
|
|
25121
|
-
function parseExceptionDate(raw) {
|
|
25122
|
-
if (typeof raw !== "string") return null;
|
|
25123
|
-
const match = EXCEPTION_DATE_FORMAT_REGEX.exec(raw.trim());
|
|
25124
|
-
if (!match) return null;
|
|
25125
|
-
const year = Number(match[1]);
|
|
25126
|
-
const month = Number(match[2]);
|
|
25127
|
-
const day = Number(match[3]);
|
|
25128
|
-
const isValidDate4 = Number.isFinite(year) && Number.isFinite(month) && Number.isFinite(day);
|
|
25129
|
-
if (!isValidDate4) return null;
|
|
25130
|
-
return Date.UTC(year, month - 1, day);
|
|
25131
|
-
}
|
|
25132
|
-
function exceptionToDateValue(exception) {
|
|
25133
|
-
if (exception.workable === false) return false;
|
|
25134
|
-
const shifts = exception.shifts;
|
|
25135
|
-
if (Array.isArray(shifts) && shifts.length > 0) {
|
|
25136
|
-
const windows = extractExceptionWindows(shifts);
|
|
25137
|
-
if (windows.length > 0) return windows;
|
|
25138
|
-
}
|
|
25139
|
-
return void 0;
|
|
25140
|
-
}
|
|
25141
|
-
var TIME_OF_DAY = /^\d{1,2}:\d{2}$/;
|
|
25142
|
-
function extractExceptionWindows(shifts) {
|
|
25143
|
-
const windows = [];
|
|
25144
|
-
for (const shift of shifts) {
|
|
25145
|
-
const csvs = splitShiftString(shift?.shift_string);
|
|
25146
|
-
if (!csvs) continue;
|
|
25147
|
-
const isCompactWindow = !csvs.startsCsv.includes(",") && !csvs.endsCsv.includes(",");
|
|
25148
|
-
if (isCompactWindow) {
|
|
25149
|
-
const start = csvs.startsCsv.trim();
|
|
25150
|
-
const end = csvs.endsCsv.trim();
|
|
25151
|
-
const isUsableWindow = !isMissingValue(start) && !isMissingValue(end) && TIME_OF_DAY.test(start) && TIME_OF_DAY.test(end);
|
|
25152
|
-
if (isUsableWindow) windows.push(`${start}-${end}`);
|
|
25153
|
-
continue;
|
|
25154
|
-
}
|
|
25155
|
-
const perDay = shiftCsvToPerDayWindows(csvs.startsCsv, csvs.endsCsv);
|
|
25156
|
-
const firstWindow = perDay.find((window2) => window2 !== null);
|
|
25157
|
-
if (firstWindow) windows.push(firstWindow);
|
|
25158
|
-
}
|
|
25159
|
-
windows.sort(compareWindowByStart);
|
|
25160
|
-
return windows;
|
|
25161
|
-
}
|
|
25162
|
-
function windowStartMinutes(window2) {
|
|
25163
|
-
const dash = window2.indexOf("-");
|
|
25164
|
-
const start = dash > 0 ? window2.slice(0, dash) : window2;
|
|
25165
|
-
const [hour, minute] = start.split(":");
|
|
25166
|
-
return (Number(hour) || 0) * 60 + (Number(minute) || 0);
|
|
25167
|
-
}
|
|
25168
|
-
function compareWindowByStart(first, second) {
|
|
25169
|
-
return windowStartMinutes(first) - windowStartMinutes(second);
|
|
25170
|
-
}
|
|
25171
|
-
function parseWorktimeDays(raw, workingMask) {
|
|
25172
|
-
const windowsByDay = Array.from({ length: 7 }, () => []);
|
|
25173
|
-
const addCsvPair = (startsCsv, endsCsv) => {
|
|
25174
|
-
const perDay = shiftCsvToPerDayWindows(startsCsv, endsCsv);
|
|
25175
|
-
for (let i = 0; i < 7; i += 1) {
|
|
25176
|
-
const window2 = perDay[i];
|
|
25177
|
-
const dayWindows = windowsByDay[i];
|
|
25178
|
-
if (window2 && dayWindows) dayWindows.push(window2);
|
|
25179
|
-
}
|
|
25180
|
-
};
|
|
25181
|
-
const hasNestedShifts = Array.isArray(raw.shifts) && raw.shifts.length > 0;
|
|
25182
|
-
const hasFlatShift = typeof raw.shift_start === "string" && typeof raw.shift_end === "string";
|
|
25183
|
-
if (hasNestedShifts) {
|
|
25184
|
-
for (const shift of raw.shifts) {
|
|
25185
|
-
const csvs = splitShiftString(shift?.shift_string);
|
|
25186
|
-
if (csvs) addCsvPair(csvs.startsCsv, csvs.endsCsv);
|
|
25187
|
-
}
|
|
25188
|
-
} else if (hasFlatShift) {
|
|
25189
|
-
addCsvPair(raw.shift_start, raw.shift_end);
|
|
25190
|
-
}
|
|
25191
|
-
for (const dayWindows of windowsByDay) dayWindows.sort(compareWindowByStart);
|
|
25192
|
-
const firstWorkingWindows = windowsByDay.find(
|
|
25193
|
-
(windows, i) => Boolean(workingMask[i]) && windows.length > 0
|
|
25194
|
-
);
|
|
25195
|
-
const defaultHours = firstWorkingWindows ?? [];
|
|
25196
|
-
const days = workingMask.map((isWorking, i) => {
|
|
25197
|
-
if (!isWorking) return false;
|
|
25198
|
-
const dayWindows = windowsByDay[i];
|
|
25199
|
-
return dayWindows && dayWindows.length > 0 ? dayWindows : defaultHours;
|
|
25200
|
-
});
|
|
25201
|
-
return { days, hours: defaultHours };
|
|
25202
|
-
}
|
|
25203
|
-
function shiftCsvToPerDayWindows(startsCsv, endsCsv) {
|
|
25204
|
-
const empty = Array.from(
|
|
25205
|
-
{ length: WEEKDAYS_PER_WEEK },
|
|
25206
|
-
() => null
|
|
25207
|
-
);
|
|
25208
|
-
if (typeof startsCsv !== "string" || typeof endsCsv !== "string") {
|
|
25209
|
-
return empty;
|
|
25210
|
-
}
|
|
25211
|
-
const starts = startsCsv.split(",").map((value) => value.trim());
|
|
25212
|
-
const ends = endsCsv.split(",").map((value) => value.trim());
|
|
25213
|
-
const isAlignedWeek = starts.length === ends.length && starts.length > 0 && starts.length <= WEEKDAYS_PER_WEEK;
|
|
25214
|
-
if (!isAlignedWeek) return empty;
|
|
25215
|
-
const windows = [...empty];
|
|
25216
|
-
for (let i = 0; i < starts.length; i += 1) {
|
|
25217
|
-
const start = starts[i];
|
|
25218
|
-
const end = ends[i];
|
|
25219
|
-
if (isMissingValue(start) || isMissingValue(end)) continue;
|
|
25220
|
-
windows[i] = `${start}-${end}`;
|
|
25221
|
-
}
|
|
25222
|
-
return windows;
|
|
25602
|
+
isMilestone
|
|
25603
|
+
)
|
|
25604
|
+
).filter((point) => point !== null);
|
|
25223
25605
|
}
|
|
25224
|
-
function
|
|
25225
|
-
|
|
25226
|
-
|
|
25227
|
-
|
|
25606
|
+
function parseActivity(raw, context) {
|
|
25607
|
+
const calendarId = resolveCalendarId2(
|
|
25608
|
+
raw.calendarId,
|
|
25609
|
+
context.knownCalendarIds,
|
|
25610
|
+
context.defaultCalendarId
|
|
25611
|
+
);
|
|
25612
|
+
const inheritedDefaultCalendar = raw.calendarId == null || !context.knownCalendarIds.has(String(raw.calendarId));
|
|
25613
|
+
const progress = parseProgress(
|
|
25614
|
+
raw.progress,
|
|
25615
|
+
context.reporter,
|
|
25616
|
+
context.recordDiagnostic,
|
|
25617
|
+
String(raw.unique_id)
|
|
25618
|
+
);
|
|
25619
|
+
const { constraintType, constraintDate } = resolveConstraint(
|
|
25620
|
+
raw,
|
|
25621
|
+
context.reporter,
|
|
25622
|
+
context.recordDiagnostic
|
|
25623
|
+
);
|
|
25624
|
+
const isMilestone = raw.type === ACTIVITY_TYPE.MILESTONE;
|
|
25625
|
+
const startDate = parseBackendDate(raw.start_date);
|
|
25626
|
+
const endDate = isMilestone ? startDate : parseBackendDate(raw.end_date);
|
|
25627
|
+
const durationDays = isMilestone ? 0 : Number(raw.duration);
|
|
25628
|
+
const isCritical = parseCriticality(raw, context.reporter);
|
|
25228
25629
|
return {
|
|
25229
|
-
|
|
25230
|
-
|
|
25630
|
+
id: String(raw.unique_id),
|
|
25631
|
+
proplannerId: normalizePersistedActivityId(raw.id),
|
|
25632
|
+
parentId: parseParentId(raw.parent_id),
|
|
25633
|
+
name: raw.name,
|
|
25634
|
+
description: raw.description ?? "",
|
|
25635
|
+
type: raw.type,
|
|
25636
|
+
startDate,
|
|
25637
|
+
endDate,
|
|
25638
|
+
durationHours: durationToHours(durationDays, context.hoursPerDay),
|
|
25639
|
+
constraintType,
|
|
25640
|
+
constraintDate,
|
|
25641
|
+
autoScheduling: isAutoSchedulingEnabledForProgress(progress),
|
|
25642
|
+
calendarId,
|
|
25643
|
+
assignedDefaultCalendar: calendarId != null && inheritedDefaultCalendar,
|
|
25644
|
+
dateOrigin: raw.date_origin == null ? null : parseBackendDate(raw.date_origin),
|
|
25645
|
+
progress,
|
|
25646
|
+
cost: Number(raw.cost),
|
|
25647
|
+
usedCost: Number(raw.used_cost ?? 0),
|
|
25648
|
+
realCost: Number(raw.real_cost ?? 0),
|
|
25649
|
+
workHours: Number(raw.hhWorkTime),
|
|
25650
|
+
realWorkHours: Number(raw.real_work ?? 0),
|
|
25651
|
+
ponderator: Number(raw.ponderator ?? 0),
|
|
25652
|
+
hasCustomPonderator: raw.hasCustomPonderator,
|
|
25653
|
+
correlativeId: raw.correlative_id,
|
|
25654
|
+
uniqueCorrelativeId: raw.unique_correlative_id,
|
|
25655
|
+
customId: normalizeCustomId(raw),
|
|
25656
|
+
subcontractId: raw.subcontractId,
|
|
25657
|
+
isLookahead: raw.isOnLookahead,
|
|
25658
|
+
hasLookaheadTasks: Array.isArray(raw.tasks) && raw.tasks.length > 0,
|
|
25659
|
+
newActivityIds: parseNewActivityIds(raw.newActivitiesArray),
|
|
25660
|
+
hasNewActivities: raw.hasNewActivities ?? false,
|
|
25661
|
+
...raw.isNewActivity === true ? { isNewActivity: true } : {},
|
|
25662
|
+
pendingRequestIds: parseIdList(raw.pendingRequests),
|
|
25663
|
+
responsableIds: parseIdList(raw.responsables),
|
|
25664
|
+
tagIds: parseIdList(raw.tags),
|
|
25665
|
+
baselinePoints: parseBaselinePoints(
|
|
25666
|
+
raw.baseline_points,
|
|
25667
|
+
context.reporter,
|
|
25668
|
+
context.recordDiagnostic,
|
|
25669
|
+
String(raw.unique_id),
|
|
25670
|
+
isMilestone
|
|
25671
|
+
),
|
|
25672
|
+
baselineSnapshot: null,
|
|
25673
|
+
baselineVarianceDays: null,
|
|
25674
|
+
recursiveDurationHours: durationToHours(
|
|
25675
|
+
Number(raw.sumOfDurationRecursively ?? 0),
|
|
25676
|
+
context.hoursPerDay
|
|
25677
|
+
),
|
|
25678
|
+
calendarDuration: computeCalendarDuration({
|
|
25679
|
+
type: raw.type,
|
|
25680
|
+
startDate,
|
|
25681
|
+
endDate
|
|
25682
|
+
}),
|
|
25683
|
+
isCritical,
|
|
25684
|
+
freeSlackHours: null,
|
|
25685
|
+
expectedProgress: null,
|
|
25686
|
+
expectedProgressBaseline: null,
|
|
25687
|
+
status: null,
|
|
25688
|
+
criticalPath: null
|
|
25231
25689
|
};
|
|
25232
25690
|
}
|
|
25233
|
-
function
|
|
25234
|
-
|
|
25235
|
-
const parts = csv.split(",").map((value) => value.trim());
|
|
25236
|
-
if (parts.length !== WEEKDAYS_PER_WEEK) {
|
|
25237
|
-
return [...CALENDAR_FALLBACK_WORKING_DAYS];
|
|
25238
|
-
}
|
|
25239
|
-
return parts.map((part) => WORKING_DAY_TRUE_VALUES.has(part));
|
|
25691
|
+
function normalizeCustomId(raw) {
|
|
25692
|
+
return raw.has_childs ? null : raw.custom_id;
|
|
25240
25693
|
}
|
|
25241
|
-
|
|
25242
|
-
|
|
25243
|
-
|
|
25694
|
+
function forceRootProjectToRoot(activities) {
|
|
25695
|
+
const rootProject = activities.find(
|
|
25696
|
+
(activity) => activity.correlativeId === 0 && activity.type === ACTIVITY_TYPE.PROJECT
|
|
25697
|
+
);
|
|
25698
|
+
if (rootProject) rootProject.parentId = null;
|
|
25699
|
+
}
|
|
25700
|
+
function reparentOrphansToRoot(activities, ids, reporter, recordDiagnostic) {
|
|
25701
|
+
for (const activity of activities) {
|
|
25702
|
+
if (activity.parentId === null) continue;
|
|
25703
|
+
if (!ids.has(activity.parentId)) {
|
|
25704
|
+
reporter.warn(
|
|
25705
|
+
`[parseFromBackend] activity "${activity.id}" references unknown parent "${activity.parentId}" \u2014 re-parenting to root (null)`
|
|
25706
|
+
);
|
|
25707
|
+
recordDiagnostic(LOAD_DIAGNOSTIC_CODE.ORPHAN_ACTIVITY, activity.id);
|
|
25708
|
+
activity.parentId = null;
|
|
25709
|
+
}
|
|
25710
|
+
}
|
|
25244
25711
|
}
|
|
25245
25712
|
|
|
25246
25713
|
// src/boundary/backend/normalize-link.ts
|
|
@@ -26175,23 +26642,40 @@ function recomputeCanonicalRealWork(state) {
|
|
|
26175
26642
|
state.forEachActivity((activity, activityId) => {
|
|
26176
26643
|
if (activity.parentId === null) rootIds.push(String(activityId));
|
|
26177
26644
|
});
|
|
26178
|
-
const
|
|
26179
|
-
|
|
26180
|
-
|
|
26181
|
-
|
|
26182
|
-
|
|
26183
|
-
|
|
26184
|
-
|
|
26185
|
-
)
|
|
26645
|
+
const stack = rootIds.map((activityId) => ({
|
|
26646
|
+
activityId,
|
|
26647
|
+
parent: null,
|
|
26648
|
+
childIds: null,
|
|
26649
|
+
realWork: 0
|
|
26650
|
+
})).reverse();
|
|
26651
|
+
for (let frame = stack.pop(); frame; frame = stack.pop()) {
|
|
26652
|
+
if (frame.childIds === null) {
|
|
26653
|
+
const activity = state.getActivity(frame.activityId);
|
|
26654
|
+
if (!activity) continue;
|
|
26655
|
+
const childIds = [...state.getChildren(frame.activityId)];
|
|
26656
|
+
const isLeaf = childIds.length === 0;
|
|
26657
|
+
frame.childIds = childIds.values();
|
|
26658
|
+
frame.realWork = isLeaf ? computeLeafRealWork(activity.workHours, activity.progress) : 0;
|
|
26659
|
+
}
|
|
26660
|
+
const nextChild = frame.childIds.next();
|
|
26661
|
+
const hasNextChild = !nextChild.done;
|
|
26662
|
+
if (hasNextChild) {
|
|
26663
|
+
stack.push(frame, {
|
|
26664
|
+
activityId: String(nextChild.value),
|
|
26665
|
+
parent: frame,
|
|
26666
|
+
childIds: null,
|
|
26667
|
+
realWork: 0
|
|
26668
|
+
});
|
|
26669
|
+
continue;
|
|
26670
|
+
}
|
|
26186
26671
|
state.setActivityField(
|
|
26187
|
-
activityId,
|
|
26672
|
+
frame.activityId,
|
|
26188
26673
|
ACTIVITY_PROPERTY.REAL_WORK_HOURS,
|
|
26189
|
-
realWork
|
|
26674
|
+
frame.realWork
|
|
26190
26675
|
);
|
|
26191
|
-
changedIds.push(activityId);
|
|
26192
|
-
|
|
26193
|
-
}
|
|
26194
|
-
for (const rootId of rootIds) visit(rootId);
|
|
26676
|
+
changedIds.push(frame.activityId);
|
|
26677
|
+
if (frame.parent) frame.parent.realWork += frame.realWork;
|
|
26678
|
+
}
|
|
26195
26679
|
return changedIds;
|
|
26196
26680
|
}
|
|
26197
26681
|
|
|
@@ -26204,8 +26688,16 @@ async function runInitialPasses(deps) {
|
|
|
26204
26688
|
}
|
|
26205
26689
|
normalizeLoadedConstraintDates(state);
|
|
26206
26690
|
recomputeCanonicalRealWork(state);
|
|
26691
|
+
if (sector.activityCreter === ACTIVITY_PONDERATOR_CRITERION.COST) {
|
|
26692
|
+
let hasActiveBaseline2 = false;
|
|
26693
|
+
state.forEachActivity((activity) => {
|
|
26694
|
+
hasActiveBaseline2 ||= getActiveBaseline(activity) !== null;
|
|
26695
|
+
});
|
|
26696
|
+
if (hasActiveBaseline2)
|
|
26697
|
+
recomputeAllPonderators(ACTIVITY_PONDERATOR_CRITERION.COST, state);
|
|
26698
|
+
}
|
|
26207
26699
|
if (skipAutoSchedule) {
|
|
26208
|
-
recomputeAllProgressRollup(state);
|
|
26700
|
+
recomputeAllProgressRollup(state, sector.activityCreter);
|
|
26209
26701
|
if (now) {
|
|
26210
26702
|
applyExpectedProgressLive(state, now);
|
|
26211
26703
|
applyStatusPass(state, sector.statusCriteria);
|
|
@@ -26218,7 +26710,7 @@ async function runInitialPasses(deps) {
|
|
|
26218
26710
|
normalizeMilestoneConstraintDatesForDisplay(state);
|
|
26219
26711
|
recomputeSkippedLeafEnds(state);
|
|
26220
26712
|
await updateParentBoundsFromChildren(state, void 0, false);
|
|
26221
|
-
recomputeAllProgressRollup(state);
|
|
26713
|
+
recomputeAllProgressRollup(state, sector.activityCreter);
|
|
26222
26714
|
if (now) {
|
|
26223
26715
|
applyExpectedProgressLive(state, now);
|
|
26224
26716
|
applyStatusPass(state, sector.statusCriteria);
|
|
@@ -26691,6 +27183,39 @@ function clampPercent(value) {
|
|
|
26691
27183
|
return Math.min(MAXIMUM_PERCENT, Math.max(MINIMUM_PERCENT, value));
|
|
26692
27184
|
}
|
|
26693
27185
|
|
|
27186
|
+
// src/p6/rolled-expected-finish.ts
|
|
27187
|
+
var PINNABLE_ACTIVITY_TYPES = /* @__PURE__ */ new Set([
|
|
27188
|
+
P6_ACTIVITY_TYPE.TASK,
|
|
27189
|
+
P6_ACTIVITY_TYPE.RESOURCE_DEPENDENT
|
|
27190
|
+
]);
|
|
27191
|
+
var NO_ROLLED_EXPECTED_FINISHES = /* @__PURE__ */ new Map();
|
|
27192
|
+
function planRolledExpectedFinishes(input) {
|
|
27193
|
+
const adoptsShownFinishes = input.settings.useExpectedFinishDates && rollsDataDateForward(input.previousSettings, input.settings);
|
|
27194
|
+
if (!adoptsShownFinishes) return NO_ROLLED_EXPECTED_FINISHES;
|
|
27195
|
+
const pinned = /* @__PURE__ */ new Map();
|
|
27196
|
+
for (const [activityId, state] of input.activities) {
|
|
27197
|
+
const shownFinish = state.remainingEarlyFinish;
|
|
27198
|
+
if (shownFinish === null) continue;
|
|
27199
|
+
if (!needsExpectedFinishPin(state)) continue;
|
|
27200
|
+
pinned.set(activityId, new Date(shownFinish));
|
|
27201
|
+
}
|
|
27202
|
+
return pinned;
|
|
27203
|
+
}
|
|
27204
|
+
function rollsDataDateForward(previous, next) {
|
|
27205
|
+
const previousDataDate = previous.dataDate;
|
|
27206
|
+
const nextDataDate = next.dataDate;
|
|
27207
|
+
if (previousDataDate === null || nextDataDate === null) return false;
|
|
27208
|
+
return nextDataDate.getTime() > previousDataDate.getTime();
|
|
27209
|
+
}
|
|
27210
|
+
function needsExpectedFinishPin(state) {
|
|
27211
|
+
return state.executionStatus === P6_EXECUTION_STATUS.IN_PROGRESS && state.expectedFinish === null && hasPinnableActivityType(state);
|
|
27212
|
+
}
|
|
27213
|
+
function hasPinnableActivityType(state) {
|
|
27214
|
+
const { activityType } = state;
|
|
27215
|
+
if (activityType === void 0) return true;
|
|
27216
|
+
return PINNABLE_ACTIVITY_TYPES.has(activityType);
|
|
27217
|
+
}
|
|
27218
|
+
|
|
26694
27219
|
// src/p6/scheduler-projection.ts
|
|
26695
27220
|
function buildDataDateAuthorityFields(p6, settings) {
|
|
26696
27221
|
return {
|
|
@@ -26733,20 +27258,32 @@ function buildDataDateScheduleProjection(input) {
|
|
|
26733
27258
|
}
|
|
26734
27259
|
|
|
26735
27260
|
// src/p6/live-derived.ts
|
|
26736
|
-
function prepareDataDateLiveDerived(source, before, after) {
|
|
27261
|
+
function prepareDataDateLiveDerived(source, before, after, options = {}) {
|
|
26737
27262
|
if (!dataDateChanged(before.dataDate, after.dataDate)) return /* @__PURE__ */ new Map();
|
|
26738
27263
|
if (!hasActiveDataDate(after)) return /* @__PURE__ */ new Map();
|
|
26739
27264
|
const activating = !hasActiveDataDate(before);
|
|
27265
|
+
const activities = source.getAllActivities();
|
|
27266
|
+
const rolledExpectedFinishes = planSettingsExpectedFinishes(
|
|
27267
|
+
activities,
|
|
27268
|
+
before,
|
|
27269
|
+
after,
|
|
27270
|
+
options.adoptExpectedFinish
|
|
27271
|
+
);
|
|
26740
27272
|
const patches = /* @__PURE__ */ new Map();
|
|
26741
|
-
for (const activity of
|
|
27273
|
+
for (const activity of activities) {
|
|
26742
27274
|
const p6 = activity.p6;
|
|
26743
27275
|
if (p6 === void 0) continue;
|
|
26744
27276
|
const calendar = source.calendarReader.getCalendar(activity.calendarId);
|
|
26745
27277
|
if (calendar === null) {
|
|
26746
27278
|
throw new Error(`Missing calendar for Data Date activity ${activity.id}`);
|
|
26747
27279
|
}
|
|
26748
|
-
const nextP6 = liveDerivedState(
|
|
26749
|
-
|
|
27280
|
+
const nextP6 = liveDerivedState(
|
|
27281
|
+
p6,
|
|
27282
|
+
after.dataDate,
|
|
27283
|
+
calendar,
|
|
27284
|
+
rolledExpectedFinishes.get(activity.id)
|
|
27285
|
+
);
|
|
27286
|
+
const p6Changed = !Object.is(nextP6.expectedFinish, p6.expectedFinish) || !Object.is(nextP6.schedulePercentComplete, p6.schedulePercentComplete) || !Object.is(nextP6.actualDurationHours, p6.actualDurationHours);
|
|
26750
27287
|
if (!activating && !p6Changed) continue;
|
|
26751
27288
|
patches.set(activity.id, {
|
|
26752
27289
|
...p6Changed ? { p6: nextP6 } : {},
|
|
@@ -26755,17 +27292,37 @@ function prepareDataDateLiveDerived(source, before, after) {
|
|
|
26755
27292
|
}
|
|
26756
27293
|
return patches;
|
|
26757
27294
|
}
|
|
27295
|
+
function planSettingsExpectedFinishes(activities, before, after, adoptExpectedFinish = false) {
|
|
27296
|
+
if (!adoptExpectedFinish) return /* @__PURE__ */ new Map();
|
|
27297
|
+
const overridesDataDateWithForecast = after.setDataDateAndPlannedStartToForecastStart && after.projectForecastStart !== null;
|
|
27298
|
+
if (overridesDataDateWithForecast) return /* @__PURE__ */ new Map();
|
|
27299
|
+
const scheduledActivities = new Map(
|
|
27300
|
+
activities.flatMap((activity) => {
|
|
27301
|
+
const p6 = activity.p6;
|
|
27302
|
+
const hasSchedulingState = p6 !== void 0 && isP6ActivityState(p6);
|
|
27303
|
+
if (activity.type === ACTIVITY_TYPE.PROJECT || !hasSchedulingState)
|
|
27304
|
+
return [];
|
|
27305
|
+
return [[activity.id, p6]];
|
|
27306
|
+
})
|
|
27307
|
+
);
|
|
27308
|
+
return planRolledExpectedFinishes({
|
|
27309
|
+
previousSettings: before,
|
|
27310
|
+
settings: after,
|
|
27311
|
+
activities: scheduledActivities
|
|
27312
|
+
});
|
|
27313
|
+
}
|
|
26758
27314
|
function applyDataDateLiveDerived(writer, patches) {
|
|
26759
27315
|
for (const [activityId, fields] of patches) {
|
|
26760
27316
|
writer.setActivityFields(activityId, fields);
|
|
26761
27317
|
}
|
|
26762
27318
|
}
|
|
26763
|
-
function liveDerivedState(p6, dataDate, calendar) {
|
|
27319
|
+
function liveDerivedState(p6, dataDate, calendar, rolledExpectedFinish) {
|
|
26764
27320
|
const context = { dataDate, calendar };
|
|
26765
27321
|
const schedulePercentComplete = deriveP6SchedulePercentComplete(p6, context);
|
|
26766
27322
|
const measuresActualDuration = isP6ActivityState(p6) && p6.executionStatus === P6_EXECUTION_STATUS.IN_PROGRESS;
|
|
26767
27323
|
return {
|
|
26768
27324
|
...p6,
|
|
27325
|
+
expectedFinish: rolledExpectedFinish ?? p6.expectedFinish,
|
|
26769
27326
|
schedulePercentComplete,
|
|
26770
27327
|
...measuresActualDuration ? { actualDurationHours: deriveP6ActualDurationHours(p6, context) } : {}
|
|
26771
27328
|
};
|
|
@@ -29207,8 +29764,8 @@ function compareActivityReference(leftId, rightId, adapter, settings) {
|
|
|
29207
29764
|
function collectFreeFloatPaths(endingActivityId2, adapter, forward, settings) {
|
|
29208
29765
|
const paths = [];
|
|
29209
29766
|
const assigned = /* @__PURE__ */ new Set();
|
|
29210
|
-
const
|
|
29211
|
-
|
|
29767
|
+
const pending = [endingActivityId2];
|
|
29768
|
+
for (let pathEndId = pending.pop(); pathEndId !== void 0; pathEndId = pending.pop()) {
|
|
29212
29769
|
const path = [];
|
|
29213
29770
|
let currentId = pathEndId;
|
|
29214
29771
|
while (currentId !== null && !assigned.has(currentId)) {
|
|
@@ -29218,23 +29775,24 @@ function collectFreeFloatPaths(endingActivityId2, adapter, forward, settings) {
|
|
|
29218
29775
|
path.push(currentId);
|
|
29219
29776
|
currentId = startsFreeFloatPathSegment(currentId, adapter, settings) ? null : resolvePrimaryPathPredecessor(currentId, adapter, forward, settings);
|
|
29220
29777
|
}
|
|
29221
|
-
if (path.length === 0)
|
|
29778
|
+
if (path.length === 0) continue;
|
|
29222
29779
|
paths.push(path);
|
|
29223
|
-
|
|
29780
|
+
const alternatives = [...path].reverse().flatMap((activityId) => {
|
|
29224
29781
|
const primaryPredecessor = startsFreeFloatPathSegment(
|
|
29225
29782
|
activityId,
|
|
29226
29783
|
adapter,
|
|
29227
29784
|
settings
|
|
29228
29785
|
) ? null : resolvePrimaryPathPredecessor(activityId, adapter, forward, settings);
|
|
29229
|
-
|
|
29786
|
+
return adapter.getIncomingLinkIds(activityId).map((linkId) => adapter.getLink(linkId)).filter(
|
|
29230
29787
|
(link) => link !== null && link.source !== primaryPredecessor
|
|
29231
29788
|
).sort(
|
|
29232
|
-
(left, right) =>
|
|
29789
|
+
(left, right) => right.source.localeCompare(left.source) || right.id.localeCompare(left.id)
|
|
29233
29790
|
);
|
|
29234
|
-
|
|
29791
|
+
});
|
|
29792
|
+
for (const link of alternatives) {
|
|
29793
|
+
pending.push(link.source);
|
|
29235
29794
|
}
|
|
29236
|
-
}
|
|
29237
|
-
visit(endingActivityId2);
|
|
29795
|
+
}
|
|
29238
29796
|
return paths;
|
|
29239
29797
|
}
|
|
29240
29798
|
function startsFreeFloatPathSegment(activityId, adapter, settings) {
|
|
@@ -29378,6 +29936,103 @@ function resolvePrimaryPathPredecessor(activityId, adapter, forward, settings) {
|
|
|
29378
29936
|
return resolveLongestPathPredecessors(activityId, adapter, forward, settings)[0] ?? null;
|
|
29379
29937
|
}
|
|
29380
29938
|
|
|
29939
|
+
// src/p6/settings-enums.ts
|
|
29940
|
+
function validateP6ScheduleSettingEnums(settings) {
|
|
29941
|
+
validateChoice(settings.outOfSequencePolicy, "outOfSequencePolicy", [
|
|
29942
|
+
"retained_logic",
|
|
29943
|
+
"progress_override",
|
|
29944
|
+
"actual_dates"
|
|
29945
|
+
]);
|
|
29946
|
+
validateChoice(settings.dependencyReference, "dependencyReference", [
|
|
29947
|
+
"correlative_id",
|
|
29948
|
+
"custom_id"
|
|
29949
|
+
]);
|
|
29950
|
+
validateChoice(settings.startToStartLagBasis, "startToStartLagBasis", [
|
|
29951
|
+
"actual_start",
|
|
29952
|
+
"early_start"
|
|
29953
|
+
]);
|
|
29954
|
+
validateChoice(settings.relationshipLagCalendar, "relationshipLagCalendar", [
|
|
29955
|
+
"predecessor",
|
|
29956
|
+
"successor",
|
|
29957
|
+
"project_default",
|
|
29958
|
+
"twenty_four_hour"
|
|
29959
|
+
]);
|
|
29960
|
+
validateChoice(settings.totalFloatMethod, "totalFloatMethod", [
|
|
29961
|
+
"start_float",
|
|
29962
|
+
"finish_float",
|
|
29963
|
+
"smallest"
|
|
29964
|
+
]);
|
|
29965
|
+
validateChoice(
|
|
29966
|
+
settings.criticalActivityMethod,
|
|
29967
|
+
"criticalActivityMethod",
|
|
29968
|
+
Object.values(P6_CRITICAL_ACTIVITY_METHOD)
|
|
29969
|
+
);
|
|
29970
|
+
validateChoice(settings.calculateFloatBasedOn, "calculateFloatBasedOn", [
|
|
29971
|
+
"each_project",
|
|
29972
|
+
"opened_projects"
|
|
29973
|
+
]);
|
|
29974
|
+
}
|
|
29975
|
+
function validateChoice(value, field, allowed) {
|
|
29976
|
+
if (allowed.includes(value)) return;
|
|
29977
|
+
throw new Error(`Invalid P6 schedule settings: ${field}`);
|
|
29978
|
+
}
|
|
29979
|
+
|
|
29980
|
+
// src/p6/wbs-summary-activities.ts
|
|
29981
|
+
function prependAncestor(ancestorId, matches, requested) {
|
|
29982
|
+
return requested.has(ancestorId) ? { ancestorId, next: matches } : matches;
|
|
29983
|
+
}
|
|
29984
|
+
function cacheCycleMatches(path, cycleStart, requested, cache) {
|
|
29985
|
+
const cycle = path.slice(cycleStart).reverse();
|
|
29986
|
+
let matches = null;
|
|
29987
|
+
for (const ancestorId of cycle)
|
|
29988
|
+
matches = prependAncestor(ancestorId, matches, requested);
|
|
29989
|
+
for (const ancestorId of cycle) cache.set(ancestorId, matches);
|
|
29990
|
+
return matches;
|
|
29991
|
+
}
|
|
29992
|
+
function resolveAncestorMatches(parentId, byId, requested, cache) {
|
|
29993
|
+
const path = [];
|
|
29994
|
+
const positions = /* @__PURE__ */ new Map();
|
|
29995
|
+
let currentId = parentId;
|
|
29996
|
+
while (currentId !== null && !cache.has(currentId) && !positions.has(currentId)) {
|
|
29997
|
+
positions.set(currentId, path.length);
|
|
29998
|
+
path.push(currentId);
|
|
29999
|
+
currentId = byId.get(currentId)?.parentId ?? null;
|
|
30000
|
+
}
|
|
30001
|
+
let matches = currentId === null ? null : cache.get(currentId) ?? null;
|
|
30002
|
+
const cycleStart = currentId === null ? void 0 : positions.get(currentId);
|
|
30003
|
+
let lastIndex = path.length - 1;
|
|
30004
|
+
if (cycleStart !== void 0) {
|
|
30005
|
+
matches = cacheCycleMatches(path, cycleStart, requested, cache);
|
|
30006
|
+
lastIndex = cycleStart - 1;
|
|
30007
|
+
}
|
|
30008
|
+
for (let index = lastIndex; index >= 0; index -= 1) {
|
|
30009
|
+
const ancestorId = path[index];
|
|
30010
|
+
if (ancestorId === void 0) throw new Error("Missing WBS ancestor");
|
|
30011
|
+
matches = prependAncestor(ancestorId, matches, requested);
|
|
30012
|
+
cache.set(ancestorId, matches);
|
|
30013
|
+
}
|
|
30014
|
+
return cache.get(parentId) ?? null;
|
|
30015
|
+
}
|
|
30016
|
+
function groupWbsSummaryActivities(activities, byId, ancestorIds) {
|
|
30017
|
+
const groups = /* @__PURE__ */ new Map();
|
|
30018
|
+
if (ancestorIds.size === 0) return groups;
|
|
30019
|
+
const cache = /* @__PURE__ */ new Map();
|
|
30020
|
+
for (const activity of activities) {
|
|
30021
|
+
const isRealActivity = activity.p6 !== void 0 && activity.p6.activityType !== P6_ACTIVITY_TYPE.WBS_SUMMARY;
|
|
30022
|
+
if (!isRealActivity) continue;
|
|
30023
|
+
const parentId = activity.parentId;
|
|
30024
|
+
if (parentId === null) continue;
|
|
30025
|
+
let matches = resolveAncestorMatches(parentId, byId, ancestorIds, cache);
|
|
30026
|
+
while (matches !== null) {
|
|
30027
|
+
const bucket = groups.get(matches.ancestorId);
|
|
30028
|
+
if (bucket === void 0) groups.set(matches.ancestorId, [activity]);
|
|
30029
|
+
else bucket.push(activity);
|
|
30030
|
+
matches = matches.next;
|
|
30031
|
+
}
|
|
30032
|
+
}
|
|
30033
|
+
return groups;
|
|
30034
|
+
}
|
|
30035
|
+
|
|
29381
30036
|
// src/p6/schedule.ts
|
|
29382
30037
|
var EMPTY_LEVEL_OF_EFFORT_WINDOWS = {
|
|
29383
30038
|
remainingEarlyStart: null,
|
|
@@ -29529,27 +30184,6 @@ function calculateP6Schedule(input) {
|
|
|
29529
30184
|
];
|
|
29530
30185
|
return { activities, criticalPath, warnings };
|
|
29531
30186
|
}
|
|
29532
|
-
function groupActivitiesByWbsAncestor(all, byId) {
|
|
29533
|
-
const childrenByAncestor = /* @__PURE__ */ new Map();
|
|
29534
|
-
for (const activity of all) {
|
|
29535
|
-
if (activity.p6 === void 0 || activity.p6.activityType === "wbs_summary") {
|
|
29536
|
-
continue;
|
|
29537
|
-
}
|
|
29538
|
-
let currentId = activity.parentId;
|
|
29539
|
-
const visited = /* @__PURE__ */ new Set();
|
|
29540
|
-
while (currentId !== null && !visited.has(currentId)) {
|
|
29541
|
-
visited.add(currentId);
|
|
29542
|
-
const bucket = childrenByAncestor.get(currentId);
|
|
29543
|
-
if (bucket === void 0) {
|
|
29544
|
-
childrenByAncestor.set(currentId, [activity]);
|
|
29545
|
-
} else {
|
|
29546
|
-
bucket.push(activity);
|
|
29547
|
-
}
|
|
29548
|
-
currentId = byId.get(currentId)?.parentId ?? null;
|
|
29549
|
-
}
|
|
29550
|
-
}
|
|
29551
|
-
return childrenByAncestor;
|
|
29552
|
-
}
|
|
29553
30187
|
function hasNoPrimaryConstraint(constraintType) {
|
|
29554
30188
|
return (constraintType ?? CONSTRAINT_TYPE.ASAP) === CONSTRAINT_TYPE.ASAP;
|
|
29555
30189
|
}
|
|
@@ -29860,11 +30494,20 @@ function settleIsolatedLevelOfEffort(current, scheduled, dataDate) {
|
|
|
29860
30494
|
function calculateWbsSummaries(input) {
|
|
29861
30495
|
const { adapter, settings, activities } = input;
|
|
29862
30496
|
const all = adapter.getAllActivities();
|
|
30497
|
+
const summaries = sortedP6Activities(
|
|
30498
|
+
all.filter(
|
|
30499
|
+
(activity) => activity.p6?.activityType === P6_ACTIVITY_TYPE.WBS_SUMMARY
|
|
30500
|
+
)
|
|
30501
|
+
);
|
|
30502
|
+
const ancestorIds = new Set(
|
|
30503
|
+
summaries.flatMap(
|
|
30504
|
+
(summary) => summary.parentId === null ? [] : [summary.parentId]
|
|
30505
|
+
)
|
|
30506
|
+
);
|
|
30507
|
+
if (ancestorIds.size === 0) return;
|
|
29863
30508
|
const byId = new Map(all.map((activity) => [activity.id, activity]));
|
|
29864
|
-
const childrenByAncestor =
|
|
29865
|
-
for (const summary of
|
|
29866
|
-
(activity) => activity.p6?.activityType === "wbs_summary"
|
|
29867
|
-
)) {
|
|
30509
|
+
const childrenByAncestor = groupWbsSummaryActivities(all, byId, ancestorIds);
|
|
30510
|
+
for (const summary of summaries) {
|
|
29868
30511
|
if (summary.parentId === null) continue;
|
|
29869
30512
|
const children = childrenByAncestor.get(summary.parentId) ?? [];
|
|
29870
30513
|
if (children.length === 0) continue;
|
|
@@ -29987,6 +30630,7 @@ function validateP6ScheduleSettings(settings) {
|
|
|
29987
30630
|
if (endingActivityId2 !== null && typeof endingActivityId2 !== "string" && (typeof endingActivityId2 !== "number" || !Number.isFinite(endingActivityId2))) {
|
|
29988
30631
|
throw new Error("Invalid P6 schedule settings: ending activity ID");
|
|
29989
30632
|
}
|
|
30633
|
+
validateP6ScheduleSettingEnums(settings);
|
|
29990
30634
|
}
|
|
29991
30635
|
function sortedP6Activities(activities) {
|
|
29992
30636
|
return activities.filter((activity) => activity.p6 !== void 0).sort((left, right) => String(left.id).localeCompare(String(right.id)));
|
|
@@ -30160,39 +30804,6 @@ function blockedActivities(code, message, activityIds, missingInputs = []) {
|
|
|
30160
30804
|
};
|
|
30161
30805
|
}
|
|
30162
30806
|
|
|
30163
|
-
// src/p6/rolled-expected-finish.ts
|
|
30164
|
-
var PINNABLE_ACTIVITY_TYPES = /* @__PURE__ */ new Set([
|
|
30165
|
-
P6_ACTIVITY_TYPE.TASK,
|
|
30166
|
-
P6_ACTIVITY_TYPE.RESOURCE_DEPENDENT
|
|
30167
|
-
]);
|
|
30168
|
-
var NO_ROLLED_EXPECTED_FINISHES = /* @__PURE__ */ new Map();
|
|
30169
|
-
function planRolledExpectedFinishes(input) {
|
|
30170
|
-
const adoptsShownFinishes = input.settings.useExpectedFinishDates && rollsDataDateForward(input.previousSettings, input.settings);
|
|
30171
|
-
if (!adoptsShownFinishes) return NO_ROLLED_EXPECTED_FINISHES;
|
|
30172
|
-
const pinned = /* @__PURE__ */ new Map();
|
|
30173
|
-
for (const [activityId, state] of input.activities) {
|
|
30174
|
-
const shownFinish = state.remainingEarlyFinish;
|
|
30175
|
-
if (shownFinish === null) continue;
|
|
30176
|
-
if (!needsExpectedFinishPin(state)) continue;
|
|
30177
|
-
pinned.set(activityId, new Date(shownFinish));
|
|
30178
|
-
}
|
|
30179
|
-
return pinned;
|
|
30180
|
-
}
|
|
30181
|
-
function rollsDataDateForward(previous, next) {
|
|
30182
|
-
const previousDataDate = previous.dataDate;
|
|
30183
|
-
const nextDataDate = next.dataDate;
|
|
30184
|
-
if (previousDataDate === null || nextDataDate === null) return false;
|
|
30185
|
-
return nextDataDate.getTime() > previousDataDate.getTime();
|
|
30186
|
-
}
|
|
30187
|
-
function needsExpectedFinishPin(state) {
|
|
30188
|
-
return state.executionStatus === P6_EXECUTION_STATUS.IN_PROGRESS && state.expectedFinish === null && hasPinnableActivityType(state);
|
|
30189
|
-
}
|
|
30190
|
-
function hasPinnableActivityType(state) {
|
|
30191
|
-
const { activityType } = state;
|
|
30192
|
-
if (activityType === void 0) return true;
|
|
30193
|
-
return PINNABLE_ACTIVITY_TYPES.has(activityType);
|
|
30194
|
-
}
|
|
30195
|
-
|
|
30196
30807
|
// src/p6/commands.ts
|
|
30197
30808
|
function dataDateScheduleReadiness(input) {
|
|
30198
30809
|
const preflight = getP6SchedulePreflight({
|
|
@@ -30410,6 +31021,10 @@ function throwPreflight(preflight) {
|
|
|
30410
31021
|
}
|
|
30411
31022
|
function validateActivityInputPatch(patch) {
|
|
30412
31023
|
validateDates2(patch);
|
|
31024
|
+
const executionStatus = patch.executionStatus;
|
|
31025
|
+
if ("executionStatus" in patch && executionStatus !== P6_EXECUTION_STATUS.NOT_STARTED && executionStatus !== P6_EXECUTION_STATUS.IN_PROGRESS && executionStatus !== P6_EXECUTION_STATUS.COMPLETED) {
|
|
31026
|
+
throw new Error("Invalid P6 activity input: execution status");
|
|
31027
|
+
}
|
|
30413
31028
|
for (const value of [
|
|
30414
31029
|
patch.remainingDurationHours,
|
|
30415
31030
|
patch.originalDurationHours,
|
|
@@ -31069,9 +31684,7 @@ var ScheduleCore = class _ScheduleCore {
|
|
|
31069
31684
|
this._activityClipboard.value = cloneDomainValue(
|
|
31070
31685
|
source._activityClipboard.value
|
|
31071
31686
|
);
|
|
31072
|
-
this._cellClipboard.value = cloneDomainValue(
|
|
31073
|
-
source._cellClipboard.value
|
|
31074
|
-
);
|
|
31687
|
+
this._cellClipboard.value = cloneDomainValue(source._cellClipboard.value);
|
|
31075
31688
|
this._undo = source._undo.fork();
|
|
31076
31689
|
this._saveTracker = source._saveTracker.fork();
|
|
31077
31690
|
this._scheduleRevision = source._scheduleRevision;
|
|
@@ -31242,6 +31855,7 @@ var ScheduleCore = class _ScheduleCore {
|
|
|
31242
31855
|
const activity = readActivity(this.coreRuntime.state, id);
|
|
31243
31856
|
if (!activity) return null;
|
|
31244
31857
|
const context = buildPipelineContext(this.coreRuntime.state, {
|
|
31858
|
+
calendars: this.coreRuntime.calendars,
|
|
31245
31859
|
hoursPerDay: this.coreRuntime.sector.hoursPerDay,
|
|
31246
31860
|
dateFormat: this.coreRuntime.sector.dateFormat
|
|
31247
31861
|
});
|
|
@@ -31276,6 +31890,7 @@ var ScheduleCore = class _ScheduleCore {
|
|
|
31276
31890
|
const pipeline = findPipelineForColumn(column);
|
|
31277
31891
|
if (!activity || !pipeline) return null;
|
|
31278
31892
|
const context = buildPipelineContext(this.coreRuntime.state, {
|
|
31893
|
+
calendars: this.coreRuntime.calendars,
|
|
31279
31894
|
hoursPerDay: this.coreRuntime.sector.hoursPerDay,
|
|
31280
31895
|
dateFormat: this.coreRuntime.sector.dateFormat
|
|
31281
31896
|
});
|
|
@@ -31836,7 +32451,8 @@ var ScheduleCore = class _ScheduleCore {
|
|
|
31836
32451
|
const liveDerived = capability.prepareLiveDerived(
|
|
31837
32452
|
this.coreRuntime.state,
|
|
31838
32453
|
before,
|
|
31839
|
-
after
|
|
32454
|
+
after,
|
|
32455
|
+
{ adoptExpectedFinish: true }
|
|
31840
32456
|
);
|
|
31841
32457
|
const touchedIds = [...liveDerived.keys()];
|
|
31842
32458
|
const beforeSnap = new Map(
|
|
@@ -32265,6 +32881,7 @@ var ScheduleCore = class _ScheduleCore {
|
|
|
32265
32881
|
this.assertReady();
|
|
32266
32882
|
return buildLookaheadConversionPlan(input, {
|
|
32267
32883
|
adapter: this.coreRuntime.state,
|
|
32884
|
+
sector: this.getSector(),
|
|
32268
32885
|
stateRevision: this._stateRevision
|
|
32269
32886
|
});
|
|
32270
32887
|
}
|
|
@@ -32312,6 +32929,16 @@ var ScheduleCore = class _ScheduleCore {
|
|
|
32312
32929
|
});
|
|
32313
32930
|
continue;
|
|
32314
32931
|
}
|
|
32932
|
+
const manualSchedulingActive = hasActiveDataDate(
|
|
32933
|
+
this.coreRuntime.state.dataDateSettings()
|
|
32934
|
+
);
|
|
32935
|
+
if (manualSchedulingActive) {
|
|
32936
|
+
results.push({
|
|
32937
|
+
ok: false,
|
|
32938
|
+
reason: REJECTION_REASON.MANUAL_SCHEDULING_ACTIVE
|
|
32939
|
+
});
|
|
32940
|
+
continue;
|
|
32941
|
+
}
|
|
32315
32942
|
const changes = emptyChangeSet2(action);
|
|
32316
32943
|
results.push({ ok: true, changes });
|
|
32317
32944
|
acceptedChangeSets.push(changes);
|
|
@@ -32413,6 +33040,7 @@ var ScheduleCore = class _ScheduleCore {
|
|
|
32413
33040
|
};
|
|
32414
33041
|
}
|
|
32415
33042
|
const pipelineContext = buildPipelineContext(this.coreRuntime.state, {
|
|
33043
|
+
calendars: this.coreRuntime.calendars,
|
|
32416
33044
|
hoursPerDay: this.coreRuntime.sector.hoursPerDay,
|
|
32417
33045
|
dateFormat: this.coreRuntime.sector.dateFormat
|
|
32418
33046
|
});
|