@outbuild-company/schedule-core 1.1.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cdn/schedule-core.global.js +1 -1
- package/dist/cdn/schedule-core.global.js.map +1 -1
- package/dist/index.cjs +1942 -1579
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +75 -214
- package/dist/index.d.ts +75 -214
- package/dist/index.js +1943 -1577
- package/dist/index.js.map +1 -1
- package/package.json +2 -3
package/dist/index.cjs
CHANGED
|
@@ -835,49 +835,63 @@ function appendToBucket(index, key, link) {
|
|
|
835
835
|
}
|
|
836
836
|
index.set(key, [link]);
|
|
837
837
|
}
|
|
838
|
-
function filterToChainEndpoints(leaves, adapter, linksByActivity) {
|
|
838
|
+
function filterToChainEndpoints(leaves, adapter, linksByActivity, selectSourceLinks) {
|
|
839
839
|
if (leaves.length <= 1) return leaves;
|
|
840
840
|
const leafSet = new Set(leaves.map(String));
|
|
841
841
|
const keptLeaves = [];
|
|
842
842
|
for (const leafId of leaves) {
|
|
843
|
-
if (!shouldSkipMidChainLeaf(
|
|
843
|
+
if (!shouldSkipMidChainLeaf(
|
|
844
|
+
leafId,
|
|
845
|
+
leafSet,
|
|
846
|
+
adapter,
|
|
847
|
+
linksByActivity,
|
|
848
|
+
selectSourceLinks
|
|
849
|
+
)) {
|
|
844
850
|
keptLeaves.push(leafId);
|
|
845
851
|
}
|
|
846
852
|
}
|
|
847
853
|
return keptLeaves.length > 0 ? keptLeaves : leaves;
|
|
848
854
|
}
|
|
849
|
-
function shouldSkipMidChainLeaf(leafId, leafSet, adapter, linksByActivity) {
|
|
855
|
+
function shouldSkipMidChainLeaf(leafId, leafSet, adapter, linksByActivity, selectSourceLinks) {
|
|
850
856
|
const leafKey = String(leafId);
|
|
851
857
|
const leafTask = adapter.getActivity(leafId);
|
|
852
858
|
if (!leafTask) return false;
|
|
853
859
|
if (leafTask.autoScheduling === false) return false;
|
|
854
860
|
const linksOnThis = linksByActivity.get(leafKey) ?? [];
|
|
855
861
|
for (const siblingLink of linksOnThis) {
|
|
856
|
-
if (
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
862
|
+
if (isMidChainConnection(
|
|
863
|
+
siblingLink,
|
|
864
|
+
leafKey,
|
|
865
|
+
leafTask,
|
|
866
|
+
leafSet,
|
|
867
|
+
adapter,
|
|
868
|
+
selectSourceLinks
|
|
869
|
+
))
|
|
863
870
|
return true;
|
|
864
|
-
}
|
|
865
871
|
}
|
|
866
872
|
return false;
|
|
867
873
|
}
|
|
874
|
+
function isMidChainConnection(link, leafKey, leafTask, leafSet, adapter, selectSourceLinks) {
|
|
875
|
+
if (isSelfLink(link)) return false;
|
|
876
|
+
const relevantDirection = selectSourceLinks ? String(link.source) === leafKey : String(link.target) === leafKey;
|
|
877
|
+
if (!relevantDirection) return false;
|
|
878
|
+
const otherId = otherEndOf(link, leafKey);
|
|
879
|
+
if (!leafSet.has(String(otherId))) return false;
|
|
880
|
+
const siblingTask = adapter.getActivity(otherId);
|
|
881
|
+
return Boolean(
|
|
882
|
+
siblingTask?.autoScheduling !== false && siblingTask && linkConnectsMidChain(link, leafTask, siblingTask)
|
|
883
|
+
);
|
|
884
|
+
}
|
|
868
885
|
function isSelfLink(link) {
|
|
869
886
|
return link.source === link.target;
|
|
870
887
|
}
|
|
871
888
|
function otherEndOf(link, knownEndKey) {
|
|
872
889
|
return String(link.source) === knownEndKey ? link.target : link.source;
|
|
873
890
|
}
|
|
874
|
-
function linkConnectsMidChain(link,
|
|
891
|
+
function linkConnectsMidChain(link, leafTask, siblingTask) {
|
|
875
892
|
const lag = link.lag ?? 0;
|
|
876
893
|
const absLag = Math.abs(lag);
|
|
877
|
-
|
|
878
|
-
if (link.target === otherId && absLag <= siblingTask.durationHours)
|
|
879
|
-
return true;
|
|
880
|
-
return false;
|
|
894
|
+
return String(link.target) === String(siblingTask.id) && absLag <= siblingTask.durationHours || String(link.target) === String(leafTask.id) && absLag <= leafTask.durationHours;
|
|
881
895
|
}
|
|
882
896
|
function expandParentLinks(links, adapter) {
|
|
883
897
|
const expanded = [];
|
|
@@ -886,116 +900,172 @@ function expandParentLinks(links, adapter) {
|
|
|
886
900
|
for (const link of links) {
|
|
887
901
|
const sourceIsSummary = isSummary2(link.source, adapter);
|
|
888
902
|
const targetIsSummary = isSummary2(link.target, adapter);
|
|
889
|
-
if (sourceIsSummary
|
|
890
|
-
if (targetIsSummary && isDescendantOf(link.source, link.target, adapter) || sourceIsSummary && isDescendantOf(link.target, link.source, adapter)) {
|
|
903
|
+
if (isInternalSummaryLink(link, sourceIsSummary, targetIsSummary, adapter))
|
|
891
904
|
continue;
|
|
892
|
-
}
|
|
893
905
|
if (!sourceIsSummary && !targetIsSummary) {
|
|
894
906
|
expanded.push(link);
|
|
895
907
|
continue;
|
|
896
908
|
}
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
chainEndpoints,
|
|
913
|
-
link,
|
|
914
|
-
link.target,
|
|
915
|
-
adapter,
|
|
916
|
-
virtualIdCounter
|
|
917
|
-
);
|
|
918
|
-
continue;
|
|
919
|
-
}
|
|
920
|
-
targetIds = keepBoundDefiningLeaves(chainEndpoints, true, adapter);
|
|
921
|
-
}
|
|
922
|
-
virtualIdCounter = pushExpandedLinks(
|
|
909
|
+
const sourceIds = expandedEndpoints(
|
|
910
|
+
link.source,
|
|
911
|
+
sourceIsSummary,
|
|
912
|
+
adapter,
|
|
913
|
+
linksByActivity,
|
|
914
|
+
true
|
|
915
|
+
);
|
|
916
|
+
const targetIds = expandedEndpoints(
|
|
917
|
+
link.target,
|
|
918
|
+
targetIsSummary,
|
|
919
|
+
adapter,
|
|
920
|
+
linksByActivity,
|
|
921
|
+
false
|
|
922
|
+
);
|
|
923
|
+
virtualIdCounter = pushOffsetPreservingLinks(
|
|
923
924
|
expanded,
|
|
924
925
|
sourceIds,
|
|
925
926
|
targetIds,
|
|
926
927
|
link,
|
|
927
|
-
|
|
928
|
+
adapter,
|
|
929
|
+
virtualIdCounter,
|
|
930
|
+
linksByActivity
|
|
928
931
|
);
|
|
929
932
|
}
|
|
930
933
|
return expanded;
|
|
931
934
|
}
|
|
932
|
-
function
|
|
933
|
-
|
|
934
|
-
const summaryStart = summary?.startDate;
|
|
935
|
-
const summaryDuration = summary?.durationHours ?? 0;
|
|
936
|
-
const userLag = originalLink.lag ?? 0;
|
|
937
|
-
const source = adapter.getActivity(originalLink.source);
|
|
938
|
-
let counter = virtualIdCounter;
|
|
939
|
-
for (const srcId of sourceIds) {
|
|
940
|
-
for (const tgtId of leafIds) {
|
|
941
|
-
if (String(srcId) === String(tgtId)) continue;
|
|
942
|
-
const leaf = adapter.getActivity(tgtId);
|
|
943
|
-
const offTarget = summaryStart && leaf && source ? adapter.calculateDuration({
|
|
944
|
-
startDate: summaryStart,
|
|
945
|
-
endDate: leaf.startDate,
|
|
946
|
-
task: source
|
|
947
|
-
}) : 0;
|
|
948
|
-
expanded.push({
|
|
949
|
-
id: `virtual_${originalLink.id}_${counter}`,
|
|
950
|
-
source: srcId,
|
|
951
|
-
target: tgtId,
|
|
952
|
-
type: originalLink.type,
|
|
953
|
-
lag: originalLink.lag,
|
|
954
|
-
_sourceLag: 0,
|
|
955
|
-
_targetLag: -summaryDuration,
|
|
956
|
-
_trueLag: userLag + offTarget
|
|
957
|
-
});
|
|
958
|
-
counter += 1;
|
|
959
|
-
}
|
|
960
|
-
}
|
|
961
|
-
return counter;
|
|
935
|
+
function isInternalSummaryLink(link, sourceIsSummary, targetIsSummary, adapter) {
|
|
936
|
+
return targetIsSummary && isDescendantOf(link.source, link.target, adapter) || sourceIsSummary && isDescendantOf(link.target, link.source, adapter);
|
|
962
937
|
}
|
|
963
|
-
function
|
|
964
|
-
if (
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
if (
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
938
|
+
function expandedEndpoints(activityId, summary, adapter, linksByActivity, sourceSide) {
|
|
939
|
+
if (!summary) return [activityId];
|
|
940
|
+
return filterToChainEndpoints(
|
|
941
|
+
getLeafDescendants(activityId, adapter),
|
|
942
|
+
adapter,
|
|
943
|
+
linksByActivity,
|
|
944
|
+
sourceSide
|
|
945
|
+
);
|
|
946
|
+
}
|
|
947
|
+
function deriveSummaryBoundsWithDates(summaryId, adapter, resolveDates) {
|
|
948
|
+
const leaves = getLeafDescendants(summaryId, adapter);
|
|
949
|
+
if (leaves.length === 0) return null;
|
|
950
|
+
let earliestStart = null;
|
|
951
|
+
let latestEnd = null;
|
|
952
|
+
for (const leafId of leaves) {
|
|
953
|
+
const leafDates = resolveDates(leafId);
|
|
954
|
+
if (!leafDates) continue;
|
|
955
|
+
const startsEarlier = earliestStart === null || leafDates.startDate < earliestStart;
|
|
956
|
+
if (startsEarlier) earliestStart = leafDates.startDate;
|
|
957
|
+
const endsLater = latestEnd === null || leafDates.endDate > latestEnd;
|
|
958
|
+
if (endsLater) latestEnd = leafDates.endDate;
|
|
959
|
+
}
|
|
960
|
+
if (earliestStart === null || latestEnd === null) return null;
|
|
961
|
+
return { startDate: earliestStart, endDate: latestEnd };
|
|
962
|
+
}
|
|
963
|
+
function deriveSummaryBounds(summaryId, adapter) {
|
|
964
|
+
return deriveSummaryBoundsWithDates(summaryId, adapter, (leafId) => {
|
|
965
|
+
const leaf = adapter.getActivity(leafId);
|
|
966
|
+
if (!leaf) return null;
|
|
967
|
+
return { startDate: leaf.startDate, endDate: leaf.endDate };
|
|
968
|
+
});
|
|
969
|
+
}
|
|
970
|
+
function endpointSpanHours(endpoint, bounds, adapter) {
|
|
971
|
+
if (!endpoint) return 0;
|
|
972
|
+
if (!bounds) return endpoint.durationHours;
|
|
973
|
+
return adapter.calculateDuration({
|
|
974
|
+
startDate: bounds.startDate,
|
|
975
|
+
endDate: bounds.endDate,
|
|
976
|
+
task: endpoint
|
|
979
977
|
});
|
|
980
|
-
return kept.length > 0 ? kept : leaves;
|
|
981
978
|
}
|
|
982
|
-
function
|
|
979
|
+
function sourceLagForLeaf(leafId, source, sourceBounds, adapter) {
|
|
980
|
+
if (!source) return 0;
|
|
981
|
+
const leaf = adapter.getActivity(leafId);
|
|
982
|
+
if (!sourceBounds || !leaf) return -source.durationHours;
|
|
983
|
+
return -adapter.calculateDuration({
|
|
984
|
+
startDate: sourceBounds.startDate,
|
|
985
|
+
endDate: leaf.endDate,
|
|
986
|
+
task: source
|
|
987
|
+
});
|
|
988
|
+
}
|
|
989
|
+
function hasIncomingRawLink(leafId, linksByActivity) {
|
|
990
|
+
const leafKey = String(leafId);
|
|
991
|
+
const bucket = linksByActivity.get(leafKey) ?? [];
|
|
992
|
+
return bucket.some((rawLink) => String(rawLink.target) === leafKey);
|
|
993
|
+
}
|
|
994
|
+
function targetOffsetForLeaf(leafId, targetStart, source, adapter, linksByActivity) {
|
|
995
|
+
if (hasIncomingRawLink(leafId, linksByActivity)) return 0;
|
|
996
|
+
const leaf = adapter.getActivity(leafId);
|
|
997
|
+
if (!targetStart || !leaf || !source) return 0;
|
|
998
|
+
return adapter.calculateDuration({
|
|
999
|
+
startDate: targetStart,
|
|
1000
|
+
endDate: leaf.startDate,
|
|
1001
|
+
task: source
|
|
1002
|
+
});
|
|
1003
|
+
}
|
|
1004
|
+
function resolveExpansionAnchors(originalLink, adapter) {
|
|
1005
|
+
const source = adapter.getActivity(originalLink.source);
|
|
1006
|
+
const target = adapter.getActivity(originalLink.target);
|
|
1007
|
+
const sourceBounds = deriveSummaryBounds(originalLink.source, adapter);
|
|
1008
|
+
const targetBounds = deriveSummaryBounds(originalLink.target, adapter);
|
|
1009
|
+
const sourceEndpointIsStart = originalLink.type === LINK_TYPE.START_TO_START || originalLink.type === LINK_TYPE.START_TO_FINISH;
|
|
1010
|
+
const targetEndpointIsFinish = originalLink.type === LINK_TYPE.FINISH_TO_FINISH || originalLink.type === LINK_TYPE.START_TO_FINISH;
|
|
1011
|
+
return {
|
|
1012
|
+
source,
|
|
1013
|
+
sourceBounds,
|
|
1014
|
+
targetStart: targetBounds?.startDate ?? target?.startDate,
|
|
1015
|
+
userLag: originalLink.lag ?? 0,
|
|
1016
|
+
sourceEndpointIsStart,
|
|
1017
|
+
targetLag: targetEndpointIsFinish ? -endpointSpanHours(target, targetBounds, adapter) : 0,
|
|
1018
|
+
summarySourceId: originalLink.type === LINK_TYPE.START_TO_START && sourceBounds ? originalLink.source : void 0
|
|
1019
|
+
};
|
|
1020
|
+
}
|
|
1021
|
+
function pushOffsetPreservingLinks(expanded, sourceIds, leafIds, originalLink, adapter, virtualIdCounter, linksByActivity) {
|
|
1022
|
+
const anchors = resolveExpansionAnchors(originalLink, adapter);
|
|
1023
|
+
const { source, sourceBounds, targetStart, userLag } = anchors;
|
|
1024
|
+
const { sourceEndpointIsStart, targetLag, summarySourceId } = anchors;
|
|
983
1025
|
let counter = virtualIdCounter;
|
|
984
1026
|
for (const srcId of sourceIds) {
|
|
985
|
-
|
|
1027
|
+
const sourceLag = sourceEndpointIsStart ? sourceLagForLeaf(srcId, source, sourceBounds, adapter) : 0;
|
|
1028
|
+
for (const tgtId of leafIds) {
|
|
986
1029
|
if (String(srcId) === String(tgtId)) continue;
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
1030
|
+
const offTarget = targetOffsetForLeaf(
|
|
1031
|
+
tgtId,
|
|
1032
|
+
targetStart,
|
|
1033
|
+
source,
|
|
1034
|
+
adapter,
|
|
1035
|
+
linksByActivity
|
|
1036
|
+
);
|
|
1037
|
+
expanded.push(
|
|
1038
|
+
buildVirtualLink(
|
|
1039
|
+
originalLink,
|
|
1040
|
+
srcId,
|
|
1041
|
+
tgtId,
|
|
1042
|
+
counter,
|
|
1043
|
+
sourceLag,
|
|
1044
|
+
targetLag,
|
|
1045
|
+
userLag + offTarget,
|
|
1046
|
+
summarySourceId,
|
|
1047
|
+
offTarget !== 0 && targetLag === 0 ? originalLink.target : void 0
|
|
1048
|
+
)
|
|
1049
|
+
);
|
|
994
1050
|
counter += 1;
|
|
995
1051
|
}
|
|
996
1052
|
}
|
|
997
1053
|
return counter;
|
|
998
1054
|
}
|
|
1055
|
+
function buildVirtualLink(originalLink, sourceId, targetId, counter, sourceLag, targetLag, trueLag, summarySourceId, offsetSummaryTargetId) {
|
|
1056
|
+
return {
|
|
1057
|
+
id: `virtual_${originalLink.id}_${counter}`,
|
|
1058
|
+
source: sourceId,
|
|
1059
|
+
target: targetId,
|
|
1060
|
+
type: originalLink.type,
|
|
1061
|
+
lag: originalLink.lag,
|
|
1062
|
+
_sourceLag: sourceLag,
|
|
1063
|
+
_targetLag: targetLag,
|
|
1064
|
+
_trueLag: trueLag,
|
|
1065
|
+
...summarySourceId === void 0 ? {} : { _summarySourceId: summarySourceId },
|
|
1066
|
+
...offsetSummaryTargetId === void 0 ? {} : { _summaryTargetId: offsetSummaryTargetId }
|
|
1067
|
+
};
|
|
1068
|
+
}
|
|
999
1069
|
|
|
1000
1070
|
// src/autoscheduler/utils/expanded-links-cache.ts
|
|
1001
1071
|
var ExpandedLinksCache = class {
|
|
@@ -1125,33 +1195,49 @@ function normalize(predecessor, successor, link) {
|
|
|
1125
1195
|
};
|
|
1126
1196
|
}
|
|
1127
1197
|
}
|
|
1128
|
-
function
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1198
|
+
function summaryAnchoredSourceLag(link, predecessor, adapter) {
|
|
1199
|
+
if (link._summarySourceId === void 0) return null;
|
|
1200
|
+
const summarySource = adapter.getActivity(link._summarySourceId);
|
|
1201
|
+
if (!summarySource) return null;
|
|
1202
|
+
const summaryBounds = deriveSummaryBounds(link._summarySourceId, adapter);
|
|
1203
|
+
if (!summaryBounds) return null;
|
|
1204
|
+
return -adapter.calculateDuration({
|
|
1205
|
+
startDate: summaryBounds.startDate,
|
|
1206
|
+
endDate: predecessor.endDate,
|
|
1207
|
+
task: summarySource
|
|
1208
|
+
});
|
|
1209
|
+
}
|
|
1210
|
+
function noLagSuccessorStart(predecessor, successor, link, adapter, isEndAnchoredType) {
|
|
1211
|
+
const snapsToPast = successor.durationHours === 0 && isEndAnchoredType;
|
|
1212
|
+
return {
|
|
1213
|
+
successorStart: adapter.getClosestWorkTime({
|
|
1214
|
+
date: predecessor.endDate,
|
|
1215
|
+
dir: snapsToPast ? "past" : "future",
|
|
1216
|
+
task: successor
|
|
1217
|
+
}),
|
|
1132
1218
|
link
|
|
1133
|
-
|
|
1134
|
-
|
|
1219
|
+
};
|
|
1220
|
+
}
|
|
1221
|
+
function calculateSuccessorStartFromLink(predecessor, successor, link, adapter) {
|
|
1222
|
+
const {
|
|
1223
|
+
sourceLag: frozenSourceLag,
|
|
1224
|
+
targetLag,
|
|
1225
|
+
trueLag,
|
|
1226
|
+
isFS,
|
|
1227
|
+
isFF
|
|
1228
|
+
} = normalize(predecessor, successor, link);
|
|
1229
|
+
const sourceLag = summaryAnchoredSourceLag(link, predecessor, adapter) ?? frozenSourceLag;
|
|
1230
|
+
const totalLag = sourceLag + targetLag + trueLag;
|
|
1231
|
+
const isZeroDurationSuccessor = successor.durationHours === 0;
|
|
1232
|
+
const hasLag = isZeroDurationSuccessor ? totalLag !== 0 : sourceLag !== 0 || targetLag !== 0 || trueLag !== 0;
|
|
1135
1233
|
if (!hasLag) {
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
}),
|
|
1144
|
-
link
|
|
1145
|
-
};
|
|
1146
|
-
}
|
|
1147
|
-
return {
|
|
1148
|
-
successorStart: adapter.getClosestWorkTime({
|
|
1149
|
-
date: predecessor.endDate,
|
|
1150
|
-
dir: "future",
|
|
1151
|
-
task: successor
|
|
1152
|
-
}),
|
|
1153
|
-
link
|
|
1154
|
-
};
|
|
1234
|
+
return noLagSuccessorStart(
|
|
1235
|
+
predecessor,
|
|
1236
|
+
successor,
|
|
1237
|
+
link,
|
|
1238
|
+
adapter,
|
|
1239
|
+
isFS || isFF
|
|
1240
|
+
);
|
|
1155
1241
|
}
|
|
1156
1242
|
const baseTask = isFS ? successor : predecessor;
|
|
1157
1243
|
let date2 = adapter.getClosestWorkTime({
|
|
@@ -1372,10 +1458,12 @@ async function asapPass(orderedIds, links, adapter, options, isCurrent, plans) {
|
|
|
1372
1458
|
const incoming = incomingLinks.get(String(activityId)) ?? [];
|
|
1373
1459
|
let maxStart = null;
|
|
1374
1460
|
let drivingLinkId = null;
|
|
1461
|
+
let drivingOffsetIsStale = false;
|
|
1375
1462
|
for (const link of incoming) {
|
|
1376
1463
|
const predecessorSnap = adapter.getActivity(link.source);
|
|
1377
1464
|
if (!predecessorSnap) continue;
|
|
1378
1465
|
const predDates = getActivityDates(link.source);
|
|
1466
|
+
const predecessorMovedThisRun = predDates.startDate.getTime() !== predecessorSnap.startDate.getTime() || predDates.endDate.getTime() !== predecessorSnap.endDate.getTime();
|
|
1379
1467
|
const effectivePred = {
|
|
1380
1468
|
...predecessorSnap,
|
|
1381
1469
|
startDate: predDates.startDate,
|
|
@@ -1405,8 +1493,13 @@ async function asapPass(orderedIds, links, adapter, options, isCurrent, plans) {
|
|
|
1405
1493
|
if (!maxStart || result.successorStart > maxStart) {
|
|
1406
1494
|
maxStart = result.successorStart;
|
|
1407
1495
|
drivingLinkId = String(link.id);
|
|
1496
|
+
drivingOffsetIsStale = link._summaryTargetId !== void 0 && !predecessorMovedThisRun;
|
|
1408
1497
|
}
|
|
1409
1498
|
}
|
|
1499
|
+
const staleOffsetWouldPullBack = maxStart !== null && drivingOffsetIsStale && maxStart < activity.startDate;
|
|
1500
|
+
if (staleOffsetWouldPullBack) {
|
|
1501
|
+
maxStart = new Date(activity.startDate);
|
|
1502
|
+
}
|
|
1410
1503
|
const existing = plans.get(activityId);
|
|
1411
1504
|
const plan = existing ? { ...existing } : {
|
|
1412
1505
|
activityId,
|
|
@@ -1574,31 +1667,33 @@ async function alapPass(reversedIds, links, asapPlans, adapter, _options, isCurr
|
|
|
1574
1667
|
latestEnd = boundary;
|
|
1575
1668
|
}
|
|
1576
1669
|
}
|
|
1670
|
+
const incomingForKind = incomingLinks.get(String(activityId)) ?? [];
|
|
1671
|
+
const isFinishMarker = incomingForKind.some(
|
|
1672
|
+
(incomingLink) => incomingLink.type === LINK_TYPE.FINISH_TO_START || incomingLink.type === LINK_TYPE.FINISH_TO_FINISH
|
|
1673
|
+
);
|
|
1674
|
+
const latestEndAtDayStart = new Date(
|
|
1675
|
+
Date.UTC(
|
|
1676
|
+
latestEnd.getUTCFullYear(),
|
|
1677
|
+
latestEnd.getUTCMonth(),
|
|
1678
|
+
latestEnd.getUTCDate()
|
|
1679
|
+
)
|
|
1680
|
+
);
|
|
1681
|
+
const finishMarkerEnd = () => adapter.getClosestWorkTime({
|
|
1682
|
+
date: latestEndAtDayStart,
|
|
1683
|
+
dir: "past",
|
|
1684
|
+
task: activity
|
|
1685
|
+
});
|
|
1686
|
+
const latestEndLandsInsideWorkingDay = adapter.getClosestWorkTime({ date: latestEnd, dir: "future", task: activity }).getTime() === latestEnd.getTime();
|
|
1577
1687
|
let snappedEnd;
|
|
1578
1688
|
if (activity.durationHours === 0 && successorAnchor === null) {
|
|
1579
|
-
snappedEnd = adapter.getClosestWorkTime({
|
|
1689
|
+
snappedEnd = isFinishMarker && latestEndLandsInsideWorkingDay ? finishMarkerEnd() : adapter.getClosestWorkTime({
|
|
1580
1690
|
date: latestEnd,
|
|
1581
1691
|
dir: "past",
|
|
1582
1692
|
task: activity
|
|
1583
1693
|
});
|
|
1584
1694
|
} else if (activity.durationHours === 0) {
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
(l) => l.type === LINK_TYPE.FINISH_TO_START || l.type === LINK_TYPE.FINISH_TO_FINISH
|
|
1588
|
-
);
|
|
1589
|
-
if (isFinishKind) {
|
|
1590
|
-
const dayStart = new Date(
|
|
1591
|
-
Date.UTC(
|
|
1592
|
-
latestEnd.getUTCFullYear(),
|
|
1593
|
-
latestEnd.getUTCMonth(),
|
|
1594
|
-
latestEnd.getUTCDate()
|
|
1595
|
-
)
|
|
1596
|
-
);
|
|
1597
|
-
snappedEnd = adapter.getClosestWorkTime({
|
|
1598
|
-
date: dayStart,
|
|
1599
|
-
dir: "past",
|
|
1600
|
-
task: activity
|
|
1601
|
-
});
|
|
1695
|
+
if (isFinishMarker) {
|
|
1696
|
+
snappedEnd = finishMarkerEnd();
|
|
1602
1697
|
} else {
|
|
1603
1698
|
snappedEnd = adapter.getClosestWorkTime({
|
|
1604
1699
|
date: latestEnd,
|
|
@@ -1631,10 +1726,16 @@ async function alapPass(reversedIds, links, asapPlans, adapter, _options, isCurr
|
|
|
1631
1726
|
plan.endDate = snappedEnd;
|
|
1632
1727
|
plan.drivingLinkId = null;
|
|
1633
1728
|
plan.kind = "alap";
|
|
1729
|
+
const predecessorFloor = plan.earliestSchedulingStart ?? null;
|
|
1634
1730
|
plan.earliestSchedulingStart = null;
|
|
1635
1731
|
plan.earliestSchedulingEnd = null;
|
|
1636
|
-
|
|
1637
|
-
plan.
|
|
1732
|
+
const alapTarget = predecessorFloor !== null && predecessorFloor.getTime() > snappedStart.getTime() ? predecessorFloor : snappedStart;
|
|
1733
|
+
plan.latestSchedulingStart = alapTarget;
|
|
1734
|
+
plan.latestSchedulingEnd = alapTarget === snappedStart ? snappedEnd : adapter.calculateEndDate({
|
|
1735
|
+
startDate: alapTarget,
|
|
1736
|
+
durationHours: activity.durationHours,
|
|
1737
|
+
task: activity
|
|
1738
|
+
});
|
|
1638
1739
|
limitPlanDates(activity, plan, adapter);
|
|
1639
1740
|
plans.set(activityId, plan);
|
|
1640
1741
|
}
|
|
@@ -2069,18 +2170,9 @@ var AutoScheduler = class {
|
|
|
2069
2170
|
}
|
|
2070
2171
|
const phaseScope = startPhase("schedule.scoping");
|
|
2071
2172
|
const allIds = this.adapter.getAllIds();
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
if (options.triggerId !== void 0 && options.triggerId !== null) {
|
|
2076
|
-
const group = findConnectedGroupForTrigger(
|
|
2077
|
-
options.triggerId,
|
|
2078
|
-
activeLinks
|
|
2079
|
-
);
|
|
2080
|
-
scopedLinks = group.links;
|
|
2081
|
-
scopedIds = Array.from(group.activityIds);
|
|
2082
|
-
scopedIdSet = new Set(scopedIds);
|
|
2083
|
-
}
|
|
2173
|
+
const scope = resolveScope(options, activeLinks, this.adapter);
|
|
2174
|
+
const scopedLinks = scope.links;
|
|
2175
|
+
const scopedIdSet = scope.idSet;
|
|
2084
2176
|
endPhase(phaseScope);
|
|
2085
2177
|
const phaseTopo = startPhase("schedule.topologicalSort");
|
|
2086
2178
|
const topoResult = resolveTopoResult(
|
|
@@ -2177,6 +2269,34 @@ function endPhase(handle) {
|
|
|
2177
2269
|
const elapsed = performance.now() - handle.startedAt;
|
|
2178
2270
|
console.log(`[scheduler] ${handle.name} ${elapsed.toFixed(1)}ms`);
|
|
2179
2271
|
}
|
|
2272
|
+
function resolveScope(options, activeLinks, adapter) {
|
|
2273
|
+
const triggerId = options.triggerId;
|
|
2274
|
+
if (triggerId === void 0 || triggerId === null) {
|
|
2275
|
+
return { idSet: null, links: activeLinks };
|
|
2276
|
+
}
|
|
2277
|
+
const group = findConnectedGroupForTrigger(triggerId, activeLinks);
|
|
2278
|
+
return widenScopeToAlapActivities(group, activeLinks, adapter);
|
|
2279
|
+
}
|
|
2280
|
+
function widenScopeToAlapActivities(group, allLinks, adapter) {
|
|
2281
|
+
const idSet = new Set(group.activityIds);
|
|
2282
|
+
const widenedAlapKeys = /* @__PURE__ */ new Set();
|
|
2283
|
+
for (const activity of adapter.getAllActivities()) {
|
|
2284
|
+
const activityKey = String(activity.id);
|
|
2285
|
+
const isOutOfComponentAlap = activity.constraintType === CONSTRAINT_TYPE2.ALAP && !idSet.has(activityKey);
|
|
2286
|
+
if (!isOutOfComponentAlap) continue;
|
|
2287
|
+
widenedAlapKeys.add(activityKey);
|
|
2288
|
+
idSet.add(activityKey);
|
|
2289
|
+
}
|
|
2290
|
+
if (widenedAlapKeys.size === 0) {
|
|
2291
|
+
return { idSet, links: group.links };
|
|
2292
|
+
}
|
|
2293
|
+
const links = [...group.links];
|
|
2294
|
+
for (const link of allLinks) {
|
|
2295
|
+
const touchesWidenedAlap = widenedAlapKeys.has(String(link.source)) || widenedAlapKeys.has(String(link.target));
|
|
2296
|
+
if (touchesWidenedAlap) links.push(link);
|
|
2297
|
+
}
|
|
2298
|
+
return { idSet, links };
|
|
2299
|
+
}
|
|
2180
2300
|
function resolveTopoResult(cache, allIds, allLinks, scopedIdSet) {
|
|
2181
2301
|
const fullTopo = cache.get(allIds, allLinks);
|
|
2182
2302
|
if (fullTopo.hasCycles) {
|
|
@@ -2194,9 +2314,10 @@ function resolveTopoResult(cache, allIds, allLinks, scopedIdSet) {
|
|
|
2194
2314
|
}
|
|
2195
2315
|
|
|
2196
2316
|
// src/internal/post-processors/adjust-link-lag-on-task-move.ts
|
|
2197
|
-
function adjustLinkLagOnTaskMove(targetId, adapter) {
|
|
2317
|
+
function adjustLinkLagOnTaskMove(targetId, adapter, preEditTarget) {
|
|
2198
2318
|
const target = adapter.getActivity(targetId);
|
|
2199
2319
|
if (!target) return;
|
|
2320
|
+
const targetForLagMath = preEditTarget ? { ...target, endDate: preEditTarget.endDate } : target;
|
|
2200
2321
|
const calendarApi = adapter.calendarReader.getCalendar(
|
|
2201
2322
|
String(target.calendarId)
|
|
2202
2323
|
);
|
|
@@ -2206,9 +2327,11 @@ function adjustLinkLagOnTaskMove(targetId, adapter) {
|
|
|
2206
2327
|
const source = adapter.getActivity(link.source);
|
|
2207
2328
|
if (!source) continue;
|
|
2208
2329
|
if (source.constraintType === "alap") continue;
|
|
2330
|
+
const isEndAnchoredIntoMilestone = isMilestoneType(target.type) && (link.type === LINK_TYPE.START_TO_FINISH || link.type === LINK_TYPE.FINISH_TO_FINISH);
|
|
2331
|
+
if (isEndAnchoredIntoMilestone) continue;
|
|
2209
2332
|
const { sourceDate, targetDate } = pickDatesForLinkType(
|
|
2210
2333
|
source,
|
|
2211
|
-
|
|
2334
|
+
targetForLagMath,
|
|
2212
2335
|
link.type
|
|
2213
2336
|
);
|
|
2214
2337
|
const newLag = dateMath.computeLagBetweenTasks(
|
|
@@ -2256,20 +2379,15 @@ function computeLeafRealWork(workHours, progress) {
|
|
|
2256
2379
|
// src/propagations/upward/parent-bounds.ts
|
|
2257
2380
|
async function updateParentBoundsFromChildren(adapter, dirtyIds, recomputeProgress = true, options = {}) {
|
|
2258
2381
|
const parents = dirtyIds ? findAncestorsOfDirty(adapter, dirtyIds) : findAllParents(adapter);
|
|
2259
|
-
|
|
2382
|
+
const progressMode = recomputeProgress ? options.progressMode ?? "freeze-when-no-contribution" : "skip";
|
|
2383
|
+
await recomputeParentsCooperatively(parents, adapter, progressMode, {
|
|
2260
2384
|
recomputeRealWork: options.recomputeRealWork ?? false
|
|
2261
2385
|
});
|
|
2262
2386
|
}
|
|
2263
|
-
function recomputeParentBoundsSync(adapter, dirtyIds, recomputeProgress = true) {
|
|
2264
|
-
const parents = findAncestorsOfDirty(adapter, dirtyIds);
|
|
2265
|
-
for (const parentId of parents) {
|
|
2266
|
-
recomputeParentFromChildren(parentId, adapter, recomputeProgress);
|
|
2267
|
-
}
|
|
2268
|
-
}
|
|
2269
2387
|
function recomputeSingleParentDisplayBounds(parentId, adapter) {
|
|
2270
|
-
recomputeParentFromChildren(parentId, adapter,
|
|
2388
|
+
recomputeParentFromChildren(parentId, adapter, "skip");
|
|
2271
2389
|
}
|
|
2272
|
-
async function recomputeParentsCooperatively(parents, adapter,
|
|
2390
|
+
async function recomputeParentsCooperatively(parents, adapter, progressMode, options = {
|
|
2273
2391
|
recomputeRealWork: false
|
|
2274
2392
|
}) {
|
|
2275
2393
|
const YIELD_EVERY_N_PARENTS = 200;
|
|
@@ -2278,7 +2396,7 @@ async function recomputeParentsCooperatively(parents, adapter, recomputeProgress
|
|
|
2278
2396
|
recomputeParentFromChildren(
|
|
2279
2397
|
parentId,
|
|
2280
2398
|
adapter,
|
|
2281
|
-
|
|
2399
|
+
progressMode,
|
|
2282
2400
|
options.recomputeRealWork
|
|
2283
2401
|
);
|
|
2284
2402
|
processed += 1;
|
|
@@ -2328,7 +2446,7 @@ function aggregateChildren(childrenIds, adapter, includeRealWork) {
|
|
|
2328
2446
|
}
|
|
2329
2447
|
return { minStart, maxEnd, realWorkSum, weightedChildren };
|
|
2330
2448
|
}
|
|
2331
|
-
function recomputeParentFromChildren(parentId, adapter,
|
|
2449
|
+
function recomputeParentFromChildren(parentId, adapter, progressMode = "freeze-when-no-contribution", recomputeRealWork = false) {
|
|
2332
2450
|
const parent = adapter.getActivity(parentId);
|
|
2333
2451
|
if (!parent) return;
|
|
2334
2452
|
const childrenIds = adapter.getChildren(parentId);
|
|
@@ -2346,11 +2464,12 @@ function recomputeParentFromChildren(parentId, adapter, recomputeProgress = true
|
|
|
2346
2464
|
const progressRollup = computeWeightedProgressRollup(
|
|
2347
2465
|
aggregate.weightedChildren
|
|
2348
2466
|
);
|
|
2349
|
-
|
|
2467
|
+
const shouldWriteProgress = progressMode !== "skip" && (progressRollup !== null || progressMode === "zero-when-no-contribution");
|
|
2468
|
+
if (shouldWriteProgress) {
|
|
2350
2469
|
adapter.setActivityField(
|
|
2351
2470
|
parentId,
|
|
2352
2471
|
"progress",
|
|
2353
|
-
roundProgressPerLevel(progressRollup)
|
|
2472
|
+
roundProgressPerLevel(progressRollup ?? 0)
|
|
2354
2473
|
);
|
|
2355
2474
|
}
|
|
2356
2475
|
if (recomputeRealWork) {
|
|
@@ -2412,7 +2531,7 @@ function runRecordLastStartDate(activityId, adapter) {
|
|
|
2412
2531
|
const activity = adapter.getActivity(activityId);
|
|
2413
2532
|
if (activity) adapter.setLastStartDate(activityId, activity.startDate);
|
|
2414
2533
|
}
|
|
2415
|
-
function runPostProcessorsOnAdapter(activityId, processorNames, adapter) {
|
|
2534
|
+
function runPostProcessorsOnAdapter(activityId, processorNames, adapter, preEditActivity) {
|
|
2416
2535
|
for (const name of processorNames) {
|
|
2417
2536
|
const fn = name in POST_PROCESSORS ? POST_PROCESSORS[name] : void 0;
|
|
2418
2537
|
if (!fn) {
|
|
@@ -2421,7 +2540,7 @@ function runPostProcessorsOnAdapter(activityId, processorNames, adapter) {
|
|
|
2421
2540
|
);
|
|
2422
2541
|
continue;
|
|
2423
2542
|
}
|
|
2424
|
-
fn(activityId, adapter);
|
|
2543
|
+
fn(activityId, adapter, preEditActivity ?? null);
|
|
2425
2544
|
}
|
|
2426
2545
|
}
|
|
2427
2546
|
function runNoOp(name) {
|
|
@@ -2694,10 +2813,7 @@ var durationPipeline = {
|
|
|
2694
2813
|
);
|
|
2695
2814
|
return {
|
|
2696
2815
|
...fieldChanges(extraFields, {
|
|
2697
|
-
|
|
2698
|
-
// anchored and Finish moves. Running the ALAP pass would instead
|
|
2699
|
-
// preserve Finish and pull Start, which is not the observed UI flow.
|
|
2700
|
-
autoSchedule: activity.constraintType !== "alap",
|
|
2816
|
+
autoSchedule: true,
|
|
2701
2817
|
postProcessors: [POST_PROCESSOR.RECORD_LAST_START_DATE]
|
|
2702
2818
|
}),
|
|
2703
2819
|
...constraintCheck.violated ? {
|
|
@@ -2859,16 +2975,22 @@ function buildCanonicalRealWorkOverlay(activity, progress, hierarchy) {
|
|
|
2859
2975
|
realWorkByActivity.set(activity.id, selfRealWork);
|
|
2860
2976
|
return realWorkByActivity;
|
|
2861
2977
|
}
|
|
2978
|
+
function summariesOverSummariesDeepestFirst(activity, hierarchy) {
|
|
2979
|
+
const subtreeIds = [activity.id, ...hierarchy.getDescendantIds(activity.id)];
|
|
2980
|
+
const hasSummaryChild = (parentId) => hierarchy.getChildProgressInfo(parentId).some((child) => hierarchy.hasChildren(child.id));
|
|
2981
|
+
const depthOf3 = (activityId) => hierarchy.getAncestorIds(activityId).length;
|
|
2982
|
+
return subtreeIds.filter((candidateId) => hasSummaryChild(String(candidateId))).map(String).sort((first, second) => depthOf3(second) - depthOf3(first));
|
|
2983
|
+
}
|
|
2862
2984
|
function buildAncestorRollupCascade(activity, newValue, hierarchy) {
|
|
2863
2985
|
const overlay = /* @__PURE__ */ new Map();
|
|
2864
2986
|
overlay.set(activity.id, newValue);
|
|
2865
2987
|
for (const descendantId of hierarchy.getDescendantIds(activity.id)) {
|
|
2866
2988
|
overlay.set(descendantId, newValue);
|
|
2867
2989
|
}
|
|
2868
|
-
const chain = [
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2990
|
+
const chain = [
|
|
2991
|
+
...summariesOverSummariesDeepestFirst(activity, hierarchy),
|
|
2992
|
+
...hierarchy.getAncestorIds(activity.id)
|
|
2993
|
+
];
|
|
2872
2994
|
const mutations = [];
|
|
2873
2995
|
for (const id of chain) {
|
|
2874
2996
|
const rollup = computeWeightedProgress(id, overlay, hierarchy);
|
|
@@ -3265,6 +3387,8 @@ function checkIsWorkingDay(newDate, activity, ctx) {
|
|
|
3265
3387
|
return null;
|
|
3266
3388
|
}
|
|
3267
3389
|
function detectEndDateConstraintWarning(activity, newEndDate) {
|
|
3390
|
+
const cannotViolateStartPin = effectiveConstraintType(activity) === CONSTRAINT_TYPE2.MSO;
|
|
3391
|
+
if (cannotViolateStartPin) return void 0;
|
|
3268
3392
|
const projectedDate = pickProjectedDateForConstraint(
|
|
3269
3393
|
effectiveConstraintType(activity),
|
|
3270
3394
|
activity.startDate,
|
|
@@ -3285,7 +3409,8 @@ function detectEndDateConstraintWarning(activity, newEndDate) {
|
|
|
3285
3409
|
function buildEndDateExtraFields(activity, newEndDate, ctx, violatesConstraint = false) {
|
|
3286
3410
|
const fields = {};
|
|
3287
3411
|
const isMilestone = isMilestoneType(activity.type);
|
|
3288
|
-
|
|
3412
|
+
const seedsMilestoneDate = isMilestone && !violatesConstraint && hasDatelessConstraintType(activity);
|
|
3413
|
+
if (seedsMilestoneDate) {
|
|
3289
3414
|
Object.assign(fields, setConstraintDate(activity.startDate));
|
|
3290
3415
|
} else if (violatesConstraint || hasDatelessConstraintType(activity)) {
|
|
3291
3416
|
Object.assign(
|
|
@@ -3295,10 +3420,8 @@ function buildEndDateExtraFields(activity, newEndDate, ctx, violatesConstraint =
|
|
|
3295
3420
|
);
|
|
3296
3421
|
}
|
|
3297
3422
|
const newDuration = calculateNewDuration(activity, newEndDate, ctx);
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
if (flippedType) fields.type = flippedType;
|
|
3301
|
-
}
|
|
3423
|
+
const flippedType = typeForNewDuration(activity.durationHours, newDuration);
|
|
3424
|
+
if (flippedType) fields.type = flippedType;
|
|
3302
3425
|
Object.assign(fields, setDuration(newDuration));
|
|
3303
3426
|
fields.endDate = newEndDate;
|
|
3304
3427
|
return fields;
|
|
@@ -3715,6 +3838,49 @@ function setLinkFieldDynamic(state, linkId, field, value) {
|
|
|
3715
3838
|
state.setLinkFieldDynamic(linkId, field, value);
|
|
3716
3839
|
}
|
|
3717
3840
|
|
|
3841
|
+
// src/internal/state/clone-core-activity.ts
|
|
3842
|
+
function cloneCoreActivity(activity) {
|
|
3843
|
+
return {
|
|
3844
|
+
...activity,
|
|
3845
|
+
startDate: new Date(activity.startDate),
|
|
3846
|
+
endDate: new Date(activity.endDate),
|
|
3847
|
+
constraintDate: cloneNullableDate(activity.constraintDate),
|
|
3848
|
+
dateOrigin: cloneNullableDate(activity.dateOrigin),
|
|
3849
|
+
newActivityIds: [...activity.newActivityIds],
|
|
3850
|
+
pendingRequestIds: [...activity.pendingRequestIds],
|
|
3851
|
+
responsableIds: [...activity.responsableIds],
|
|
3852
|
+
tagIds: [...activity.tagIds],
|
|
3853
|
+
baselinePoints: activity.baselinePoints.map((point) => ({
|
|
3854
|
+
...point,
|
|
3855
|
+
startDate: cloneNullableDate(point.startDate),
|
|
3856
|
+
endDate: cloneNullableDate(point.endDate)
|
|
3857
|
+
})),
|
|
3858
|
+
baselineSnapshot: cloneBaselineSnapshot(activity.baselineSnapshot),
|
|
3859
|
+
criticalPath: cloneCriticalPath(activity.criticalPath)
|
|
3860
|
+
};
|
|
3861
|
+
}
|
|
3862
|
+
function cloneNullableDate(value) {
|
|
3863
|
+
return value === null ? null : new Date(value);
|
|
3864
|
+
}
|
|
3865
|
+
function cloneBaselineSnapshot(value) {
|
|
3866
|
+
if (value === null) return null;
|
|
3867
|
+
return {
|
|
3868
|
+
...value,
|
|
3869
|
+
startDate: cloneNullableDate(value.startDate),
|
|
3870
|
+
endDate: cloneNullableDate(value.endDate)
|
|
3871
|
+
};
|
|
3872
|
+
}
|
|
3873
|
+
function cloneCriticalPath(value) {
|
|
3874
|
+
if (value === null) return null;
|
|
3875
|
+
return {
|
|
3876
|
+
...value,
|
|
3877
|
+
earlyStart: cloneNullableDate(value.earlyStart),
|
|
3878
|
+
earlyFinish: cloneNullableDate(value.earlyFinish),
|
|
3879
|
+
lateStart: cloneNullableDate(value.lateStart),
|
|
3880
|
+
lateFinish: cloneNullableDate(value.lateFinish)
|
|
3881
|
+
};
|
|
3882
|
+
}
|
|
3883
|
+
|
|
3718
3884
|
// src/dispatch/shared/snapshots.ts
|
|
3719
3885
|
function collectTouchedIds(primary, changes) {
|
|
3720
3886
|
const ids = /* @__PURE__ */ new Set([String(primary)]);
|
|
@@ -3732,13 +3898,7 @@ function snapshotActivities(adapter, ids) {
|
|
|
3732
3898
|
return out;
|
|
3733
3899
|
}
|
|
3734
3900
|
function structuredCloneActivity(activity) {
|
|
3735
|
-
return
|
|
3736
|
-
...activity,
|
|
3737
|
-
startDate: new Date(activity.startDate),
|
|
3738
|
-
endDate: new Date(activity.endDate),
|
|
3739
|
-
constraintDate: activity.constraintDate ? new Date(activity.constraintDate) : null,
|
|
3740
|
-
dateOrigin: activity.dateOrigin ? new Date(activity.dateOrigin) : null
|
|
3741
|
-
};
|
|
3901
|
+
return cloneCoreActivity(activity);
|
|
3742
3902
|
}
|
|
3743
3903
|
function applyFieldChanges(adapter, activityId, changes) {
|
|
3744
3904
|
applyCanonicalPatch(adapter, activityId, changes.patch);
|
|
@@ -3766,6 +3926,7 @@ function buildActivityChanges(adapter, before, touched) {
|
|
|
3766
3926
|
}
|
|
3767
3927
|
const beforeSnap = before.get(id);
|
|
3768
3928
|
const diff = diffActivity(beforeSnap, afterSnap);
|
|
3929
|
+
if (beforeSnap && Object.keys(diff).length === 0) continue;
|
|
3769
3930
|
if (!beforeSnap) {
|
|
3770
3931
|
out.push({
|
|
3771
3932
|
id,
|
|
@@ -3790,12 +3951,33 @@ function diffActivity(before, after) {
|
|
|
3790
3951
|
const afterRec = after;
|
|
3791
3952
|
const keys = /* @__PURE__ */ new Set([...Object.keys(beforeRec), ...Object.keys(afterRec)]);
|
|
3792
3953
|
for (const k of keys) {
|
|
3793
|
-
if (!
|
|
3954
|
+
if (Object.hasOwn(beforeRec, k) !== Object.hasOwn(afterRec, k) || !fieldValueEqual(beforeRec[k], afterRec[k])) {
|
|
3794
3955
|
fields[k] = { before: beforeRec[k], after: afterRec[k] };
|
|
3795
3956
|
}
|
|
3796
3957
|
}
|
|
3797
3958
|
return fields;
|
|
3798
3959
|
}
|
|
3960
|
+
function fieldValueEqual(left, right) {
|
|
3961
|
+
if (Object.is(left, right)) return true;
|
|
3962
|
+
if (left instanceof Date && right instanceof Date) {
|
|
3963
|
+
return left.getTime() === right.getTime();
|
|
3964
|
+
}
|
|
3965
|
+
if (left == null || right == null) return false;
|
|
3966
|
+
if (Array.isArray(left) || Array.isArray(right)) {
|
|
3967
|
+
if (!Array.isArray(left) || !Array.isArray(right)) return false;
|
|
3968
|
+
if (left.length !== right.length) return false;
|
|
3969
|
+
return left.every((value, index) => fieldValueEqual(value, right[index]));
|
|
3970
|
+
}
|
|
3971
|
+
if (typeof left !== "object" || typeof right !== "object") return false;
|
|
3972
|
+
const leftRecord = left;
|
|
3973
|
+
const rightRecord = right;
|
|
3974
|
+
const leftKeys = Object.keys(leftRecord);
|
|
3975
|
+
const rightKeys = Object.keys(rightRecord);
|
|
3976
|
+
if (leftKeys.length !== rightKeys.length) return false;
|
|
3977
|
+
return leftKeys.every(
|
|
3978
|
+
(key) => Object.hasOwn(rightRecord, key) && fieldValueEqual(leftRecord[key], rightRecord[key])
|
|
3979
|
+
);
|
|
3980
|
+
}
|
|
3799
3981
|
function collectDirtyForInlineEdit(triggerId, touchedIds, scheduledIds) {
|
|
3800
3982
|
const dirty = /* @__PURE__ */ new Set();
|
|
3801
3983
|
dirty.add(triggerId);
|
|
@@ -3821,21 +4003,6 @@ function foldCorrelativeShifts(adapter, shifts, excludeIds, beforeSnap, touched)
|
|
|
3821
4003
|
beforeSnap.set(shift.activityId, beforeImage);
|
|
3822
4004
|
}
|
|
3823
4005
|
}
|
|
3824
|
-
function shallowEqual(a, b) {
|
|
3825
|
-
if (a === b) return true;
|
|
3826
|
-
if (a instanceof Date && b instanceof Date)
|
|
3827
|
-
return a.getTime() === b.getTime();
|
|
3828
|
-
if (a == null || b == null) return false;
|
|
3829
|
-
if (typeof a !== typeof b) return false;
|
|
3830
|
-
if (Array.isArray(a) && Array.isArray(b)) {
|
|
3831
|
-
if (a.length !== b.length) return false;
|
|
3832
|
-
for (let i = 0; i < a.length; i++) {
|
|
3833
|
-
if (!shallowEqual(a[i], b[i])) return false;
|
|
3834
|
-
}
|
|
3835
|
-
return true;
|
|
3836
|
-
}
|
|
3837
|
-
return false;
|
|
3838
|
-
}
|
|
3839
4006
|
|
|
3840
4007
|
// src/shared/backend-date.ts
|
|
3841
4008
|
var BACKEND_DATE_FORMAT_REGEX = /^(\d{4})\/(\d{1,2})\/(\d{1,2})\s+(\d{1,2}):(\d{2})$/;
|
|
@@ -3919,6 +4086,77 @@ function computeExpectedProgressLive(rootIds, now, state) {
|
|
|
3919
4086
|
for (const activityId of rootIds) visit(activityId);
|
|
3920
4087
|
return changed;
|
|
3921
4088
|
}
|
|
4089
|
+
function applyExpectedProgressLive(state, now) {
|
|
4090
|
+
const rootIds = [];
|
|
4091
|
+
state.forEachActivity((activity, activityId) => {
|
|
4092
|
+
if (activity.parentId === null) rootIds.push(activityId);
|
|
4093
|
+
});
|
|
4094
|
+
computeExpectedProgressLive(rootIds, now, state);
|
|
4095
|
+
}
|
|
4096
|
+
|
|
4097
|
+
// src/propagations/shared/get-active-baseline.ts
|
|
4098
|
+
function getActiveBaseline(activity) {
|
|
4099
|
+
const points = activity?.baselinePoints;
|
|
4100
|
+
if (!Array.isArray(points) || points.length === 0) return null;
|
|
4101
|
+
return points.find((point) => point.isActiveVersion) ?? null;
|
|
4102
|
+
}
|
|
4103
|
+
|
|
4104
|
+
// src/columns/expected-progress-base/compute.ts
|
|
4105
|
+
var isProject2 = (a) => a.type === "project";
|
|
4106
|
+
var activeBaselineOf = (a) => getActiveBaseline(a);
|
|
4107
|
+
var leafExpected = (a, now, adapter, defaultBaseCalendarId) => {
|
|
4108
|
+
const base = activeBaselineOf(a);
|
|
4109
|
+
if (!base) return 0;
|
|
4110
|
+
const cal = (base.baseCalendarId != null ? adapter.getBaseCalendar(`${base.baseCalendarId}-base`) : null) ?? (defaultBaseCalendarId ? adapter.getBaseCalendar(defaultBaseCalendarId) : null);
|
|
4111
|
+
if (!cal) return 0;
|
|
4112
|
+
if (!base.startDate || !base.endDate) return 0;
|
|
4113
|
+
return expectedProgressFromBaseline(base.startDate, base.endDate, now, cal);
|
|
4114
|
+
};
|
|
4115
|
+
function computeExpectedProgress(rootIds, now, adapter, defaultBaseCalendarId = null) {
|
|
4116
|
+
const changed = [];
|
|
4117
|
+
const writeIfChanged = (id, value) => {
|
|
4118
|
+
const a = adapter.getActivity(id);
|
|
4119
|
+
if (!a) return;
|
|
4120
|
+
if (a.expectedProgressBaseline !== value) {
|
|
4121
|
+
adapter.setActivityField(id, "expectedProgressBaseline", value);
|
|
4122
|
+
changed.push(id);
|
|
4123
|
+
}
|
|
4124
|
+
};
|
|
4125
|
+
const visit = (id) => {
|
|
4126
|
+
const a = adapter.getActivity(id);
|
|
4127
|
+
if (!a) return 0;
|
|
4128
|
+
if (!isProject2(a)) {
|
|
4129
|
+
const v2 = leafExpected(a, now, adapter, defaultBaseCalendarId);
|
|
4130
|
+
writeIfChanged(id, v2);
|
|
4131
|
+
return v2;
|
|
4132
|
+
}
|
|
4133
|
+
let acc = 0;
|
|
4134
|
+
for (const childId of adapter.getChildrenIds(id)) {
|
|
4135
|
+
const childBase = visit(childId);
|
|
4136
|
+
const child = adapter.getActivity(childId);
|
|
4137
|
+
const weight = typeof child?.ponderator === "number" ? child.ponderator : 0;
|
|
4138
|
+
acc += childBase * weight;
|
|
4139
|
+
}
|
|
4140
|
+
const v = acc / 100;
|
|
4141
|
+
writeIfChanged(id, v);
|
|
4142
|
+
return v;
|
|
4143
|
+
};
|
|
4144
|
+
for (const id of rootIds) visit(id);
|
|
4145
|
+
return changed;
|
|
4146
|
+
}
|
|
4147
|
+
function runExpectedProgressBase(state, now, defaultBaseCalendarId = null) {
|
|
4148
|
+
const adapter = {
|
|
4149
|
+
getChildrenIds: (parentId) => state.getChildren(String(parentId)).map((childId) => String(childId)),
|
|
4150
|
+
getActivity: (id) => state.getActivity(id),
|
|
4151
|
+
setActivityField: (id, field, value) => setActivityFieldDynamic(state, id, field, value),
|
|
4152
|
+
getBaseCalendar: (engineId) => state.calendarReader.getCalendar(engineId)
|
|
4153
|
+
};
|
|
4154
|
+
const rootIds = [];
|
|
4155
|
+
state.forEachActivity((activity, id) => {
|
|
4156
|
+
if (activity.parentId === null) rootIds.push(id);
|
|
4157
|
+
});
|
|
4158
|
+
return computeExpectedProgress(rootIds, now, adapter, defaultBaseCalendarId);
|
|
4159
|
+
}
|
|
3922
4160
|
|
|
3923
4161
|
// src/columns/status/compute.ts
|
|
3924
4162
|
var roundToTwoDecimals = (value) => Math.round(value * 100) / 100;
|
|
@@ -3954,552 +4192,248 @@ function applyStatusPass(state, criteria) {
|
|
|
3954
4192
|
return changed;
|
|
3955
4193
|
}
|
|
3956
4194
|
|
|
3957
|
-
// src/
|
|
3958
|
-
|
|
3959
|
-
function
|
|
3960
|
-
const
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
function iterateInVisualOrder(adapter) {
|
|
3965
|
-
const result = [];
|
|
3966
|
-
const visit = (activity) => {
|
|
3967
|
-
result.push(activity);
|
|
3968
|
-
const childIds = getChildrenInVisualOrder(String(activity.id), adapter);
|
|
3969
|
-
for (const childId of childIds) {
|
|
3970
|
-
const child = adapter.getActivity(childId);
|
|
3971
|
-
if (child) visit(child);
|
|
3972
|
-
}
|
|
4195
|
+
// src/critical-path/legacy/shims/moment.js
|
|
4196
|
+
function moment(input) {
|
|
4197
|
+
const d = input instanceof Date ? new Date(input.getTime()) : input && typeof input === "object" && typeof input.valueOf === "function" ? new Date(input.valueOf()) : new Date(input);
|
|
4198
|
+
const accessor = (getUTC, setUTC) => (value) => {
|
|
4199
|
+
if (value === void 0) return d[getUTC]();
|
|
4200
|
+
d[setUTC](value);
|
|
4201
|
+
return api;
|
|
3973
4202
|
};
|
|
3974
|
-
const
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
const idx = siblings.findIndex((id) => String(id) === String(taskId));
|
|
3987
|
-
if (idx <= 0) return null;
|
|
3988
|
-
for (let i = idx - 1; i >= 0; i--) {
|
|
3989
|
-
const candidateId = siblings[i];
|
|
3990
|
-
if (candidateId === void 0) continue;
|
|
3991
|
-
if (!setHas(selected, candidateId)) return candidateId;
|
|
3992
|
-
}
|
|
3993
|
-
return null;
|
|
3994
|
-
}
|
|
3995
|
-
function visualIndexInParent(taskId, adapter) {
|
|
3996
|
-
const activity = adapter.getActivity(taskId);
|
|
3997
|
-
if (!activity) return -1;
|
|
3998
|
-
const parentKey = parentKeyOf(activity);
|
|
3999
|
-
const siblings = getChildrenInVisualOrder(parentKey, adapter);
|
|
4000
|
-
return siblings.findIndex((id) => String(id) === String(taskId));
|
|
4203
|
+
const api = {
|
|
4204
|
+
__isMomentShim: true,
|
|
4205
|
+
clone: () => moment(d),
|
|
4206
|
+
hours: accessor("getUTCHours", "setUTCHours"),
|
|
4207
|
+
minutes: accessor("getUTCMinutes", "setUTCMinutes"),
|
|
4208
|
+
seconds: accessor("getUTCSeconds", "setUTCSeconds"),
|
|
4209
|
+
milliseconds: accessor("getUTCMilliseconds", "setUTCMilliseconds"),
|
|
4210
|
+
valueOf: () => d.getTime(),
|
|
4211
|
+
toDate: () => new Date(d.getTime()),
|
|
4212
|
+
getTime: () => d.getTime()
|
|
4213
|
+
};
|
|
4214
|
+
return api;
|
|
4001
4215
|
}
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
for (const id of childIds) {
|
|
4010
|
-
const snap = adapter.getActivity(id);
|
|
4011
|
-
if (snap) out.push(snap);
|
|
4216
|
+
moment.isMoment = (x) => Boolean(x) && typeof x === "object" && x.__isMomentShim === true;
|
|
4217
|
+
var moment_default = moment;
|
|
4218
|
+
|
|
4219
|
+
// src/critical-path/legacy/helpers/isValidDate.js
|
|
4220
|
+
function isDate(obj) {
|
|
4221
|
+
if (obj && obj.constructor === Date) {
|
|
4222
|
+
return Boolean(obj.getFullYear && obj.getMonth && obj.getDate);
|
|
4012
4223
|
}
|
|
4013
|
-
return
|
|
4014
|
-
}
|
|
4015
|
-
function byCorrelativeIdThenId(a, b) {
|
|
4016
|
-
const ac = correlativeIdOf(a);
|
|
4017
|
-
const bc = correlativeIdOf(b);
|
|
4018
|
-
if (ac !== bc) return ac - bc;
|
|
4019
|
-
return String(a.id).localeCompare(String(b.id));
|
|
4020
|
-
}
|
|
4021
|
-
function correlativeIdOf(activity) {
|
|
4022
|
-
const raw = activity.correlativeId;
|
|
4023
|
-
const n = typeof raw === "number" ? raw : Number(raw);
|
|
4024
|
-
return Number.isFinite(n) ? n : NOT_SET_SORT_VALUE;
|
|
4025
|
-
}
|
|
4026
|
-
function parentKeyOf(activity) {
|
|
4027
|
-
const parentId = activity.parentId;
|
|
4028
|
-
if (parentId === null) return "0";
|
|
4029
|
-
return parentId;
|
|
4224
|
+
return false;
|
|
4030
4225
|
}
|
|
4031
|
-
function
|
|
4032
|
-
|
|
4033
|
-
return set.has(String(id));
|
|
4226
|
+
function isValidDate2(obj) {
|
|
4227
|
+
return isDate(obj) && !isNaN(obj.getTime());
|
|
4034
4228
|
}
|
|
4035
4229
|
|
|
4036
|
-
// src/
|
|
4037
|
-
function
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
});
|
|
4043
|
-
roots.sort(byCorrelativeId);
|
|
4044
|
-
const stack = [];
|
|
4045
|
-
pushInReverseOrder(stack, roots);
|
|
4046
|
-
const shifts = [];
|
|
4047
|
-
let counter = 0;
|
|
4048
|
-
while (stack.length > 0) {
|
|
4049
|
-
const activity = stack.pop();
|
|
4050
|
-
if (activity.correlativeId !== counter) {
|
|
4051
|
-
const before = typeof activity.correlativeId === "number" ? activity.correlativeId : void 0;
|
|
4052
|
-
shifts.push({ activityId: String(activity.id), before });
|
|
4053
|
-
if (before !== void 0)
|
|
4054
|
-
adapter.noteCorrelativeBefore?.(String(activity.id), before);
|
|
4055
|
-
setCorrelativeId(activity, counter);
|
|
4056
|
-
}
|
|
4057
|
-
counter += 1;
|
|
4058
|
-
const children = collectChildrenSnapshots(String(activity.id), adapter);
|
|
4059
|
-
children.sort(byCorrelativeId);
|
|
4060
|
-
pushInReverseOrder(stack, children);
|
|
4230
|
+
// src/critical-path/legacy/helpers/addDurationToDate.js
|
|
4231
|
+
function addDurationToDate(activityCalendar, date2, duration, activity) {
|
|
4232
|
+
if (!isValidDate2(new Date(date2))) {
|
|
4233
|
+
throw new Error(
|
|
4234
|
+
`Invalid date argument for calculateEndDate method. Date: ${date2}, Activity: ${JSON.stringify(activity)}`
|
|
4235
|
+
);
|
|
4061
4236
|
}
|
|
4062
|
-
|
|
4237
|
+
const dateToCalculate = date2;
|
|
4238
|
+
return activityCalendar.calculateEndDate({
|
|
4239
|
+
start_date: new Date(dateToCalculate),
|
|
4240
|
+
duration,
|
|
4241
|
+
unit: "hour",
|
|
4242
|
+
task: activity
|
|
4243
|
+
});
|
|
4063
4244
|
}
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4245
|
+
|
|
4246
|
+
// src/critical-path/legacy/helpers/getNextWorkingHour.js
|
|
4247
|
+
function getNextWorkingHour(activityParams) {
|
|
4248
|
+
if (!isValidDate2(new Date(activityParams.dateBaseToCalculate))) {
|
|
4249
|
+
throw new Error("Invalid date argument for getClosestWorkTime method");
|
|
4067
4250
|
}
|
|
4068
|
-
}
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
activity.correlativeId = value;
|
|
4251
|
+
const { dateBaseToCalculate, activityCalendar, direction, activity } = activityParams;
|
|
4252
|
+
const newDate = activityCalendar.$gantt.getClosestWorkTime({
|
|
4253
|
+
date: new Date(dateBaseToCalculate),
|
|
4254
|
+
dir: direction,
|
|
4255
|
+
unit: "hour",
|
|
4256
|
+
task: activity
|
|
4257
|
+
});
|
|
4258
|
+
return newDate;
|
|
4077
4259
|
}
|
|
4078
4260
|
|
|
4079
|
-
// src/
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4261
|
+
// src/critical-path/legacy/helpers/filters.js
|
|
4262
|
+
var byFirstLevel = (activity) => {
|
|
4263
|
+
if (!activity) return false;
|
|
4264
|
+
return activity["$level"] === 1;
|
|
4265
|
+
};
|
|
4266
|
+
var filterByParentType = (activity) => activity.type === "project";
|
|
4267
|
+
var avoidSubproject = (activity) => activity["$level"] !== 0;
|
|
4268
|
+
var byTaskType = (activity) => activity.type === "task";
|
|
4269
|
+
var byTaskTypeAndMilestone = (activity) => activity.type === "task" || activity.type === "milestone";
|
|
4270
|
+
var filters_default = {
|
|
4271
|
+
byFirstLevel,
|
|
4272
|
+
filterByParentType,
|
|
4273
|
+
avoidSubproject,
|
|
4274
|
+
byTaskType,
|
|
4275
|
+
byTaskTypeAndMilestone
|
|
4276
|
+
};
|
|
4277
|
+
|
|
4278
|
+
// src/critical-path/legacy/constants/constraints.js
|
|
4279
|
+
var CONSTRAINT_TYPES = Object.freeze({
|
|
4280
|
+
MFO: "mfo",
|
|
4281
|
+
MSO: "mso",
|
|
4282
|
+
FNLT: "fnlt",
|
|
4283
|
+
FNET: "fnet",
|
|
4284
|
+
SNET: "snet",
|
|
4285
|
+
SNLT: "snlt",
|
|
4286
|
+
ALAP: "alap",
|
|
4287
|
+
ASAP: "asap"
|
|
4288
|
+
});
|
|
4289
|
+
|
|
4290
|
+
// src/critical-path/legacy/constants/linkTypes.js
|
|
4291
|
+
var LINK_TYPES = Object.freeze({
|
|
4292
|
+
FS: "fs",
|
|
4293
|
+
SS: "ss",
|
|
4294
|
+
FF: "ff",
|
|
4295
|
+
SF: "sf"
|
|
4296
|
+
});
|
|
4297
|
+
|
|
4298
|
+
// src/critical-path/legacy/constants/linkByCode.js
|
|
4299
|
+
function getLinkNameByCode(code) {
|
|
4300
|
+
const linkMap = {
|
|
4301
|
+
0: "fs",
|
|
4302
|
+
1: "ss",
|
|
4303
|
+
2: "ff",
|
|
4304
|
+
3: "sf"
|
|
4101
4305
|
};
|
|
4102
|
-
|
|
4103
|
-
return changedIds;
|
|
4306
|
+
return linkMap[Number(code)] || "sf";
|
|
4104
4307
|
}
|
|
4105
4308
|
|
|
4106
|
-
// src/
|
|
4107
|
-
|
|
4108
|
-
const {
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
if (now) {
|
|
4117
|
-
applyExpectedProgressLive(state, now);
|
|
4118
|
-
applyStatusPass(state, sector.statusCriteria);
|
|
4309
|
+
// src/critical-path/legacy/base/identifiers/secondLevelActivities.js
|
|
4310
|
+
function identifySecondLevelActivities(params) {
|
|
4311
|
+
const { gantt, pendingParentsWithNoLinks, calculations, linkProperty } = params;
|
|
4312
|
+
try {
|
|
4313
|
+
const subprojectsWithNoLinks = getSubprojectsWithNoLinks({
|
|
4314
|
+
gantt,
|
|
4315
|
+
pendingParentsWithNoLinks
|
|
4316
|
+
});
|
|
4317
|
+
if (subprojectsWithNoLinks.length === 0) {
|
|
4318
|
+
return /* @__PURE__ */ new Set();
|
|
4119
4319
|
}
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4320
|
+
const allChildrenFromParents = getAllChildrenFromParents({
|
|
4321
|
+
gantt,
|
|
4322
|
+
subprojectsWithNoLinks
|
|
4323
|
+
});
|
|
4324
|
+
const childrenThatCanBeCalculated = filterChildrenThatCanBeCalculated({
|
|
4325
|
+
gantt,
|
|
4326
|
+
childrenIds: allChildrenFromParents,
|
|
4327
|
+
linkProperty,
|
|
4328
|
+
getArrayOfLinkedActivities,
|
|
4329
|
+
calculations
|
|
4330
|
+
});
|
|
4331
|
+
return new Set(childrenThatCanBeCalculated.map((activity) => activity.id));
|
|
4332
|
+
} catch (e) {
|
|
4333
|
+
throw e;
|
|
4130
4334
|
}
|
|
4131
4335
|
}
|
|
4132
|
-
function
|
|
4133
|
-
const
|
|
4134
|
-
|
|
4135
|
-
if (activity.parentId === null) rootIds.push(activityId);
|
|
4136
|
-
});
|
|
4137
|
-
computeExpectedProgressLive(rootIds, now, state);
|
|
4336
|
+
function getSubprojectsWithNoLinks(params) {
|
|
4337
|
+
const { gantt, pendingParentsWithNoLinks } = params;
|
|
4338
|
+
return gantt.getTaskByTime().filter(filters_default.filterByParentType).filter((activity) => pendingParentsWithNoLinks.has(activity.id)).map((activity) => activity.id);
|
|
4138
4339
|
}
|
|
4139
|
-
function
|
|
4140
|
-
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4340
|
+
function getAllChildrenFromParents(params) {
|
|
4341
|
+
const { gantt, subprojectsWithNoLinks } = params;
|
|
4342
|
+
const allChildrenSet = /* @__PURE__ */ new Set();
|
|
4343
|
+
for (const subprojectId of subprojectsWithNoLinks) {
|
|
4344
|
+
const childrenIds = gantt.getChildren(subprojectId);
|
|
4345
|
+
const validChildren = childrenIds.filter((childId) => {
|
|
4346
|
+
const childActivity = gantt.getTask(childId);
|
|
4347
|
+
const isTaskOrMilestone = filters_default.byTaskTypeAndMilestone(childActivity);
|
|
4348
|
+
const hasProgressLessThan100 = Number(childActivity.progress) < 100;
|
|
4349
|
+
return isTaskOrMilestone && hasProgressLessThan100;
|
|
4148
4350
|
});
|
|
4149
|
-
|
|
4351
|
+
validChildren.forEach((childId) => allChildrenSet.add(childId));
|
|
4352
|
+
}
|
|
4353
|
+
return [...allChildrenSet];
|
|
4150
4354
|
}
|
|
4151
|
-
function
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4355
|
+
function filterChildrenThatCanBeCalculated(params) {
|
|
4356
|
+
const {
|
|
4357
|
+
gantt,
|
|
4358
|
+
childrenIds,
|
|
4359
|
+
linkProperty,
|
|
4360
|
+
getArrayOfLinkedActivities: getArrayOfLinkedActivities3,
|
|
4361
|
+
calculations
|
|
4362
|
+
} = params;
|
|
4363
|
+
const calculableChildren = [];
|
|
4364
|
+
for (const childId of childrenIds) {
|
|
4365
|
+
const activity = gantt.getTask(childId);
|
|
4366
|
+
const links = activity[linkProperty] || [];
|
|
4367
|
+
const linkedActivities = getArrayOfLinkedActivities3({
|
|
4368
|
+
gantt,
|
|
4369
|
+
links,
|
|
4370
|
+
linkDirection: linkProperty === "$source" ? "target" : "source"
|
|
4158
4371
|
});
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
function normalizeLoadedConstraintDates(state) {
|
|
4162
|
-
state.forEachActivity((activity) => {
|
|
4163
|
-
const type = activity.constraintType;
|
|
4164
|
-
if (!type || !activity.constraintDate) return;
|
|
4165
|
-
const constraintDate = activity.constraintDate;
|
|
4166
|
-
if (activity.type === "milestone" && (constraintDate.getUTCHours() !== 0 || constraintDate.getUTCMinutes() !== 0)) {
|
|
4167
|
-
return;
|
|
4168
|
-
}
|
|
4169
|
-
const calendar = state.calendarReader.getCalendar(
|
|
4170
|
-
String(activity.calendarId)
|
|
4171
|
-
);
|
|
4172
|
-
if (!calendar) return;
|
|
4173
|
-
activity.constraintDate = normalizeConstraintDate(
|
|
4174
|
-
activity.constraintDate,
|
|
4175
|
-
calendar,
|
|
4176
|
-
type
|
|
4177
|
-
);
|
|
4178
|
-
});
|
|
4179
|
-
}
|
|
4180
|
-
function normalizeMilestoneConstraintDatesForDisplay(state) {
|
|
4181
|
-
state.forEachActivity((activity) => {
|
|
4182
|
-
if (activity.type !== "milestone") return;
|
|
4183
|
-
const type = activity.constraintType;
|
|
4184
|
-
if (!type || !activity.constraintDate) return;
|
|
4185
|
-
const calendar = state.calendarReader.getCalendar(
|
|
4186
|
-
String(activity.calendarId)
|
|
4187
|
-
);
|
|
4188
|
-
if (!calendar) return;
|
|
4189
|
-
activity.constraintDate = normalizeConstraintDate(
|
|
4190
|
-
activity.constraintDate,
|
|
4191
|
-
calendar,
|
|
4192
|
-
type
|
|
4372
|
+
const isLinkedWithCalculatedOrSibling = linkedActivities.every(
|
|
4373
|
+
(linkedActivityId) => calculations.has(linkedActivityId)
|
|
4193
4374
|
);
|
|
4194
|
-
|
|
4375
|
+
if (isLinkedWithCalculatedOrSibling) {
|
|
4376
|
+
calculableChildren.push(activity);
|
|
4377
|
+
}
|
|
4378
|
+
}
|
|
4379
|
+
return calculableChildren;
|
|
4195
4380
|
}
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
const
|
|
4200
|
-
|
|
4201
|
-
|
|
4381
|
+
function getArrayOfLinkedActivities(params) {
|
|
4382
|
+
const { gantt, links, linkDirection } = params;
|
|
4383
|
+
const linkedActivityIds = [];
|
|
4384
|
+
for (const linkId of links) {
|
|
4385
|
+
const link = gantt.getLink(linkId);
|
|
4386
|
+
if (!link) {
|
|
4387
|
+
continue;
|
|
4388
|
+
}
|
|
4389
|
+
const linkedActivityId = Number(link[linkDirection]);
|
|
4390
|
+
linkedActivityIds.push(linkedActivityId);
|
|
4391
|
+
}
|
|
4392
|
+
return linkedActivityIds;
|
|
4202
4393
|
}
|
|
4203
4394
|
|
|
4204
|
-
// src/
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
return expectedProgressFromBaseline(base.startDate, base.endDate, now, cal);
|
|
4214
|
-
};
|
|
4215
|
-
function computeExpectedProgress(rootIds, now, adapter, defaultBaseCalendarId = null) {
|
|
4216
|
-
const changed = [];
|
|
4217
|
-
const writeIfChanged = (id, value) => {
|
|
4218
|
-
const a = adapter.getActivity(id);
|
|
4219
|
-
if (!a) return;
|
|
4220
|
-
if (a.expectedProgressBaseline !== value) {
|
|
4221
|
-
adapter.setActivityField(id, "expectedProgressBaseline", value);
|
|
4222
|
-
changed.push(id);
|
|
4223
|
-
}
|
|
4224
|
-
};
|
|
4225
|
-
const visit = (id) => {
|
|
4226
|
-
const a = adapter.getActivity(id);
|
|
4227
|
-
if (!a) return 0;
|
|
4228
|
-
if (!isProject2(a)) {
|
|
4229
|
-
const v2 = leafExpected(a, now, adapter, defaultBaseCalendarId);
|
|
4230
|
-
writeIfChanged(id, v2);
|
|
4231
|
-
return v2;
|
|
4395
|
+
// src/critical-path/legacy/base/identifiers/initialActivities.js
|
|
4396
|
+
function identifyInitialActivities({ gantt, linkProperty, direction }) {
|
|
4397
|
+
try {
|
|
4398
|
+
const chainStartActivities = getChainStartActivities(gantt, linkProperty);
|
|
4399
|
+
if (direction === "forward") {
|
|
4400
|
+
return {
|
|
4401
|
+
chainStartActivities,
|
|
4402
|
+
activitiesStartChainButChildrenOfLinkedParents: null
|
|
4403
|
+
};
|
|
4232
4404
|
}
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4405
|
+
if (direction === "backward") {
|
|
4406
|
+
return processBackwardActivities(
|
|
4407
|
+
chainStartActivities,
|
|
4408
|
+
gantt,
|
|
4409
|
+
linkProperty
|
|
4410
|
+
);
|
|
4239
4411
|
}
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
};
|
|
4244
|
-
for (const id of rootIds) visit(id);
|
|
4245
|
-
return changed;
|
|
4246
|
-
}
|
|
4247
|
-
function runExpectedProgressBase(state, now, defaultBaseCalendarId = null) {
|
|
4248
|
-
const adapter = {
|
|
4249
|
-
getChildrenIds: (parentId) => state.getChildren(String(parentId)).map((childId) => String(childId)),
|
|
4250
|
-
getActivity: (id) => state.getActivity(id),
|
|
4251
|
-
setActivityField: (id, field, value) => setActivityFieldDynamic(state, id, field, value),
|
|
4252
|
-
getBaseCalendar: (engineId) => state.calendarReader.getCalendar(engineId)
|
|
4253
|
-
};
|
|
4254
|
-
const rootIds = [];
|
|
4255
|
-
state.forEachActivity((activity, id) => {
|
|
4256
|
-
if (activity.parentId === null) rootIds.push(id);
|
|
4257
|
-
});
|
|
4258
|
-
return computeExpectedProgress(rootIds, now, adapter, defaultBaseCalendarId);
|
|
4259
|
-
}
|
|
4260
|
-
|
|
4261
|
-
// src/critical-path/legacy/shims/moment.js
|
|
4262
|
-
function moment(input) {
|
|
4263
|
-
const d = input instanceof Date ? new Date(input.getTime()) : input && typeof input === "object" && typeof input.valueOf === "function" ? new Date(input.valueOf()) : new Date(input);
|
|
4264
|
-
const accessor = (getUTC, setUTC) => (value) => {
|
|
4265
|
-
if (value === void 0) return d[getUTC]();
|
|
4266
|
-
d[setUTC](value);
|
|
4267
|
-
return api;
|
|
4268
|
-
};
|
|
4269
|
-
const api = {
|
|
4270
|
-
__isMomentShim: true,
|
|
4271
|
-
clone: () => moment(d),
|
|
4272
|
-
hours: accessor("getUTCHours", "setUTCHours"),
|
|
4273
|
-
minutes: accessor("getUTCMinutes", "setUTCMinutes"),
|
|
4274
|
-
seconds: accessor("getUTCSeconds", "setUTCSeconds"),
|
|
4275
|
-
milliseconds: accessor("getUTCMilliseconds", "setUTCMilliseconds"),
|
|
4276
|
-
valueOf: () => d.getTime(),
|
|
4277
|
-
toDate: () => new Date(d.getTime()),
|
|
4278
|
-
getTime: () => d.getTime()
|
|
4279
|
-
};
|
|
4280
|
-
return api;
|
|
4281
|
-
}
|
|
4282
|
-
moment.isMoment = (x) => Boolean(x) && typeof x === "object" && x.__isMomentShim === true;
|
|
4283
|
-
var moment_default = moment;
|
|
4284
|
-
|
|
4285
|
-
// src/critical-path/legacy/helpers/isValidDate.js
|
|
4286
|
-
function isDate(obj) {
|
|
4287
|
-
if (obj && obj.constructor === Date) {
|
|
4288
|
-
return Boolean(obj.getFullYear && obj.getMonth && obj.getDate);
|
|
4412
|
+
} catch (e) {
|
|
4413
|
+
console.log("Critical Path", e);
|
|
4414
|
+
throw e;
|
|
4289
4415
|
}
|
|
4290
|
-
return false;
|
|
4291
4416
|
}
|
|
4292
|
-
function
|
|
4293
|
-
return
|
|
4417
|
+
function getChainStartActivities(gantt, linkProperty) {
|
|
4418
|
+
return gantt.getTaskByTime().filter(filters_default.avoidSubproject).filter(filters_default.byTaskTypeAndMilestone).filter((activity) => !activity[linkProperty].length);
|
|
4294
4419
|
}
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
4301
|
-
);
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
unit: "hour",
|
|
4308
|
-
task: activity
|
|
4420
|
+
function processBackwardActivities(chainStartActivities, gantt, linkProperty) {
|
|
4421
|
+
const withoutLinkedParents = [];
|
|
4422
|
+
const activitiesStartChainButChildrenOfLinkedParents = /* @__PURE__ */ new Set();
|
|
4423
|
+
chainStartActivities.forEach((activity) => {
|
|
4424
|
+
const parentId = Number(activity.parent);
|
|
4425
|
+
const parentActivity = gantt.getTask(parentId);
|
|
4426
|
+
if (!parentActivity) return;
|
|
4427
|
+
if (parentActivity[linkProperty].length > 0) {
|
|
4428
|
+
activitiesStartChainButChildrenOfLinkedParents.add(activity.id);
|
|
4429
|
+
} else if (parentActivity.constraint_type !== "fnlt") {
|
|
4430
|
+
withoutLinkedParents.push(activity);
|
|
4431
|
+
}
|
|
4309
4432
|
});
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
if (!isValidDate2(new Date(activityParams.dateBaseToCalculate))) {
|
|
4315
|
-
throw new Error("Invalid date argument for getClosestWorkTime method");
|
|
4316
|
-
}
|
|
4317
|
-
const { dateBaseToCalculate, activityCalendar, direction, activity } = activityParams;
|
|
4318
|
-
const newDate = activityCalendar.$gantt.getClosestWorkTime({
|
|
4319
|
-
date: new Date(dateBaseToCalculate),
|
|
4320
|
-
dir: direction,
|
|
4321
|
-
unit: "hour",
|
|
4322
|
-
task: activity
|
|
4323
|
-
});
|
|
4324
|
-
return newDate;
|
|
4325
|
-
}
|
|
4326
|
-
|
|
4327
|
-
// src/critical-path/legacy/helpers/filters.js
|
|
4328
|
-
var byFirstLevel = (activity) => {
|
|
4329
|
-
if (!activity) return false;
|
|
4330
|
-
return activity["$level"] === 1;
|
|
4331
|
-
};
|
|
4332
|
-
var filterByParentType = (activity) => activity.type === "project";
|
|
4333
|
-
var avoidSubproject = (activity) => activity["$level"] !== 0;
|
|
4334
|
-
var byTaskType = (activity) => activity.type === "task";
|
|
4335
|
-
var byTaskTypeAndMilestone = (activity) => activity.type === "task" || activity.type === "milestone";
|
|
4336
|
-
var filters_default = {
|
|
4337
|
-
byFirstLevel,
|
|
4338
|
-
filterByParentType,
|
|
4339
|
-
avoidSubproject,
|
|
4340
|
-
byTaskType,
|
|
4341
|
-
byTaskTypeAndMilestone
|
|
4342
|
-
};
|
|
4343
|
-
|
|
4344
|
-
// src/critical-path/legacy/constants/constraints.js
|
|
4345
|
-
var CONSTRAINT_TYPES = Object.freeze({
|
|
4346
|
-
MFO: "mfo",
|
|
4347
|
-
MSO: "mso",
|
|
4348
|
-
FNLT: "fnlt",
|
|
4349
|
-
FNET: "fnet",
|
|
4350
|
-
SNET: "snet",
|
|
4351
|
-
SNLT: "snlt",
|
|
4352
|
-
ALAP: "alap",
|
|
4353
|
-
ASAP: "asap"
|
|
4354
|
-
});
|
|
4355
|
-
|
|
4356
|
-
// src/critical-path/legacy/constants/linkTypes.js
|
|
4357
|
-
var LINK_TYPES = Object.freeze({
|
|
4358
|
-
FS: "fs",
|
|
4359
|
-
SS: "ss",
|
|
4360
|
-
FF: "ff",
|
|
4361
|
-
SF: "sf"
|
|
4362
|
-
});
|
|
4363
|
-
|
|
4364
|
-
// src/critical-path/legacy/constants/linkByCode.js
|
|
4365
|
-
function getLinkNameByCode(code) {
|
|
4366
|
-
const linkMap = {
|
|
4367
|
-
0: "fs",
|
|
4368
|
-
1: "ss",
|
|
4369
|
-
2: "ff",
|
|
4370
|
-
3: "sf"
|
|
4371
|
-
};
|
|
4372
|
-
return linkMap[Number(code)] || "sf";
|
|
4373
|
-
}
|
|
4374
|
-
|
|
4375
|
-
// src/critical-path/legacy/base/identifiers/secondLevelActivities.js
|
|
4376
|
-
function identifySecondLevelActivities(params) {
|
|
4377
|
-
const { gantt, pendingParentsWithNoLinks, calculations, linkProperty } = params;
|
|
4378
|
-
try {
|
|
4379
|
-
const subprojectsWithNoLinks = getSubprojectsWithNoLinks({
|
|
4380
|
-
gantt,
|
|
4381
|
-
pendingParentsWithNoLinks
|
|
4382
|
-
});
|
|
4383
|
-
if (subprojectsWithNoLinks.length === 0) {
|
|
4384
|
-
return /* @__PURE__ */ new Set();
|
|
4385
|
-
}
|
|
4386
|
-
const allChildrenFromParents = getAllChildrenFromParents({
|
|
4387
|
-
gantt,
|
|
4388
|
-
subprojectsWithNoLinks
|
|
4389
|
-
});
|
|
4390
|
-
const childrenThatCanBeCalculated = filterChildrenThatCanBeCalculated({
|
|
4391
|
-
gantt,
|
|
4392
|
-
childrenIds: allChildrenFromParents,
|
|
4393
|
-
linkProperty,
|
|
4394
|
-
getArrayOfLinkedActivities,
|
|
4395
|
-
calculations
|
|
4396
|
-
});
|
|
4397
|
-
return new Set(childrenThatCanBeCalculated.map((activity) => activity.id));
|
|
4398
|
-
} catch (e) {
|
|
4399
|
-
throw e;
|
|
4400
|
-
}
|
|
4401
|
-
}
|
|
4402
|
-
function getSubprojectsWithNoLinks(params) {
|
|
4403
|
-
const { gantt, pendingParentsWithNoLinks } = params;
|
|
4404
|
-
return gantt.getTaskByTime().filter(filters_default.filterByParentType).filter((activity) => pendingParentsWithNoLinks.has(activity.id)).map((activity) => activity.id);
|
|
4405
|
-
}
|
|
4406
|
-
function getAllChildrenFromParents(params) {
|
|
4407
|
-
const { gantt, subprojectsWithNoLinks } = params;
|
|
4408
|
-
const allChildrenSet = /* @__PURE__ */ new Set();
|
|
4409
|
-
for (const subprojectId of subprojectsWithNoLinks) {
|
|
4410
|
-
const childrenIds = gantt.getChildren(subprojectId);
|
|
4411
|
-
const validChildren = childrenIds.filter((childId) => {
|
|
4412
|
-
const childActivity = gantt.getTask(childId);
|
|
4413
|
-
const isTaskOrMilestone = filters_default.byTaskTypeAndMilestone(childActivity);
|
|
4414
|
-
const hasProgressLessThan100 = Number(childActivity.progress) < 100;
|
|
4415
|
-
return isTaskOrMilestone && hasProgressLessThan100;
|
|
4416
|
-
});
|
|
4417
|
-
validChildren.forEach((childId) => allChildrenSet.add(childId));
|
|
4418
|
-
}
|
|
4419
|
-
return [...allChildrenSet];
|
|
4420
|
-
}
|
|
4421
|
-
function filterChildrenThatCanBeCalculated(params) {
|
|
4422
|
-
const {
|
|
4423
|
-
gantt,
|
|
4424
|
-
childrenIds,
|
|
4425
|
-
linkProperty,
|
|
4426
|
-
getArrayOfLinkedActivities: getArrayOfLinkedActivities3,
|
|
4427
|
-
calculations
|
|
4428
|
-
} = params;
|
|
4429
|
-
const calculableChildren = [];
|
|
4430
|
-
for (const childId of childrenIds) {
|
|
4431
|
-
const activity = gantt.getTask(childId);
|
|
4432
|
-
const links = activity[linkProperty] || [];
|
|
4433
|
-
const linkedActivities = getArrayOfLinkedActivities3({
|
|
4434
|
-
gantt,
|
|
4435
|
-
links,
|
|
4436
|
-
linkDirection: linkProperty === "$source" ? "target" : "source"
|
|
4437
|
-
});
|
|
4438
|
-
const isLinkedWithCalculatedOrSibling = linkedActivities.every(
|
|
4439
|
-
(linkedActivityId) => calculations.has(linkedActivityId)
|
|
4440
|
-
);
|
|
4441
|
-
if (isLinkedWithCalculatedOrSibling) {
|
|
4442
|
-
calculableChildren.push(activity);
|
|
4443
|
-
}
|
|
4444
|
-
}
|
|
4445
|
-
return calculableChildren;
|
|
4446
|
-
}
|
|
4447
|
-
function getArrayOfLinkedActivities(params) {
|
|
4448
|
-
const { gantt, links, linkDirection } = params;
|
|
4449
|
-
const linkedActivityIds = [];
|
|
4450
|
-
for (const linkId of links) {
|
|
4451
|
-
const link = gantt.getLink(linkId);
|
|
4452
|
-
if (!link) {
|
|
4453
|
-
continue;
|
|
4454
|
-
}
|
|
4455
|
-
const linkedActivityId = Number(link[linkDirection]);
|
|
4456
|
-
linkedActivityIds.push(linkedActivityId);
|
|
4457
|
-
}
|
|
4458
|
-
return linkedActivityIds;
|
|
4459
|
-
}
|
|
4460
|
-
|
|
4461
|
-
// src/critical-path/legacy/base/identifiers/initialActivities.js
|
|
4462
|
-
function identifyInitialActivities({ gantt, linkProperty, direction }) {
|
|
4463
|
-
try {
|
|
4464
|
-
const chainStartActivities = getChainStartActivities(gantt, linkProperty);
|
|
4465
|
-
if (direction === "forward") {
|
|
4466
|
-
return {
|
|
4467
|
-
chainStartActivities,
|
|
4468
|
-
activitiesStartChainButChildrenOfLinkedParents: null
|
|
4469
|
-
};
|
|
4470
|
-
}
|
|
4471
|
-
if (direction === "backward") {
|
|
4472
|
-
return processBackwardActivities(
|
|
4473
|
-
chainStartActivities,
|
|
4474
|
-
gantt,
|
|
4475
|
-
linkProperty
|
|
4476
|
-
);
|
|
4477
|
-
}
|
|
4478
|
-
} catch (e) {
|
|
4479
|
-
console.log("Critical Path", e);
|
|
4480
|
-
throw e;
|
|
4481
|
-
}
|
|
4482
|
-
}
|
|
4483
|
-
function getChainStartActivities(gantt, linkProperty) {
|
|
4484
|
-
return gantt.getTaskByTime().filter(filters_default.avoidSubproject).filter(filters_default.byTaskTypeAndMilestone).filter((activity) => !activity[linkProperty].length);
|
|
4485
|
-
}
|
|
4486
|
-
function processBackwardActivities(chainStartActivities, gantt, linkProperty) {
|
|
4487
|
-
const withoutLinkedParents = [];
|
|
4488
|
-
const activitiesStartChainButChildrenOfLinkedParents = /* @__PURE__ */ new Set();
|
|
4489
|
-
chainStartActivities.forEach((activity) => {
|
|
4490
|
-
const parentId = Number(activity.parent);
|
|
4491
|
-
const parentActivity = gantt.getTask(parentId);
|
|
4492
|
-
if (!parentActivity) return;
|
|
4493
|
-
if (parentActivity[linkProperty].length > 0) {
|
|
4494
|
-
activitiesStartChainButChildrenOfLinkedParents.add(activity.id);
|
|
4495
|
-
} else if (parentActivity.constraint_type !== "fnlt") {
|
|
4496
|
-
withoutLinkedParents.push(activity);
|
|
4497
|
-
}
|
|
4498
|
-
});
|
|
4499
|
-
return {
|
|
4500
|
-
chainStartActivities: withoutLinkedParents,
|
|
4501
|
-
activitiesStartChainButChildrenOfLinkedParents
|
|
4502
|
-
};
|
|
4433
|
+
return {
|
|
4434
|
+
chainStartActivities: withoutLinkedParents,
|
|
4435
|
+
activitiesStartChainButChildrenOfLinkedParents
|
|
4436
|
+
};
|
|
4503
4437
|
}
|
|
4504
4438
|
|
|
4505
4439
|
// src/critical-path/legacy/base/identifiers/identifyParentsWithAndWithoutLinks.js
|
|
@@ -9491,13 +9425,18 @@ var NON_SCHEDULING_INLINE_COLUMNS = /* @__PURE__ */ new Set([
|
|
|
9491
9425
|
COLUMN.SUBCONTRACT_ID,
|
|
9492
9426
|
COLUMN.TAGS
|
|
9493
9427
|
]);
|
|
9494
|
-
var
|
|
9428
|
+
var NON_SCHEDULING_KINDS = /* @__PURE__ */ new Set([
|
|
9495
9429
|
"selection-toggle",
|
|
9496
9430
|
"selection-replace",
|
|
9497
9431
|
"visibility-set",
|
|
9498
9432
|
"sir-sync",
|
|
9499
|
-
"activity-lookahead-sync"
|
|
9433
|
+
"activity-lookahead-sync",
|
|
9434
|
+
"persistence-acknowledge",
|
|
9435
|
+
"baseline-apply",
|
|
9436
|
+
"ponderator-criterion-set",
|
|
9437
|
+
"status-criteria-set"
|
|
9500
9438
|
]);
|
|
9439
|
+
var NO_STRUCTURAL_EXEMPTIONS = /* @__PURE__ */ new Set();
|
|
9501
9440
|
function editsOnlyNonSchedulingColumns(action) {
|
|
9502
9441
|
if (action.kind === "inline-edit") {
|
|
9503
9442
|
return NON_SCHEDULING_INLINE_COLUMNS.has(action.column);
|
|
@@ -9510,11 +9449,14 @@ function editsOnlyNonSchedulingColumns(action) {
|
|
|
9510
9449
|
return false;
|
|
9511
9450
|
}
|
|
9512
9451
|
function isSchedulingDispatch(action, structuralStaleKinds) {
|
|
9513
|
-
if (
|
|
9452
|
+
if (NON_SCHEDULING_KINDS.has(action.kind)) return false;
|
|
9514
9453
|
if (structuralStaleKinds.has(action.kind)) return false;
|
|
9515
9454
|
if (editsOnlyNonSchedulingColumns(action)) return false;
|
|
9516
9455
|
return true;
|
|
9517
9456
|
}
|
|
9457
|
+
function dispatchChangesSchedulingState(action) {
|
|
9458
|
+
return isSchedulingDispatch(action, NO_STRUCTURAL_EXEMPTIONS);
|
|
9459
|
+
}
|
|
9518
9460
|
function resolveRunCriticalPath(action) {
|
|
9519
9461
|
return isSchedulingDispatch(
|
|
9520
9462
|
action,
|
|
@@ -9590,6 +9532,9 @@ function resolveDerivedPasses(action, autoSchedule, options) {
|
|
|
9590
9532
|
// src/dispatch/shared/post-mutation.ts
|
|
9591
9533
|
async function runPostMutation(deps, args) {
|
|
9592
9534
|
const passes = resolvePasses(args);
|
|
9535
|
+
if (passes.has(DERIVED_PASS.AUTOSCHEDULE)) {
|
|
9536
|
+
await refreshMutatedParentBounds(deps.adapter, args);
|
|
9537
|
+
}
|
|
9593
9538
|
const schedule = passes.has(DERIVED_PASS.AUTOSCHEDULE) ? await runAutoschedule(deps, args.autoscheduleFrom) : emptySchedule();
|
|
9594
9539
|
await rollUpParentBounds(deps.adapter, args, schedule.scheduledIds, passes);
|
|
9595
9540
|
await runDerivedRecomputes(deps, passes, args.now);
|
|
@@ -9598,7 +9543,11 @@ async function runPostMutation(deps, args) {
|
|
|
9598
9543
|
function resolvePasses(args) {
|
|
9599
9544
|
const requested = args.autoscheduleFrom !== null;
|
|
9600
9545
|
const ran = !args.options.skipAutoSchedule && requested;
|
|
9601
|
-
|
|
9546
|
+
const passes = new Set(
|
|
9547
|
+
resolveDerivedPasses(args.action, { ran }, args.options)
|
|
9548
|
+
);
|
|
9549
|
+
if (args.recomputeParentProgress) passes.add(DERIVED_PASS.PARENT_PROGRESS);
|
|
9550
|
+
return passes;
|
|
9602
9551
|
}
|
|
9603
9552
|
async function runAutoschedule(deps, autoscheduleFrom) {
|
|
9604
9553
|
const options = autoscheduleFrom === "roots" ? {} : { triggerId: autoscheduleFrom };
|
|
@@ -9609,20 +9558,23 @@ async function runAutoschedule(deps, autoscheduleFrom) {
|
|
|
9609
9558
|
}
|
|
9610
9559
|
function captureScheduledRows(adapter, updatedIds) {
|
|
9611
9560
|
const scheduledIds = [];
|
|
9612
|
-
const scheduledBeforeImages = /* @__PURE__ */ new Map();
|
|
9613
9561
|
for (const id of updatedIds) {
|
|
9614
9562
|
const activityId = String(id);
|
|
9615
9563
|
scheduledIds.push(activityId);
|
|
9616
9564
|
const snap = adapter.getActivity(activityId);
|
|
9617
9565
|
if (snap) {
|
|
9618
|
-
scheduledBeforeImages.set(activityId, structuredCloneActivity(snap));
|
|
9619
9566
|
adapter.noteScheduledBefore(activityId, snap);
|
|
9620
9567
|
}
|
|
9621
9568
|
}
|
|
9622
|
-
return { scheduledIds
|
|
9569
|
+
return { scheduledIds };
|
|
9623
9570
|
}
|
|
9624
9571
|
function emptySchedule() {
|
|
9625
|
-
return { scheduledIds: []
|
|
9572
|
+
return { scheduledIds: [] };
|
|
9573
|
+
}
|
|
9574
|
+
async function refreshMutatedParentBounds(adapter, args) {
|
|
9575
|
+
const mutated = args.collectDirty ? args.collectDirty([]) : collectDirtyForStructural(args.recomputeParentsFrom, []);
|
|
9576
|
+
if (mutated.size === 0) return;
|
|
9577
|
+
await updateParentBoundsFromChildren(adapter, mutated, false);
|
|
9626
9578
|
}
|
|
9627
9579
|
async function rollUpParentBounds(adapter, args, scheduledIds, passes) {
|
|
9628
9580
|
const dirty = args.collectDirty ? args.collectDirty(scheduledIds) : collectDirtyForStructural(args.recomputeParentsFrom, scheduledIds);
|
|
@@ -9631,17 +9583,20 @@ async function rollUpParentBounds(adapter, args, scheduledIds, passes) {
|
|
|
9631
9583
|
dirty,
|
|
9632
9584
|
passes.has(DERIVED_PASS.PARENT_PROGRESS),
|
|
9633
9585
|
{
|
|
9634
|
-
recomputeRealWork: passes.has(DERIVED_PASS.REAL_WORK)
|
|
9586
|
+
recomputeRealWork: passes.has(DERIVED_PASS.REAL_WORK),
|
|
9587
|
+
progressMode: args.recomputeParentProgress ? "zero-when-no-contribution" : "freeze-when-no-contribution"
|
|
9635
9588
|
}
|
|
9636
9589
|
);
|
|
9637
9590
|
}
|
|
9638
9591
|
async function runDerivedRecomputes(deps, passes, now) {
|
|
9639
9592
|
if (passes.has(DERIVED_PASS.EXPECTED_PROGRESS) && now !== null) {
|
|
9640
|
-
|
|
9641
|
-
|
|
9642
|
-
|
|
9643
|
-
|
|
9644
|
-
|
|
9593
|
+
if (hasActiveBaseline(deps.adapter)) {
|
|
9594
|
+
runExpectedProgressBase(
|
|
9595
|
+
deps.adapter,
|
|
9596
|
+
now,
|
|
9597
|
+
deps.defaultBaseCalendarId ?? null
|
|
9598
|
+
);
|
|
9599
|
+
}
|
|
9645
9600
|
applyExpectedProgressLive(deps.adapter, now);
|
|
9646
9601
|
applyStatusPass(deps.adapter, deps.sector.statusCriteria);
|
|
9647
9602
|
}
|
|
@@ -9652,6 +9607,13 @@ async function runDerivedRecomputes(deps, passes, now) {
|
|
|
9652
9607
|
await applyCriticalPath(deps.adapter, deps.sector.hoursPerDay);
|
|
9653
9608
|
}
|
|
9654
9609
|
}
|
|
9610
|
+
function hasActiveBaseline(adapter) {
|
|
9611
|
+
let active = false;
|
|
9612
|
+
adapter.forEachActivity((activity) => {
|
|
9613
|
+
if (getActiveBaseline(activity)) active = true;
|
|
9614
|
+
});
|
|
9615
|
+
return active;
|
|
9616
|
+
}
|
|
9655
9617
|
|
|
9656
9618
|
// src/dispatch/handlers/revert-no-op-constraint-edit.ts
|
|
9657
9619
|
var CONSTRAINT_EDIT_COLUMNS = /* @__PURE__ */ new Set([
|
|
@@ -9662,6 +9624,9 @@ var MUST_CONSTRAINTS = /* @__PURE__ */ new Set(["mso", "mfo"]);
|
|
|
9662
9624
|
function isConstraintEditColumn(column) {
|
|
9663
9625
|
return CONSTRAINT_EDIT_COLUMNS.has(column);
|
|
9664
9626
|
}
|
|
9627
|
+
function isExplicitConstraintDateEdit(column) {
|
|
9628
|
+
return column === COLUMN.CONSTRAINT_DATE;
|
|
9629
|
+
}
|
|
9665
9630
|
function revertNoOpConstraintEdit(activityId, priorConstraintDate, adapter, calendars) {
|
|
9666
9631
|
const activity = adapter.getActivity(activityId);
|
|
9667
9632
|
if (!activity) return false;
|
|
@@ -9705,7 +9670,7 @@ function sameDate(first, second) {
|
|
|
9705
9670
|
|
|
9706
9671
|
// src/dispatch/shared/constraint-settle.ts
|
|
9707
9672
|
async function settleConstraintEdits(deps, { postMutationArgs, revertTargets, revert }) {
|
|
9708
|
-
let { scheduledIds
|
|
9673
|
+
let { scheduledIds } = await runPostMutation(
|
|
9709
9674
|
deps,
|
|
9710
9675
|
withCriticalPathSuppressed(postMutationArgs)
|
|
9711
9676
|
);
|
|
@@ -9720,15 +9685,11 @@ async function settleConstraintEdits(deps, { postMutationArgs, revertTargets, re
|
|
|
9720
9685
|
withCriticalPathSuppressed(postMutationArgs)
|
|
9721
9686
|
);
|
|
9722
9687
|
scheduledIds = mergeScheduledIds(scheduledIds, resettled.scheduledIds);
|
|
9723
|
-
scheduledBeforeImages = mergeScheduledBeforeImagesFirstWins(
|
|
9724
|
-
scheduledBeforeImages,
|
|
9725
|
-
resettled.scheduledBeforeImages
|
|
9726
|
-
);
|
|
9727
9688
|
}
|
|
9728
9689
|
if (resolveRunCriticalPath(postMutationArgs.action)) {
|
|
9729
9690
|
await runPostMutation(deps, criticalPathOnlyArgs(postMutationArgs));
|
|
9730
9691
|
}
|
|
9731
|
-
return { scheduledIds
|
|
9692
|
+
return { scheduledIds };
|
|
9732
9693
|
}
|
|
9733
9694
|
function withCriticalPathSuppressed(args) {
|
|
9734
9695
|
return {
|
|
@@ -9750,13 +9711,6 @@ function mergeScheduledIds(firstSettleIds, secondSettleIds) {
|
|
|
9750
9711
|
for (const scheduledId of secondSettleIds) merged.add(scheduledId);
|
|
9751
9712
|
return [...merged];
|
|
9752
9713
|
}
|
|
9753
|
-
function mergeScheduledBeforeImagesFirstWins(firstSettleImages, secondSettleImages) {
|
|
9754
|
-
const merged = new Map(firstSettleImages);
|
|
9755
|
-
for (const [imageId, image] of secondSettleImages) {
|
|
9756
|
-
if (!merged.has(imageId)) merged.set(imageId, image);
|
|
9757
|
-
}
|
|
9758
|
-
return merged;
|
|
9759
|
-
}
|
|
9760
9714
|
|
|
9761
9715
|
// src/dispatch/sir-auto-reject.ts
|
|
9762
9716
|
function datesChanged(before, after) {
|
|
@@ -9791,33 +9745,12 @@ function detectSirAutoReject(beforeSnap, adapter, touchedIds) {
|
|
|
9791
9745
|
|
|
9792
9746
|
// src/dispatch/shared/change-set.ts
|
|
9793
9747
|
function assembleChangeSet(adapter, args) {
|
|
9794
|
-
const allTouched =
|
|
9795
|
-
for (const id of args.touchedIds) allTouched.add(id);
|
|
9796
|
-
for (const id of args.scheduledIds) allTouched.add(id);
|
|
9797
|
-
if (args.includeAllIds) {
|
|
9798
|
-
for (const id of adapter.getAllIds()) allTouched.add(id);
|
|
9799
|
-
}
|
|
9748
|
+
const allTouched = collectChangeSetIds(adapter, args);
|
|
9800
9749
|
const before = new Map(args.beforeSnap);
|
|
9801
9750
|
const captured = adapter.peekWriteCapture();
|
|
9802
9751
|
if (captured) {
|
|
9803
|
-
|
|
9804
|
-
|
|
9805
|
-
const beforeImg = captured.before.get(id);
|
|
9806
|
-
const live = adapter.getActivity(id);
|
|
9807
|
-
if (!beforeImg || !live) continue;
|
|
9808
|
-
if (Object.keys(diffActivity(beforeImg, live)).length === 0) continue;
|
|
9809
|
-
before.set(id, beforeImg);
|
|
9810
|
-
allTouched.add(id);
|
|
9811
|
-
}
|
|
9812
|
-
}
|
|
9813
|
-
if (args.scheduledBeforeImages) {
|
|
9814
|
-
for (const [id, img] of args.scheduledBeforeImages) {
|
|
9815
|
-
const sid = String(id);
|
|
9816
|
-
if (!before.has(sid)) {
|
|
9817
|
-
before.set(sid, img);
|
|
9818
|
-
allTouched.add(sid);
|
|
9819
|
-
}
|
|
9820
|
-
}
|
|
9752
|
+
const insertedIds = collectInsertedIds(captured);
|
|
9753
|
+
mergeDirtyBeforeImages(adapter, captured, insertedIds, before, allTouched);
|
|
9821
9754
|
}
|
|
9822
9755
|
const beforeDiffEffects = args.sirDetection === "before-diff" ? detectSirAutoReject(before, adapter, allTouched) : [];
|
|
9823
9756
|
const activityChanges = buildActivityChanges(adapter, before, allTouched);
|
|
@@ -9834,6 +9767,31 @@ function assembleChangeSet(adapter, args) {
|
|
|
9834
9767
|
...warnings.length > 0 ? { warnings } : {}
|
|
9835
9768
|
};
|
|
9836
9769
|
}
|
|
9770
|
+
function collectChangeSetIds(adapter, args) {
|
|
9771
|
+
const ids = /* @__PURE__ */ new Set();
|
|
9772
|
+
for (const id of args.touchedIds) ids.add(id);
|
|
9773
|
+
for (const id of args.scheduledIds) ids.add(id);
|
|
9774
|
+
if (args.includeAllIds) {
|
|
9775
|
+
for (const id of adapter.getAllIds()) ids.add(id);
|
|
9776
|
+
}
|
|
9777
|
+
return ids;
|
|
9778
|
+
}
|
|
9779
|
+
function mergeDirtyBeforeImages(adapter, captured, insertedIds, before, touched) {
|
|
9780
|
+
for (const id of captured.dirty) {
|
|
9781
|
+
if (insertedIds.has(id) || before.has(id)) continue;
|
|
9782
|
+
const beforeImage = captured.before.get(id);
|
|
9783
|
+
const live = adapter.getActivity(id);
|
|
9784
|
+
if (!beforeImage || !live) continue;
|
|
9785
|
+
if (Object.keys(diffActivity(beforeImage, live)).length === 0) continue;
|
|
9786
|
+
before.set(id, beforeImage);
|
|
9787
|
+
touched.add(id);
|
|
9788
|
+
}
|
|
9789
|
+
}
|
|
9790
|
+
function collectInsertedIds(captured) {
|
|
9791
|
+
return new Set(
|
|
9792
|
+
captured.ops.filter((operation) => operation.kind === "insert").map((operation) => operation.activityId)
|
|
9793
|
+
);
|
|
9794
|
+
}
|
|
9837
9795
|
|
|
9838
9796
|
// src/dispatch/conversion.ts
|
|
9839
9797
|
function snapshotToLink(l) {
|
|
@@ -10016,7 +9974,8 @@ async function dispatchInlineEdit(action, options, deps) {
|
|
|
10016
9974
|
runPostProcessorsOnAdapter(
|
|
10017
9975
|
action.activityId,
|
|
10018
9976
|
changes.postProcessors ?? [],
|
|
10019
|
-
adapter
|
|
9977
|
+
adapter,
|
|
9978
|
+
beforeSnap.get(String(action.activityId)) ?? null
|
|
10020
9979
|
);
|
|
10021
9980
|
const linkChanges = diffIncomingLinkLagChanges(
|
|
10022
9981
|
beforeLinkLags,
|
|
@@ -10041,7 +10000,7 @@ async function dispatchInlineEdit(action, options, deps) {
|
|
|
10041
10000
|
options
|
|
10042
10001
|
});
|
|
10043
10002
|
const isConstraintPath = isConstraintEditColumn(action.column);
|
|
10044
|
-
const { scheduledIds
|
|
10003
|
+
const { scheduledIds } = await (isConstraintPath ? settleConstraintEdits(
|
|
10045
10004
|
{
|
|
10046
10005
|
adapter,
|
|
10047
10006
|
scheduler,
|
|
@@ -10050,9 +10009,7 @@ async function dispatchInlineEdit(action, options, deps) {
|
|
|
10050
10009
|
},
|
|
10051
10010
|
{
|
|
10052
10011
|
postMutationArgs: buildPostMutationArgs(),
|
|
10053
|
-
revertTargets: [
|
|
10054
|
-
{ activityId: action.activityId, priorConstraintDate }
|
|
10055
|
-
],
|
|
10012
|
+
revertTargets: isExplicitConstraintDateEdit(action.column) ? [] : [{ activityId: action.activityId, priorConstraintDate }],
|
|
10056
10013
|
revert: (activityId, capturedConstraintDate) => revertNoOpConstraintEdit(
|
|
10057
10014
|
activityId,
|
|
10058
10015
|
capturedConstraintDate,
|
|
@@ -10084,7 +10041,6 @@ async function dispatchInlineEdit(action, options, deps) {
|
|
|
10084
10041
|
beforeSnap,
|
|
10085
10042
|
touchedIds,
|
|
10086
10043
|
scheduledIds,
|
|
10087
|
-
scheduledBeforeImages,
|
|
10088
10044
|
sirDetection: "before-diff",
|
|
10089
10045
|
links: linkChanges,
|
|
10090
10046
|
trackingEvents,
|
|
@@ -10098,6 +10054,40 @@ function columnInvalidatesExpandedLinks(column) {
|
|
|
10098
10054
|
}
|
|
10099
10055
|
|
|
10100
10056
|
// src/dispatch/handlers/link.ts
|
|
10057
|
+
function collectBatchContext(operations, adapter) {
|
|
10058
|
+
const activityIds = /* @__PURE__ */ new Set();
|
|
10059
|
+
const links = /* @__PURE__ */ new Map();
|
|
10060
|
+
for (const operation of operations) {
|
|
10061
|
+
if (operation.kind === "create") {
|
|
10062
|
+
activityIds.add(String(operation.source));
|
|
10063
|
+
activityIds.add(String(operation.target));
|
|
10064
|
+
continue;
|
|
10065
|
+
}
|
|
10066
|
+
const link = adapter.getLink(operation.linkId);
|
|
10067
|
+
if (!link) continue;
|
|
10068
|
+
activityIds.add(String(link.source));
|
|
10069
|
+
activityIds.add(String(link.target));
|
|
10070
|
+
links.set(operation.linkId, { ...link });
|
|
10071
|
+
}
|
|
10072
|
+
return { activityIds, links };
|
|
10073
|
+
}
|
|
10074
|
+
function applyBatchOperations(operations, adapter, linkIdGen, deterministicIds) {
|
|
10075
|
+
return operations.map((operation, index) => {
|
|
10076
|
+
const deterministicId = operation.kind === "create" ? deterministicIds?.get(index) : void 0;
|
|
10077
|
+
const result = applyLinkOperation(operation, {
|
|
10078
|
+
port: adapter,
|
|
10079
|
+
newLinkId: deterministicId ? () => deterministicId : linkIdGen.next
|
|
10080
|
+
});
|
|
10081
|
+
return {
|
|
10082
|
+
op: operation,
|
|
10083
|
+
finalLinkId: result.applied ? result.linkId : null,
|
|
10084
|
+
rejected: result.applied ? null : result.rejected ?? "link_op_rejected"
|
|
10085
|
+
};
|
|
10086
|
+
});
|
|
10087
|
+
}
|
|
10088
|
+
function stringKeyedLinkSnapshots(links) {
|
|
10089
|
+
return new Map([...links].map(([id, link]) => [String(id), link]));
|
|
10090
|
+
}
|
|
10101
10091
|
async function dispatchLink(action, options, deps) {
|
|
10102
10092
|
if (action.kind === "link-create" || action.kind === "link-update") {
|
|
10103
10093
|
const type = action.type;
|
|
@@ -10155,40 +10145,14 @@ function batchOpToLinkOperation(op, hoursPerDay) {
|
|
|
10155
10145
|
async function dispatchLinkBatch(operations, source, options, deps, deterministicIds) {
|
|
10156
10146
|
const { adapter, scheduler, sector, linkIdGen } = deps;
|
|
10157
10147
|
scheduler.invalidateAllCaches();
|
|
10158
|
-
const affectedActivityIds
|
|
10159
|
-
const beforeLinks = /* @__PURE__ */ new Map();
|
|
10160
|
-
for (const op of operations) {
|
|
10161
|
-
if (op.kind === "create") {
|
|
10162
|
-
affectedActivityIds.add(String(op.source));
|
|
10163
|
-
affectedActivityIds.add(String(op.target));
|
|
10164
|
-
} else {
|
|
10165
|
-
const link = adapter.getLink(op.linkId);
|
|
10166
|
-
if (link) {
|
|
10167
|
-
affectedActivityIds.add(String(link.source));
|
|
10168
|
-
affectedActivityIds.add(String(link.target));
|
|
10169
|
-
beforeLinks.set(op.linkId, { ...link });
|
|
10170
|
-
}
|
|
10171
|
-
}
|
|
10172
|
-
}
|
|
10148
|
+
const { activityIds: affectedActivityIds, links: beforeLinks } = collectBatchContext(operations, adapter);
|
|
10173
10149
|
const beforeActivities = snapshotActivities(adapter, affectedActivityIds);
|
|
10174
|
-
const applied =
|
|
10175
|
-
|
|
10176
|
-
|
|
10177
|
-
|
|
10178
|
-
|
|
10179
|
-
|
|
10180
|
-
// Si el caller pasó un id deterministic (test override, o el bridge
|
|
10181
|
-
// pasando el id que DHTMLX iba a usar), lo respetamos. Si no, el
|
|
10182
|
-
// generador del core arranca desde Date.now() — mismo formato que
|
|
10183
|
-
// DHTMLX uid(). Ver `generators/link-id-generator.ts`.
|
|
10184
|
-
newLinkId: detId ? () => detId : linkIdGen.next
|
|
10185
|
-
});
|
|
10186
|
-
applied.push({
|
|
10187
|
-
op,
|
|
10188
|
-
finalLinkId: result.applied ? result.linkId : null,
|
|
10189
|
-
rejected: result.applied ? null : result.rejected ?? "link_op_rejected"
|
|
10190
|
-
});
|
|
10191
|
-
}
|
|
10150
|
+
const applied = applyBatchOperations(
|
|
10151
|
+
operations,
|
|
10152
|
+
adapter,
|
|
10153
|
+
linkIdGen,
|
|
10154
|
+
deterministicIds
|
|
10155
|
+
);
|
|
10192
10156
|
if (operations.length === 1 && applied[0] && applied[0].rejected !== null && source.kind !== "inline-edit") {
|
|
10193
10157
|
return { ok: false, reason: applied[0].rejected };
|
|
10194
10158
|
}
|
|
@@ -10208,21 +10172,24 @@ async function dispatchLinkBatch(operations, source, options, deps, deterministi
|
|
|
10208
10172
|
options
|
|
10209
10173
|
}
|
|
10210
10174
|
);
|
|
10211
|
-
for (const id of scheduledIds) {
|
|
10212
|
-
if (!beforeActivities.has(id)) {
|
|
10213
|
-
const a = adapter.getActivity(id);
|
|
10214
|
-
if (a) beforeActivities.set(id, structuredCloneActivity(a));
|
|
10215
|
-
}
|
|
10216
|
-
}
|
|
10217
10175
|
const linkChanges = buildLinkChangesForBatch(applied, beforeLinks, adapter);
|
|
10218
|
-
const beforeLinksByStringId = /* @__PURE__ */ new Map();
|
|
10219
|
-
for (const [linkId, snap] of beforeLinks) {
|
|
10220
|
-
beforeLinksByStringId.set(String(linkId), snap);
|
|
10221
|
-
}
|
|
10222
10176
|
return {
|
|
10223
10177
|
ok: true,
|
|
10224
|
-
|
|
10225
|
-
|
|
10178
|
+
linkVerdicts: applied.map(
|
|
10179
|
+
(operation, operationIndex) => operation.rejected === null ? {
|
|
10180
|
+
operationIndex,
|
|
10181
|
+
kind: operation.op.kind,
|
|
10182
|
+
ok: true,
|
|
10183
|
+
linkId: String(operation.finalLinkId)
|
|
10184
|
+
} : {
|
|
10185
|
+
operationIndex,
|
|
10186
|
+
kind: operation.op.kind,
|
|
10187
|
+
ok: false,
|
|
10188
|
+
reason: operation.rejected
|
|
10189
|
+
}
|
|
10190
|
+
),
|
|
10191
|
+
__beforeLinks: stringKeyedLinkSnapshots(beforeLinks),
|
|
10192
|
+
changes: assembleChangeSet(adapter, {
|
|
10226
10193
|
source,
|
|
10227
10194
|
beforeSnap: beforeActivities,
|
|
10228
10195
|
touchedIds: affectedActivityIds,
|
|
@@ -10233,26 +10200,21 @@ async function dispatchLinkBatch(operations, source, options, deps, deterministi
|
|
|
10233
10200
|
};
|
|
10234
10201
|
}
|
|
10235
10202
|
function pickAutoscheduleTrigger(applied, beforeLinks, adapter) {
|
|
10236
|
-
for (const
|
|
10237
|
-
if (
|
|
10238
|
-
|
|
10239
|
-
|
|
10240
|
-
|
|
10241
|
-
if (a.op.kind === "delete") {
|
|
10242
|
-
const snap = beforeLinks.get(a.op.linkId);
|
|
10243
|
-
if (snap) {
|
|
10244
|
-
return adapter.hasChildren(snap.target) ? "roots" : String(snap.target);
|
|
10245
|
-
}
|
|
10246
|
-
}
|
|
10247
|
-
if (a.op.kind === "update") {
|
|
10248
|
-
const link = adapter.getLink(a.op.linkId);
|
|
10249
|
-
if (link) {
|
|
10250
|
-
return adapter.hasChildren(link.target) ? "roots" : String(link.target);
|
|
10251
|
-
}
|
|
10252
|
-
}
|
|
10203
|
+
for (const operation of applied) {
|
|
10204
|
+
if (operation.rejected !== null) continue;
|
|
10205
|
+
const target = autoscheduleTarget(operation.op, beforeLinks, adapter);
|
|
10206
|
+
if (target !== null)
|
|
10207
|
+
return adapter.hasChildren(target) ? "roots" : String(target);
|
|
10253
10208
|
}
|
|
10254
10209
|
return null;
|
|
10255
10210
|
}
|
|
10211
|
+
function autoscheduleTarget(operation, beforeLinks, adapter) {
|
|
10212
|
+
if (operation.kind === "create") return operation.target;
|
|
10213
|
+
if (operation.kind === "delete") {
|
|
10214
|
+
return beforeLinks.get(operation.linkId)?.target ?? null;
|
|
10215
|
+
}
|
|
10216
|
+
return adapter.getLink(operation.linkId)?.target ?? null;
|
|
10217
|
+
}
|
|
10256
10218
|
function toLinkOperation(action, hoursPerDay) {
|
|
10257
10219
|
if (action.kind === "link-create") {
|
|
10258
10220
|
return {
|
|
@@ -10323,6 +10285,128 @@ var DISPATCH_TRACK_EVENT = {
|
|
|
10323
10285
|
ACTIVITY_OUTDENT: "schedule_activity_outdent"
|
|
10324
10286
|
};
|
|
10325
10287
|
|
|
10288
|
+
// src/internal/hierarchy/visual-order.ts
|
|
10289
|
+
var NOT_SET_SORT_VALUE = Number.MAX_SAFE_INTEGER;
|
|
10290
|
+
function getChildrenInVisualOrder(parentId, adapter) {
|
|
10291
|
+
const children = collectChildrenSnapshots(parentId, adapter);
|
|
10292
|
+
children.sort(compareActivitiesInVisualOrder);
|
|
10293
|
+
return children.map((a) => String(a.id));
|
|
10294
|
+
}
|
|
10295
|
+
function iterateInVisualOrder(adapter) {
|
|
10296
|
+
const result = [];
|
|
10297
|
+
const visit = (activity) => {
|
|
10298
|
+
result.push(activity);
|
|
10299
|
+
const childIds = getChildrenInVisualOrder(String(activity.id), adapter);
|
|
10300
|
+
for (const childId of childIds) {
|
|
10301
|
+
const child = adapter.getActivity(childId);
|
|
10302
|
+
if (child) visit(child);
|
|
10303
|
+
}
|
|
10304
|
+
};
|
|
10305
|
+
const rootIds = getChildrenInVisualOrder(ROOT_PARENT_ID, adapter);
|
|
10306
|
+
for (const rootId of rootIds) {
|
|
10307
|
+
const root = adapter.getActivity(rootId);
|
|
10308
|
+
if (root) visit(root);
|
|
10309
|
+
}
|
|
10310
|
+
return result;
|
|
10311
|
+
}
|
|
10312
|
+
function findPreviousNonSelectedSibling(taskId, selected, adapter) {
|
|
10313
|
+
const activity = adapter.getActivity(taskId);
|
|
10314
|
+
if (!activity) return null;
|
|
10315
|
+
const parentKey = parentKeyOf(activity);
|
|
10316
|
+
const siblings = getChildrenInVisualOrder(parentKey, adapter);
|
|
10317
|
+
const idx = siblings.findIndex((id) => String(id) === String(taskId));
|
|
10318
|
+
if (idx <= 0) return null;
|
|
10319
|
+
for (let i = idx - 1; i >= 0; i--) {
|
|
10320
|
+
const candidateId = siblings[i];
|
|
10321
|
+
if (candidateId === void 0) continue;
|
|
10322
|
+
if (!setHas(selected, candidateId)) return candidateId;
|
|
10323
|
+
}
|
|
10324
|
+
return null;
|
|
10325
|
+
}
|
|
10326
|
+
function visualIndexInParent(taskId, adapter) {
|
|
10327
|
+
const activity = adapter.getActivity(taskId);
|
|
10328
|
+
if (!activity) return -1;
|
|
10329
|
+
const parentKey = parentKeyOf(activity);
|
|
10330
|
+
const siblings = getChildrenInVisualOrder(parentKey, adapter);
|
|
10331
|
+
return siblings.findIndex((id) => String(id) === String(taskId));
|
|
10332
|
+
}
|
|
10333
|
+
function collectChildrenSnapshots(parentId, adapter) {
|
|
10334
|
+
const key = String(parentId);
|
|
10335
|
+
if (key === "0") {
|
|
10336
|
+
return adapter.getAllActivities().filter((a) => a.parentId === null);
|
|
10337
|
+
}
|
|
10338
|
+
const childIds = adapter.getChildren(parentId);
|
|
10339
|
+
const out = [];
|
|
10340
|
+
for (const id of childIds) {
|
|
10341
|
+
const snap = adapter.getActivity(id);
|
|
10342
|
+
if (snap) out.push(snap);
|
|
10343
|
+
}
|
|
10344
|
+
return out;
|
|
10345
|
+
}
|
|
10346
|
+
function compareActivitiesInVisualOrder(a, b) {
|
|
10347
|
+
const ac = correlativeIdOf(a);
|
|
10348
|
+
const bc = correlativeIdOf(b);
|
|
10349
|
+
if (ac !== bc) return ac - bc;
|
|
10350
|
+
return String(a.id).localeCompare(String(b.id));
|
|
10351
|
+
}
|
|
10352
|
+
function correlativeIdOf(activity) {
|
|
10353
|
+
const raw = activity.correlativeId;
|
|
10354
|
+
const n = typeof raw === "number" ? raw : Number(raw);
|
|
10355
|
+
return Number.isFinite(n) ? n : NOT_SET_SORT_VALUE;
|
|
10356
|
+
}
|
|
10357
|
+
function parentKeyOf(activity) {
|
|
10358
|
+
const parentId = activity.parentId;
|
|
10359
|
+
if (parentId === null) return "0";
|
|
10360
|
+
return parentId;
|
|
10361
|
+
}
|
|
10362
|
+
function setHas(set, id) {
|
|
10363
|
+
if (set.has(id)) return true;
|
|
10364
|
+
return set.has(String(id));
|
|
10365
|
+
}
|
|
10366
|
+
|
|
10367
|
+
// src/internal/hierarchy/recompute-correlative-ids.ts
|
|
10368
|
+
function recomputeCorrelativeIds(adapter) {
|
|
10369
|
+
adapter.invalidateVisualOrderIds?.();
|
|
10370
|
+
const roots = [];
|
|
10371
|
+
adapter.forEachActivity((activity) => {
|
|
10372
|
+
if (isRootParent(activity.parentId)) roots.push(activity);
|
|
10373
|
+
});
|
|
10374
|
+
roots.sort(byCorrelativeId);
|
|
10375
|
+
const stack = [];
|
|
10376
|
+
pushInReverseOrder(stack, roots);
|
|
10377
|
+
const shifts = [];
|
|
10378
|
+
let counter = 0;
|
|
10379
|
+
while (stack.length > 0) {
|
|
10380
|
+
const activity = stack.pop();
|
|
10381
|
+
if (activity.correlativeId !== counter) {
|
|
10382
|
+
const before = typeof activity.correlativeId === "number" ? activity.correlativeId : void 0;
|
|
10383
|
+
shifts.push({ activityId: String(activity.id), before });
|
|
10384
|
+
if (before !== void 0)
|
|
10385
|
+
adapter.noteCorrelativeBefore?.(String(activity.id), before);
|
|
10386
|
+
setCorrelativeId(activity, counter);
|
|
10387
|
+
}
|
|
10388
|
+
counter += 1;
|
|
10389
|
+
const children = collectChildrenSnapshots(String(activity.id), adapter);
|
|
10390
|
+
children.sort(byCorrelativeId);
|
|
10391
|
+
pushInReverseOrder(stack, children);
|
|
10392
|
+
}
|
|
10393
|
+
return shifts;
|
|
10394
|
+
}
|
|
10395
|
+
function pushInReverseOrder(stack, activities) {
|
|
10396
|
+
for (let i = activities.length - 1; i >= 0; i -= 1) {
|
|
10397
|
+
stack.push(activities[i]);
|
|
10398
|
+
}
|
|
10399
|
+
}
|
|
10400
|
+
function getCorrelativeId(activity) {
|
|
10401
|
+
const raw = activity.correlativeId;
|
|
10402
|
+
const n = typeof raw === "number" ? raw : Number(raw);
|
|
10403
|
+
return Number.isFinite(n) ? n : NOT_SET_SORT_VALUE;
|
|
10404
|
+
}
|
|
10405
|
+
var byCorrelativeId = (a, b) => getCorrelativeId(a) - getCorrelativeId(b);
|
|
10406
|
+
function setCorrelativeId(activity, value) {
|
|
10407
|
+
activity.correlativeId = value;
|
|
10408
|
+
}
|
|
10409
|
+
|
|
10326
10410
|
// src/propagations/upward/recompute-hh-cascade.ts
|
|
10327
10411
|
function recomputeHhCascadeForParent(startParentId, adapter) {
|
|
10328
10412
|
if (!startParentId || startParentId === "0") return;
|
|
@@ -10477,8 +10561,7 @@ var NEW_ACTIVITY_DEFAULTS = Object.freeze({
|
|
|
10477
10561
|
expectedProgress: null,
|
|
10478
10562
|
expectedProgressBaseline: null,
|
|
10479
10563
|
status: null,
|
|
10480
|
-
criticalPath: null
|
|
10481
|
-
promotionRestore: null
|
|
10564
|
+
criticalPath: null
|
|
10482
10565
|
});
|
|
10483
10566
|
var FIRST_ACTIVITY_TEXT = "New Master Plan";
|
|
10484
10567
|
var NEW_ACTIVITY_TEXT = "New Activity";
|
|
@@ -10583,6 +10666,23 @@ function resolveStartDate(parent, fallback, override) {
|
|
|
10583
10666
|
}
|
|
10584
10667
|
|
|
10585
10668
|
// src/creation/parent-mutation-pipeline.ts
|
|
10669
|
+
function snapshotOf(parent) {
|
|
10670
|
+
const type = parent.type;
|
|
10671
|
+
if (type !== "task" && type !== "milestone") return null;
|
|
10672
|
+
const startDate = parent.startDate;
|
|
10673
|
+
const endDate = parent.endDate;
|
|
10674
|
+
if (!(startDate instanceof Date) || !(endDate instanceof Date)) return null;
|
|
10675
|
+
return {
|
|
10676
|
+
type,
|
|
10677
|
+
startDate: new Date(startDate),
|
|
10678
|
+
endDate: new Date(endDate),
|
|
10679
|
+
durationHours: Number(parent.durationHours ?? 0),
|
|
10680
|
+
expectedProgressBaseline: typeof parent.expectedProgressBaseline === "number" ? parent.expectedProgressBaseline : null,
|
|
10681
|
+
constraintType: parent.constraintType ?? null,
|
|
10682
|
+
constraintDate: parent.constraintDate instanceof Date ? new Date(parent.constraintDate) : null,
|
|
10683
|
+
progress: Number(parent.progress ?? 0)
|
|
10684
|
+
};
|
|
10685
|
+
}
|
|
10586
10686
|
function buildParentMutations(input) {
|
|
10587
10687
|
const parent = input.getParent(input.parentId);
|
|
10588
10688
|
if (!parent) return null;
|
|
@@ -10601,14 +10701,18 @@ function buildParentMutations(input) {
|
|
|
10601
10701
|
}
|
|
10602
10702
|
if (wasPromotableLeaf) {
|
|
10603
10703
|
fields.type = PROMOTION_TARGET_TYPE;
|
|
10604
|
-
fields.constraintType = CONSTRAINT_TYPE2.ASAP;
|
|
10605
|
-
fields.constraintDate = null;
|
|
10606
10704
|
if ((input.promotionSource ?? "create") === "create") {
|
|
10705
|
+
fields.constraintType = CONSTRAINT_TYPE2.ASAP;
|
|
10706
|
+
fields.constraintDate = null;
|
|
10607
10707
|
fields.progress = 0;
|
|
10608
10708
|
fields.expectedProgressBaseline = 0;
|
|
10609
10709
|
}
|
|
10610
10710
|
}
|
|
10611
|
-
return {
|
|
10711
|
+
return {
|
|
10712
|
+
parentId: input.parentId,
|
|
10713
|
+
fields,
|
|
10714
|
+
promotionSnapshot: snapshotOf(parent)
|
|
10715
|
+
};
|
|
10612
10716
|
}
|
|
10613
10717
|
function isPromotableLeaf(parent) {
|
|
10614
10718
|
return isPromotableLeafType(parent.type) && (!Array.isArray(parent.newActivityIds) || parent.newActivityIds.length === 0);
|
|
@@ -10834,6 +10938,12 @@ function applyParentMutations(action, newId, parent, adapter, preserveParentCust
|
|
|
10834
10938
|
if (skipCustomIdMutation) continue;
|
|
10835
10939
|
setActivityFieldDynamic(adapter, parentMutations.parentId, key, value);
|
|
10836
10940
|
}
|
|
10941
|
+
if (parentMutations.promotionSnapshot) {
|
|
10942
|
+
adapter.setPromotionSnapshot(
|
|
10943
|
+
parentMutations.parentId,
|
|
10944
|
+
parentMutations.promotionSnapshot
|
|
10945
|
+
);
|
|
10946
|
+
}
|
|
10837
10947
|
}
|
|
10838
10948
|
function recomputeAndFoldCorrelatives(adapter, newId, beforeSnap, initialTouched, opts) {
|
|
10839
10949
|
if (opts.skipCorrelativeRecompute) return;
|
|
@@ -10847,7 +10957,7 @@ function recomputeAndFoldCorrelatives(adapter, newId, beforeSnap, initialTouched
|
|
|
10847
10957
|
initialTouched
|
|
10848
10958
|
);
|
|
10849
10959
|
}
|
|
10850
|
-
function buildCreateChangeSet(adapter, action, coreResult, scheduledIds, hoursPerDay
|
|
10960
|
+
function buildCreateChangeSet(adapter, action, coreResult, scheduledIds, hoursPerDay) {
|
|
10851
10961
|
const { newId, newActivity, beforeSnap, initialTouched } = coreResult;
|
|
10852
10962
|
const trackingEvent = {
|
|
10853
10963
|
name: DISPATCH_TRACK_EVENT.ACTIVITY_CREATION,
|
|
@@ -10860,40 +10970,13 @@ function buildCreateChangeSet(adapter, action, coreResult, scheduledIds, hoursPe
|
|
|
10860
10970
|
if (action.eventSource !== void 0) {
|
|
10861
10971
|
trackingEvent.properties.event_source = action.eventSource;
|
|
10862
10972
|
}
|
|
10863
|
-
const existingScheduledBeforeImages = scheduledBeforeImages ? new Map(
|
|
10864
|
-
[...scheduledBeforeImages].filter(
|
|
10865
|
-
([scheduledId]) => String(scheduledId) !== String(newId)
|
|
10866
|
-
)
|
|
10867
|
-
) : void 0;
|
|
10868
10973
|
return assembleChangeSet(adapter, {
|
|
10869
10974
|
source: action,
|
|
10870
10975
|
beforeSnap,
|
|
10871
10976
|
touchedIds: initialTouched,
|
|
10872
10977
|
scheduledIds,
|
|
10873
|
-
scheduledBeforeImages: existingScheduledBeforeImages,
|
|
10874
10978
|
trackingEvents: [trackingEvent]});
|
|
10875
10979
|
}
|
|
10876
|
-
function createActivitySync(action, deps) {
|
|
10877
|
-
const result = createActivityCore(action, deps);
|
|
10878
|
-
if (!result.ok) {
|
|
10879
|
-
return { ok: false, reason: result.reason };
|
|
10880
|
-
}
|
|
10881
|
-
recomputeParentBoundsSync(deps.adapter, /* @__PURE__ */ new Set([result.newId]));
|
|
10882
|
-
const snapshot = deps.adapter.getActivity(result.newId);
|
|
10883
|
-
if (!snapshot) {
|
|
10884
|
-
throw new Error(
|
|
10885
|
-
`[ScheduleCore] createActivity: new activity ${result.newId} missing after commit`
|
|
10886
|
-
);
|
|
10887
|
-
}
|
|
10888
|
-
const changes = buildCreateChangeSet(
|
|
10889
|
-
deps.adapter,
|
|
10890
|
-
action,
|
|
10891
|
-
result,
|
|
10892
|
-
[],
|
|
10893
|
-
deps.sector.hoursPerDay
|
|
10894
|
-
);
|
|
10895
|
-
return { ok: true, activity: snapshot, changes };
|
|
10896
|
-
}
|
|
10897
10980
|
async function dispatchActivityCreate(action, options, deps) {
|
|
10898
10981
|
const { adapter, scheduler, sector } = deps;
|
|
10899
10982
|
const core = createActivityCore(action, deps);
|
|
@@ -10921,14 +11004,13 @@ async function dispatchActivityCreate(action, options, deps) {
|
|
|
10921
11004
|
} finally {
|
|
10922
11005
|
adapter.setActivityField(newId, "autoScheduling", createdAutoScheduling);
|
|
10923
11006
|
}
|
|
10924
|
-
const { scheduledIds
|
|
11007
|
+
const { scheduledIds } = scheduleOutcome;
|
|
10925
11008
|
const changeset = buildCreateChangeSet(
|
|
10926
11009
|
adapter,
|
|
10927
11010
|
action,
|
|
10928
11011
|
core,
|
|
10929
11012
|
scheduledIds,
|
|
10930
|
-
sector.hoursPerDay
|
|
10931
|
-
scheduledBeforeImages
|
|
11013
|
+
sector.hoursPerDay
|
|
10932
11014
|
);
|
|
10933
11015
|
return { ok: true, changes: changeset };
|
|
10934
11016
|
}
|
|
@@ -11073,7 +11155,7 @@ async function dispatchActivityPaste(action, options, deps) {
|
|
|
11073
11155
|
rejected: res.applied ? null : res.rejected ?? "link_op_rejected"
|
|
11074
11156
|
});
|
|
11075
11157
|
}
|
|
11076
|
-
const { scheduledIds
|
|
11158
|
+
const { scheduledIds } = await runPostMutation(
|
|
11077
11159
|
{
|
|
11078
11160
|
adapter,
|
|
11079
11161
|
scheduler,
|
|
@@ -11100,14 +11182,6 @@ async function dispatchActivityPaste(action, options, deps) {
|
|
|
11100
11182
|
beforeSnap,
|
|
11101
11183
|
touchedIds: touched,
|
|
11102
11184
|
scheduledIds,
|
|
11103
|
-
// Existing rows the autoscheduler moved need a before-image (the global
|
|
11104
|
-
// beforeSnap used to supply it). Pass scheduledBeforeImages but filter out
|
|
11105
|
-
// the pasted rows — their pre-schedule image would flip them to `updated`.
|
|
11106
|
-
scheduledBeforeImages: new Map(
|
|
11107
|
-
[...scheduledBeforeImages].filter(
|
|
11108
|
-
([schedId]) => !createdIdSet.has(String(schedId))
|
|
11109
|
-
)
|
|
11110
|
-
),
|
|
11111
11185
|
links: linkChanges,
|
|
11112
11186
|
hoursPerDay: sector.hoursPerDay
|
|
11113
11187
|
})
|
|
@@ -11242,10 +11316,8 @@ function collectIncidentLinkIds(activityIds, adapter) {
|
|
|
11242
11316
|
}
|
|
11243
11317
|
|
|
11244
11318
|
// src/internal/hierarchy/parent-demotion.ts
|
|
11245
|
-
function restoredPromotionFields(
|
|
11246
|
-
|
|
11247
|
-
if (typeof restore !== "object" || restore === null) return null;
|
|
11248
|
-
if (restore.type !== "task" && restore.type !== "milestone") return null;
|
|
11319
|
+
function restoredPromotionFields(restore) {
|
|
11320
|
+
if (!restore) return null;
|
|
11249
11321
|
return {
|
|
11250
11322
|
type: restore.type,
|
|
11251
11323
|
startDate: new Date(restore.startDate),
|
|
@@ -11254,16 +11326,20 @@ function restoredPromotionFields(parent) {
|
|
|
11254
11326
|
expectedProgressBaseline: restore.expectedProgressBaseline,
|
|
11255
11327
|
constraintType: restore.constraintType,
|
|
11256
11328
|
constraintDate: restore.constraintDate ? new Date(restore.constraintDate) : null,
|
|
11257
|
-
progress: restore.progress
|
|
11258
|
-
promotionRestore: null
|
|
11329
|
+
progress: restore.progress
|
|
11259
11330
|
};
|
|
11260
11331
|
}
|
|
11332
|
+
function canonicalEndDateField(parent, durationHours, computeEndDate) {
|
|
11333
|
+
const startDate = parent.startDate;
|
|
11334
|
+
if (!computeEndDate || !(startDate instanceof Date)) return {};
|
|
11335
|
+
return { endDate: computeEndDate(startDate, durationHours) };
|
|
11336
|
+
}
|
|
11261
11337
|
function buildParentDemotionMutations(input) {
|
|
11262
11338
|
if (input.remainingChildIds.length > 0) return null;
|
|
11263
11339
|
const parent = input.parent;
|
|
11264
11340
|
const canonicalDuration = input.defaultDurationHours;
|
|
11265
11341
|
const hasCanonicalDefaults = Number.isFinite(canonicalDuration);
|
|
11266
|
-
const fields = restoredPromotionFields(
|
|
11342
|
+
const fields = restoredPromotionFields(input.promotionSnapshot) ?? (hasCanonicalDefaults ? {
|
|
11267
11343
|
type: DEMOTION_TARGET_TYPE,
|
|
11268
11344
|
durationHours: canonicalDuration,
|
|
11269
11345
|
progress: 0,
|
|
@@ -11271,7 +11347,11 @@ function buildParentDemotionMutations(input) {
|
|
|
11271
11347
|
constraintType: "asap",
|
|
11272
11348
|
constraintDate: null,
|
|
11273
11349
|
hasNewActivities: false,
|
|
11274
|
-
|
|
11350
|
+
...canonicalEndDateField(
|
|
11351
|
+
parent,
|
|
11352
|
+
canonicalDuration,
|
|
11353
|
+
input.computeEndDate
|
|
11354
|
+
)
|
|
11275
11355
|
} : { type: DEMOTION_TARGET_TYPE });
|
|
11276
11356
|
if (input.idsRemoved && input.idsRemoved.size > 0) {
|
|
11277
11357
|
const existing = Array.isArray(parent.newActivityIds) ? parent.newActivityIds : [];
|
|
@@ -11368,6 +11448,8 @@ async function dispatchActivityDelete(action, options, deps) {
|
|
|
11368
11448
|
parent,
|
|
11369
11449
|
remainingChildIds: remainingChildren.map(String),
|
|
11370
11450
|
defaultDurationHours: sector.hoursPerDay,
|
|
11451
|
+
promotionSnapshot: adapter.getPromotionSnapshot(parentId),
|
|
11452
|
+
computeEndDate: (startDate, durationHours) => adapter.calculateEndDate({ startDate, durationHours, task: parent }),
|
|
11371
11453
|
idsRemoved: toDelete
|
|
11372
11454
|
});
|
|
11373
11455
|
if (!demotion) {
|
|
@@ -11403,7 +11485,7 @@ async function dispatchActivityDelete(action, options, deps) {
|
|
|
11403
11485
|
if (shift.before !== void 0) beforeImage.correlativeId = shift.before;
|
|
11404
11486
|
beforeSnap.set(shift.activityId, beforeImage);
|
|
11405
11487
|
}
|
|
11406
|
-
const { scheduledIds
|
|
11488
|
+
const { scheduledIds } = await runPostMutation(
|
|
11407
11489
|
{
|
|
11408
11490
|
adapter,
|
|
11409
11491
|
scheduler,
|
|
@@ -11440,7 +11522,6 @@ async function dispatchActivityDelete(action, options, deps) {
|
|
|
11440
11522
|
beforeSnap,
|
|
11441
11523
|
touchedIds,
|
|
11442
11524
|
scheduledIds,
|
|
11443
|
-
scheduledBeforeImages,
|
|
11444
11525
|
sirDetection: "after-diff",
|
|
11445
11526
|
links: buildLinkDeletions(beforeLinks),
|
|
11446
11527
|
trackingEvents: [trackingEvent],
|
|
@@ -11612,6 +11693,12 @@ async function dispatchActivityMove(action, options, deps) {
|
|
|
11612
11693
|
for (const [key, value] of Object.entries(promotion.fields)) {
|
|
11613
11694
|
setActivityFieldDynamic(adapter, promotion.parentId, key, value);
|
|
11614
11695
|
}
|
|
11696
|
+
if (promotion.promotionSnapshot) {
|
|
11697
|
+
adapter.setPromotionSnapshot(
|
|
11698
|
+
promotion.parentId,
|
|
11699
|
+
promotion.promotionSnapshot
|
|
11700
|
+
);
|
|
11701
|
+
}
|
|
11615
11702
|
if (promotion.fields.customId === null) {
|
|
11616
11703
|
releaseClearedCustomId(oldNewParentCustomId, deps.customIdTracker);
|
|
11617
11704
|
}
|
|
@@ -11626,6 +11713,12 @@ async function dispatchActivityMove(action, options, deps) {
|
|
|
11626
11713
|
parent: oldParentActivity,
|
|
11627
11714
|
remainingChildIds: remaining.map(String),
|
|
11628
11715
|
defaultDurationHours: sector.hoursPerDay,
|
|
11716
|
+
promotionSnapshot: adapter.getPromotionSnapshot(oldParentKey),
|
|
11717
|
+
computeEndDate: (startDate, durationHours) => adapter.calculateEndDate({
|
|
11718
|
+
startDate,
|
|
11719
|
+
durationHours,
|
|
11720
|
+
task: oldParentActivity
|
|
11721
|
+
}),
|
|
11629
11722
|
idsRemoved: /* @__PURE__ */ new Set([action.activityId])
|
|
11630
11723
|
});
|
|
11631
11724
|
if (demotion) {
|
|
@@ -11665,7 +11758,8 @@ async function dispatchActivityMove(action, options, deps) {
|
|
|
11665
11758
|
if (shift.before !== void 0) beforeImage.correlativeId = shift.before;
|
|
11666
11759
|
beforeSnap.set(shift.activityId, beforeImage);
|
|
11667
11760
|
}
|
|
11668
|
-
const
|
|
11761
|
+
const sourceParentDirtyIds = parentChanged && oldParentKey !== ROOT_PARENT_ID ? adapter.getChildren(oldParentKey).map(String) : [];
|
|
11762
|
+
const { scheduledIds } = await runPostMutation(
|
|
11669
11763
|
{
|
|
11670
11764
|
adapter,
|
|
11671
11765
|
scheduler,
|
|
@@ -11675,9 +11769,14 @@ async function dispatchActivityMove(action, options, deps) {
|
|
|
11675
11769
|
{
|
|
11676
11770
|
action,
|
|
11677
11771
|
autoscheduleFrom: action.activityId,
|
|
11678
|
-
recomputeParentsFrom: [
|
|
11772
|
+
recomputeParentsFrom: [
|
|
11773
|
+
action.activityId,
|
|
11774
|
+
action.parentId,
|
|
11775
|
+
...sourceParentDirtyIds
|
|
11776
|
+
],
|
|
11679
11777
|
now: deps.now,
|
|
11680
|
-
options
|
|
11778
|
+
options,
|
|
11779
|
+
recomputeParentProgress: parentChanged
|
|
11681
11780
|
}
|
|
11682
11781
|
);
|
|
11683
11782
|
const invalidLinkIds = parentChanged ? collectInvalidLinkIdsForCycle([action.activityId], adapter) : [];
|
|
@@ -11701,7 +11800,6 @@ async function dispatchActivityMove(action, options, deps) {
|
|
|
11701
11800
|
beforeSnap,
|
|
11702
11801
|
touchedIds: touched,
|
|
11703
11802
|
scheduledIds,
|
|
11704
|
-
scheduledBeforeImages,
|
|
11705
11803
|
sirDetection: "before-diff",
|
|
11706
11804
|
trackingEvents: [trackingEvent],
|
|
11707
11805
|
hoursPerDay: sector.hoursPerDay
|
|
@@ -11791,6 +11889,12 @@ async function dispatchActivityIndent(action, options, deps) {
|
|
|
11791
11889
|
for (const [key, value] of Object.entries(promotion.fields)) {
|
|
11792
11890
|
setActivityFieldDynamic(adapter, promotion.parentId, key, value);
|
|
11793
11891
|
}
|
|
11892
|
+
if (promotion.promotionSnapshot) {
|
|
11893
|
+
adapter.setPromotionSnapshot(
|
|
11894
|
+
promotion.parentId,
|
|
11895
|
+
promotion.promotionSnapshot
|
|
11896
|
+
);
|
|
11897
|
+
}
|
|
11794
11898
|
if (!wasTrackedAsNewChild) {
|
|
11795
11899
|
adapter.setActivityField(
|
|
11796
11900
|
newParentId,
|
|
@@ -11836,7 +11940,7 @@ async function dispatchActivityIndent(action, options, deps) {
|
|
|
11836
11940
|
if (shift.before !== void 0) beforeImage.correlativeId = shift.before;
|
|
11837
11941
|
beforeSnap.set(shift.activityId, beforeImage);
|
|
11838
11942
|
}
|
|
11839
|
-
const { scheduledIds
|
|
11943
|
+
const { scheduledIds } = await runPostMutation(
|
|
11840
11944
|
{
|
|
11841
11945
|
adapter,
|
|
11842
11946
|
scheduler,
|
|
@@ -11893,12 +11997,21 @@ async function dispatchActivityIndent(action, options, deps) {
|
|
|
11893
11997
|
}
|
|
11894
11998
|
return {
|
|
11895
11999
|
ok: true,
|
|
12000
|
+
activityVerdicts: action.activityIds.map((activityId) => {
|
|
12001
|
+
const failure = failed.find(
|
|
12002
|
+
(entry) => String(entry.activityId) === String(activityId)
|
|
12003
|
+
);
|
|
12004
|
+
return failure ? {
|
|
12005
|
+
activityId: String(activityId),
|
|
12006
|
+
ok: false,
|
|
12007
|
+
reason: failure.reason
|
|
12008
|
+
} : { activityId: String(activityId), ok: true };
|
|
12009
|
+
}),
|
|
11896
12010
|
changes: assembleChangeSet(adapter, {
|
|
11897
12011
|
source: action,
|
|
11898
12012
|
beforeSnap,
|
|
11899
12013
|
touchedIds: touched,
|
|
11900
12014
|
scheduledIds,
|
|
11901
|
-
scheduledBeforeImages,
|
|
11902
12015
|
trackingEvents: [trackingEvent],
|
|
11903
12016
|
hoursPerDay: sector.hoursPerDay
|
|
11904
12017
|
})
|
|
@@ -12020,6 +12133,12 @@ async function dispatchActivityOutdent(action, options, deps) {
|
|
|
12020
12133
|
parent: parentActivity,
|
|
12021
12134
|
remainingChildIds: remaining.map(String),
|
|
12022
12135
|
defaultDurationHours: sector.hoursPerDay,
|
|
12136
|
+
promotionSnapshot: adapter.getPromotionSnapshot(oldParentKey),
|
|
12137
|
+
computeEndDate: (startDate, durationHours) => adapter.calculateEndDate({
|
|
12138
|
+
startDate,
|
|
12139
|
+
durationHours,
|
|
12140
|
+
task: parentActivity
|
|
12141
|
+
}),
|
|
12023
12142
|
idsRemoved: new Set(
|
|
12024
12143
|
planned.filter((plan) => plan.oldParentKey === oldParentKey).map((plan) => plan.activityId)
|
|
12025
12144
|
)
|
|
@@ -12065,7 +12184,7 @@ async function dispatchActivityOutdent(action, options, deps) {
|
|
|
12065
12184
|
if (shift.before !== void 0) beforeImage.correlativeId = shift.before;
|
|
12066
12185
|
beforeSnap.set(shift.activityId, beforeImage);
|
|
12067
12186
|
}
|
|
12068
|
-
const { scheduledIds
|
|
12187
|
+
const { scheduledIds } = await runPostMutation(
|
|
12069
12188
|
{
|
|
12070
12189
|
adapter,
|
|
12071
12190
|
scheduler,
|
|
@@ -12098,12 +12217,21 @@ async function dispatchActivityOutdent(action, options, deps) {
|
|
|
12098
12217
|
}
|
|
12099
12218
|
return {
|
|
12100
12219
|
ok: true,
|
|
12220
|
+
activityVerdicts: action.activityIds.map((activityId) => {
|
|
12221
|
+
const failure = failed.find(
|
|
12222
|
+
(entry) => String(entry.activityId) === String(activityId)
|
|
12223
|
+
);
|
|
12224
|
+
return failure ? {
|
|
12225
|
+
activityId: String(activityId),
|
|
12226
|
+
ok: false,
|
|
12227
|
+
reason: failure.reason
|
|
12228
|
+
} : { activityId: String(activityId), ok: true };
|
|
12229
|
+
}),
|
|
12101
12230
|
changes: assembleChangeSet(adapter, {
|
|
12102
12231
|
source: action,
|
|
12103
12232
|
beforeSnap,
|
|
12104
12233
|
touchedIds: touched,
|
|
12105
12234
|
scheduledIds,
|
|
12106
|
-
scheduledBeforeImages,
|
|
12107
12235
|
trackingEvents: [trackingEvent],
|
|
12108
12236
|
hoursPerDay: sector.hoursPerDay
|
|
12109
12237
|
})
|
|
@@ -12195,11 +12323,15 @@ async function dispatchDatesBatch(action, options, deps) {
|
|
|
12195
12323
|
mergeBeforeSnapshots(beforeSnap, editTouched, deps);
|
|
12196
12324
|
for (const id of editTouched) touchedIds.add(id);
|
|
12197
12325
|
const beforeLinkLags = snapshotIncomingLinkLags(adapter, edit.activityId);
|
|
12326
|
+
const preEditSnapshot = snapshotActivities(adapter, /* @__PURE__ */ new Set([String(edit.activityId)])).get(
|
|
12327
|
+
String(edit.activityId)
|
|
12328
|
+
) ?? null;
|
|
12198
12329
|
applyFieldChanges(adapter, edit.activityId, outcome.changes);
|
|
12199
12330
|
runPostProcessorsOnAdapter(
|
|
12200
12331
|
edit.activityId,
|
|
12201
12332
|
outcome.changes.postProcessors ?? [],
|
|
12202
|
-
adapter
|
|
12333
|
+
adapter,
|
|
12334
|
+
preEditSnapshot
|
|
12203
12335
|
);
|
|
12204
12336
|
linkChanges.push(
|
|
12205
12337
|
...diffIncomingLinkLagChanges(beforeLinkLags, adapter, edit.activityId)
|
|
@@ -12334,6 +12466,7 @@ async function dispatchBulkEdit(action, options, deps) {
|
|
|
12334
12466
|
const verdicts = [];
|
|
12335
12467
|
const beforeSnap = /* @__PURE__ */ new Map();
|
|
12336
12468
|
const constraintPriorsByActivity = /* @__PURE__ */ new Map();
|
|
12469
|
+
const explicitDateEditActivities = /* @__PURE__ */ new Set();
|
|
12337
12470
|
const touchedIds = /* @__PURE__ */ new Set();
|
|
12338
12471
|
const trackingEvents = [];
|
|
12339
12472
|
const linkChanges = [];
|
|
@@ -12352,14 +12485,21 @@ async function dispatchBulkEdit(action, options, deps) {
|
|
|
12352
12485
|
mergeBeforeSnapshots2(beforeSnap, editTouched, deps);
|
|
12353
12486
|
for (const touchedId of editTouched) touchedIds.add(touchedId);
|
|
12354
12487
|
recordConstraintPrior(constraintPriorsByActivity, edit, beforeSnap);
|
|
12488
|
+
if (isExplicitConstraintDateEdit(edit.column)) {
|
|
12489
|
+
explicitDateEditActivities.add(String(edit.activityId));
|
|
12490
|
+
}
|
|
12355
12491
|
const beforeLinkLags = snapshotIncomingLinkLags(adapter, edit.activityId);
|
|
12492
|
+
const preEditSnapshot = snapshotActivities(adapter, /* @__PURE__ */ new Set([String(edit.activityId)])).get(
|
|
12493
|
+
String(edit.activityId)
|
|
12494
|
+
) ?? null;
|
|
12356
12495
|
const customIdBeforeApply = readLiveCustomId(edit, deps);
|
|
12357
12496
|
const changes = outcome.changes;
|
|
12358
12497
|
applyFieldChanges(adapter, edit.activityId, changes);
|
|
12359
12498
|
runPostProcessorsOnAdapter(
|
|
12360
12499
|
edit.activityId,
|
|
12361
12500
|
outcome.changes.postProcessors ?? [],
|
|
12362
|
-
adapter
|
|
12501
|
+
adapter,
|
|
12502
|
+
preEditSnapshot
|
|
12363
12503
|
);
|
|
12364
12504
|
syncCustomIdTracker(edit, customIdBeforeApply, deps);
|
|
12365
12505
|
linkChanges.push(
|
|
@@ -12381,7 +12521,7 @@ async function dispatchBulkEdit(action, options, deps) {
|
|
|
12381
12521
|
options
|
|
12382
12522
|
};
|
|
12383
12523
|
const batchHasConstraintEdits = constraintPriorsByActivity.size > 0;
|
|
12384
|
-
const { scheduledIds
|
|
12524
|
+
const { scheduledIds } = await (batchHasConstraintEdits ? settleConstraintEdits(
|
|
12385
12525
|
{
|
|
12386
12526
|
adapter,
|
|
12387
12527
|
scheduler,
|
|
@@ -12390,12 +12530,12 @@ async function dispatchBulkEdit(action, options, deps) {
|
|
|
12390
12530
|
},
|
|
12391
12531
|
{
|
|
12392
12532
|
postMutationArgs,
|
|
12393
|
-
revertTargets: [...constraintPriorsByActivity].
|
|
12394
|
-
([activityId
|
|
12395
|
-
|
|
12396
|
-
|
|
12397
|
-
|
|
12398
|
-
),
|
|
12533
|
+
revertTargets: [...constraintPriorsByActivity].filter(
|
|
12534
|
+
([activityId]) => !explicitDateEditActivities.has(activityId)
|
|
12535
|
+
).map(([activityId, priorConstraintDate]) => ({
|
|
12536
|
+
activityId,
|
|
12537
|
+
priorConstraintDate
|
|
12538
|
+
})),
|
|
12399
12539
|
revert: (activityId, priorConstraintDate) => revertNoOpConstraintEdit(
|
|
12400
12540
|
activityId,
|
|
12401
12541
|
priorConstraintDate,
|
|
@@ -12423,7 +12563,6 @@ async function dispatchBulkEdit(action, options, deps) {
|
|
|
12423
12563
|
// Los dependientes que mueve el autoscheduler no están en beforeSnap;
|
|
12424
12564
|
// sin su before-image el diff los marca FALSE-CREATED y el undo los
|
|
12425
12565
|
// borra (fix 4bbccbc de inline-edit).
|
|
12426
|
-
scheduledBeforeImages,
|
|
12427
12566
|
sirDetection: "before-diff",
|
|
12428
12567
|
links: linkChanges,
|
|
12429
12568
|
trackingEvents,
|
|
@@ -12558,8 +12697,515 @@ function mergeBeforeSnapshots2(beforeSnap, ids, deps) {
|
|
|
12558
12697
|
}
|
|
12559
12698
|
}
|
|
12560
12699
|
|
|
12700
|
+
// src/dispatch/handlers/persistence-acknowledge.ts
|
|
12701
|
+
function assertValidAssignment(assignment, entityName, readCurrent, ownerByBackendId, seenIds, seenBackendIds) {
|
|
12702
|
+
const id = String(assignment.id);
|
|
12703
|
+
if (id.length === 0 || seenIds.has(id)) {
|
|
12704
|
+
throw new Error(
|
|
12705
|
+
`persistence-acknowledge: duplicate or empty ${entityName} id "${id}"`
|
|
12706
|
+
);
|
|
12707
|
+
}
|
|
12708
|
+
if (!Number.isSafeInteger(assignment.proplannerId) || assignment.proplannerId <= 0) {
|
|
12709
|
+
throw new Error(
|
|
12710
|
+
`persistence-acknowledge: invalid ${entityName} proplannerId ${String(assignment.proplannerId)}`
|
|
12711
|
+
);
|
|
12712
|
+
}
|
|
12713
|
+
if (seenBackendIds.has(assignment.proplannerId)) {
|
|
12714
|
+
throw new Error(
|
|
12715
|
+
`persistence-acknowledge: duplicate ${entityName} proplannerId ${String(assignment.proplannerId)}`
|
|
12716
|
+
);
|
|
12717
|
+
}
|
|
12718
|
+
const state = readCurrent(id);
|
|
12719
|
+
if (!state.exists) {
|
|
12720
|
+
throw new Error(
|
|
12721
|
+
`persistence-acknowledge: unknown ${entityName} id "${id}"`
|
|
12722
|
+
);
|
|
12723
|
+
}
|
|
12724
|
+
if (state.current !== null && state.current !== assignment.proplannerId) {
|
|
12725
|
+
throw new Error(
|
|
12726
|
+
`persistence-acknowledge: ${entityName} "${id}" already has proplannerId ${String(state.current)}`
|
|
12727
|
+
);
|
|
12728
|
+
}
|
|
12729
|
+
const existingOwner = ownerByBackendId.get(assignment.proplannerId);
|
|
12730
|
+
if (existingOwner !== void 0 && existingOwner !== id) {
|
|
12731
|
+
throw new Error(
|
|
12732
|
+
`persistence-acknowledge: ${entityName} proplannerId ${String(assignment.proplannerId)} already belongs to "${existingOwner}"`
|
|
12733
|
+
);
|
|
12734
|
+
}
|
|
12735
|
+
seenIds.add(id);
|
|
12736
|
+
seenBackendIds.add(assignment.proplannerId);
|
|
12737
|
+
}
|
|
12738
|
+
function assertValidAssignments(assignments, entityName, readCurrent, ownerByBackendId) {
|
|
12739
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
12740
|
+
const seenBackendIds = /* @__PURE__ */ new Set();
|
|
12741
|
+
for (const assignment of assignments) {
|
|
12742
|
+
assertValidAssignment(
|
|
12743
|
+
assignment,
|
|
12744
|
+
entityName,
|
|
12745
|
+
readCurrent,
|
|
12746
|
+
ownerByBackendId,
|
|
12747
|
+
seenIds,
|
|
12748
|
+
seenBackendIds
|
|
12749
|
+
);
|
|
12750
|
+
}
|
|
12751
|
+
}
|
|
12752
|
+
function dispatchPersistenceAcknowledge(action, deps) {
|
|
12753
|
+
const activities = action.activities ?? [];
|
|
12754
|
+
const links = action.links ?? [];
|
|
12755
|
+
const activityOwnerByBackendId = /* @__PURE__ */ new Map();
|
|
12756
|
+
for (const activity of deps.adapter.getAllActivities()) {
|
|
12757
|
+
if (activity.proplannerId != null) {
|
|
12758
|
+
activityOwnerByBackendId.set(activity.proplannerId, String(activity.id));
|
|
12759
|
+
}
|
|
12760
|
+
}
|
|
12761
|
+
const linkOwnerByBackendId = /* @__PURE__ */ new Map();
|
|
12762
|
+
for (const link of deps.adapter.getAllLinks()) {
|
|
12763
|
+
if (link.proplannerId != null) {
|
|
12764
|
+
linkOwnerByBackendId.set(link.proplannerId, String(link.id));
|
|
12765
|
+
}
|
|
12766
|
+
}
|
|
12767
|
+
assertValidAssignments(
|
|
12768
|
+
activities,
|
|
12769
|
+
"activity",
|
|
12770
|
+
(id) => {
|
|
12771
|
+
const activity = deps.adapter.getActivity(id);
|
|
12772
|
+
return {
|
|
12773
|
+
exists: activity !== null,
|
|
12774
|
+
current: activity?.proplannerId ?? null
|
|
12775
|
+
};
|
|
12776
|
+
},
|
|
12777
|
+
activityOwnerByBackendId
|
|
12778
|
+
);
|
|
12779
|
+
assertValidAssignments(
|
|
12780
|
+
links,
|
|
12781
|
+
"link",
|
|
12782
|
+
(id) => {
|
|
12783
|
+
const link = deps.adapter.getLink(id);
|
|
12784
|
+
return { exists: link !== null, current: link?.proplannerId ?? null };
|
|
12785
|
+
},
|
|
12786
|
+
linkOwnerByBackendId
|
|
12787
|
+
);
|
|
12788
|
+
const activityChanges = [];
|
|
12789
|
+
const linkChanges = [];
|
|
12790
|
+
deps.adapter.batchUpdate(() => {
|
|
12791
|
+
for (const assignment of activities) {
|
|
12792
|
+
const before = deps.adapter.getActivity(assignment.id);
|
|
12793
|
+
if (!before || before.proplannerId === assignment.proplannerId) continue;
|
|
12794
|
+
deps.adapter.setActivityField(
|
|
12795
|
+
assignment.id,
|
|
12796
|
+
"proplannerId",
|
|
12797
|
+
assignment.proplannerId
|
|
12798
|
+
);
|
|
12799
|
+
activityChanges.push({
|
|
12800
|
+
id: assignment.id,
|
|
12801
|
+
kind: "updated",
|
|
12802
|
+
fields: {
|
|
12803
|
+
proplannerId: {
|
|
12804
|
+
before: before.proplannerId,
|
|
12805
|
+
after: assignment.proplannerId
|
|
12806
|
+
}
|
|
12807
|
+
},
|
|
12808
|
+
after: { ...before, proplannerId: assignment.proplannerId }
|
|
12809
|
+
});
|
|
12810
|
+
}
|
|
12811
|
+
for (const assignment of links) {
|
|
12812
|
+
const before = deps.adapter.getLink(assignment.id);
|
|
12813
|
+
if (!before || before.proplannerId === assignment.proplannerId) continue;
|
|
12814
|
+
deps.adapter.setLinkProplannerId(assignment.id, assignment.proplannerId);
|
|
12815
|
+
linkChanges.push({
|
|
12816
|
+
id: assignment.id,
|
|
12817
|
+
kind: "updated",
|
|
12818
|
+
fields: {
|
|
12819
|
+
proplannerId: {
|
|
12820
|
+
before: before.proplannerId,
|
|
12821
|
+
after: assignment.proplannerId
|
|
12822
|
+
}
|
|
12823
|
+
},
|
|
12824
|
+
after: { ...before, proplannerId: assignment.proplannerId }
|
|
12825
|
+
});
|
|
12826
|
+
}
|
|
12827
|
+
});
|
|
12828
|
+
return {
|
|
12829
|
+
ok: true,
|
|
12830
|
+
changes: {
|
|
12831
|
+
source: action,
|
|
12832
|
+
activities: activityChanges,
|
|
12833
|
+
links: linkChanges,
|
|
12834
|
+
calendars: [],
|
|
12835
|
+
trackingEvents: []
|
|
12836
|
+
}
|
|
12837
|
+
};
|
|
12838
|
+
}
|
|
12839
|
+
|
|
12840
|
+
// src/baselines/normalize-baseline-point.ts
|
|
12841
|
+
function parseBaselineDate(value) {
|
|
12842
|
+
return typeof value === "string" && value.length > 0 ? parseBackendDate(value) : value instanceof Date ? value : null;
|
|
12843
|
+
}
|
|
12844
|
+
function parseFiniteNonNegative(value) {
|
|
12845
|
+
const numeric = typeof value === "number" ? value : typeof value === "string" && value.trim() !== "" ? Number(value) : Number.NaN;
|
|
12846
|
+
if (!Number.isFinite(numeric) || numeric < 0) return null;
|
|
12847
|
+
return numeric;
|
|
12848
|
+
}
|
|
12849
|
+
function normalizeBaselinePoint(point, reporter) {
|
|
12850
|
+
const durationDays = parseFiniteNonNegative(point.duration);
|
|
12851
|
+
const cost = parseFiniteNonNegative(point.cost);
|
|
12852
|
+
const workHours = parseFiniteNonNegative(point.hh_work);
|
|
12853
|
+
if (durationDays === null || cost === null || workHours === null) {
|
|
12854
|
+
reporter.warn(
|
|
12855
|
+
`[baseline] dropping point with non-finite/negative magnitude \u2014 duration=${JSON.stringify(point.duration)}, cost=${JSON.stringify(point.cost)}, hh_work=${JSON.stringify(point.hh_work)}`
|
|
12856
|
+
);
|
|
12857
|
+
return null;
|
|
12858
|
+
}
|
|
12859
|
+
return {
|
|
12860
|
+
startDate: parseBaselineDate(point.start_date),
|
|
12861
|
+
endDate: parseBaselineDate(point.end_date),
|
|
12862
|
+
durationDays,
|
|
12863
|
+
cost,
|
|
12864
|
+
workHours,
|
|
12865
|
+
versionId: typeof point.sectorbaselineversionId === "number" ? point.sectorbaselineversionId : null,
|
|
12866
|
+
isActiveVersion: Boolean(point.sectorbaselineversion?.active),
|
|
12867
|
+
isVisibleVersion: Boolean(point.sectorbaselineversion?.visible),
|
|
12868
|
+
baseCalendarId: point.baseCalendarId != null ? String(point.baseCalendarId) : null,
|
|
12869
|
+
hoursPerDay: typeof point.hoursPerDay === "number" ? point.hoursPerDay : null,
|
|
12870
|
+
hoursPerWeek: typeof point.hoursPerWeek === "number" ? point.hoursPerWeek : null
|
|
12871
|
+
};
|
|
12872
|
+
}
|
|
12873
|
+
|
|
12874
|
+
// src/baselines/apply-baseline-points.ts
|
|
12875
|
+
function applyBaselinePoints(adapter, points, reporter) {
|
|
12876
|
+
const idByProplanner = /* @__PURE__ */ new Map();
|
|
12877
|
+
adapter.forEachActivity((a, id) => {
|
|
12878
|
+
const pid = a.proplannerId;
|
|
12879
|
+
if (typeof pid === "number") idByProplanner.set(pid, id);
|
|
12880
|
+
});
|
|
12881
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
12882
|
+
for (const p of points) {
|
|
12883
|
+
const activityId = p.activityId;
|
|
12884
|
+
if (typeof activityId !== "number") continue;
|
|
12885
|
+
const coreId = idByProplanner.get(activityId);
|
|
12886
|
+
if (coreId === void 0) continue;
|
|
12887
|
+
const arr = grouped.get(coreId);
|
|
12888
|
+
if (arr) arr.push(p);
|
|
12889
|
+
else grouped.set(coreId, [p]);
|
|
12890
|
+
}
|
|
12891
|
+
const changed = [];
|
|
12892
|
+
for (const [coreId, group] of grouped) {
|
|
12893
|
+
adapter.setActivityField(
|
|
12894
|
+
coreId,
|
|
12895
|
+
"baselinePoints",
|
|
12896
|
+
group.map((point) => normalizeBaselinePoint(point, reporter)).filter((point) => point !== null)
|
|
12897
|
+
);
|
|
12898
|
+
changed.push(coreId);
|
|
12899
|
+
}
|
|
12900
|
+
adapter.forEachActivity((a, id) => {
|
|
12901
|
+
if (grouped.has(id)) return;
|
|
12902
|
+
const existing = a.baselinePoints;
|
|
12903
|
+
if (Array.isArray(existing) && existing.length > 0) {
|
|
12904
|
+
adapter.setActivityField(id, "baselinePoints", []);
|
|
12905
|
+
changed.push(id);
|
|
12906
|
+
}
|
|
12907
|
+
});
|
|
12908
|
+
return changed;
|
|
12909
|
+
}
|
|
12910
|
+
|
|
12911
|
+
// src/baselines/baseline-snapshot.ts
|
|
12912
|
+
function buildBaselineSnapshot(activity) {
|
|
12913
|
+
const active = getActiveBaseline(activity);
|
|
12914
|
+
if (!active) return null;
|
|
12915
|
+
return {
|
|
12916
|
+
startDate: active.startDate,
|
|
12917
|
+
endDate: active.endDate,
|
|
12918
|
+
durationDays: active.durationDays,
|
|
12919
|
+
cost: active.cost,
|
|
12920
|
+
workHours: active.workHours
|
|
12921
|
+
};
|
|
12922
|
+
}
|
|
12923
|
+
function emitBaselineSnapshotColumns(state) {
|
|
12924
|
+
const changed = [];
|
|
12925
|
+
state.forEachActivity((activity, id) => {
|
|
12926
|
+
const snapshot = buildBaselineSnapshot(activity);
|
|
12927
|
+
if (!snapshot) {
|
|
12928
|
+
if (activity.baselineSnapshot !== null) {
|
|
12929
|
+
state.setActivityField(id, "baselineSnapshot", null);
|
|
12930
|
+
changed.push(id);
|
|
12931
|
+
}
|
|
12932
|
+
return;
|
|
12933
|
+
}
|
|
12934
|
+
state.setActivityField(id, "baselineSnapshot", snapshot);
|
|
12935
|
+
changed.push(id);
|
|
12936
|
+
});
|
|
12937
|
+
return changed;
|
|
12938
|
+
}
|
|
12939
|
+
|
|
12940
|
+
// src/baselines/apply-baseline-overlay.ts
|
|
12941
|
+
function applyBaselineOverlay(state, points, now, reporter, defaultBaseCalendarId = null) {
|
|
12942
|
+
const changed = /* @__PURE__ */ new Set();
|
|
12943
|
+
for (const id of applyBaselinePoints(
|
|
12944
|
+
state,
|
|
12945
|
+
points,
|
|
12946
|
+
reporter
|
|
12947
|
+
)) {
|
|
12948
|
+
changed.add(id);
|
|
12949
|
+
}
|
|
12950
|
+
if (now) {
|
|
12951
|
+
for (const id of runExpectedProgressBase(state, now, defaultBaseCalendarId))
|
|
12952
|
+
changed.add(id);
|
|
12953
|
+
}
|
|
12954
|
+
for (const id of emitBaselineSnapshotColumns(state)) changed.add(id);
|
|
12955
|
+
for (const id of emitRealCost(state)) changed.add(id);
|
|
12956
|
+
return [...changed];
|
|
12957
|
+
}
|
|
12958
|
+
|
|
12959
|
+
// src/propagations/downward/recompute-ponderator-for-parent.ts
|
|
12960
|
+
function recomputePonderatorsForParent(parentId, criterion, adapter) {
|
|
12961
|
+
if (!parentId || parentId === "0") return;
|
|
12962
|
+
const childIds = adapter.getChildren(parentId);
|
|
12963
|
+
if (childIds.length === 0) return;
|
|
12964
|
+
const pesoById = /* @__PURE__ */ new Map();
|
|
12965
|
+
let denominator = 0;
|
|
12966
|
+
for (const childId of childIds) {
|
|
12967
|
+
const peso = criterionValue(String(childId), criterion, adapter);
|
|
12968
|
+
pesoById.set(String(childId), peso);
|
|
12969
|
+
denominator += peso;
|
|
12970
|
+
}
|
|
12971
|
+
const relationValue = denominator ? 100 / denominator : 0;
|
|
12972
|
+
for (const childId of childIds) {
|
|
12973
|
+
const child = adapter.getActivity(childId);
|
|
12974
|
+
if (!child) continue;
|
|
12975
|
+
const points = child.baselinePoints;
|
|
12976
|
+
const active = getActiveBaseline(child);
|
|
12977
|
+
if (active) {
|
|
12978
|
+
const peso = pesoById.get(String(childId)) ?? 0;
|
|
12979
|
+
adapter.setActivityField(
|
|
12980
|
+
childId,
|
|
12981
|
+
COLUMN.PONDERATOR,
|
|
12982
|
+
relationValue * peso
|
|
12983
|
+
);
|
|
12984
|
+
} else if (!Array.isArray(points) || points.length === 0) {
|
|
12985
|
+
adapter.setActivityField(childId, COLUMN.PONDERATOR, 0);
|
|
12986
|
+
}
|
|
12987
|
+
}
|
|
12988
|
+
}
|
|
12989
|
+
function criterionValue(childId, criterion, adapter) {
|
|
12990
|
+
const child = adapter.getActivity(childId);
|
|
12991
|
+
if (!child) return 0;
|
|
12992
|
+
const active = getActiveBaseline(child);
|
|
12993
|
+
if (!active) return 0;
|
|
12994
|
+
if (criterion === "COST") return toNumber(active.cost);
|
|
12995
|
+
if (criterion === "HH") return toNumber(active.workHours);
|
|
12996
|
+
const type = child.type;
|
|
12997
|
+
if (type === "project")
|
|
12998
|
+
return sumRecursiveBaselineDurationDays(childId, adapter);
|
|
12999
|
+
if (type === "milestone") return 0;
|
|
13000
|
+
return toNumber(active.durationDays);
|
|
13001
|
+
}
|
|
13002
|
+
function sumRecursiveBaselineDurationDays(activityId, adapter) {
|
|
13003
|
+
let sum = 0;
|
|
13004
|
+
for (const childId of adapter.getChildren(activityId)) {
|
|
13005
|
+
const child = adapter.getActivity(childId);
|
|
13006
|
+
if (!child) continue;
|
|
13007
|
+
const active = getActiveBaseline(child);
|
|
13008
|
+
if (!active) continue;
|
|
13009
|
+
const type = child.type;
|
|
13010
|
+
if (type === "project") {
|
|
13011
|
+
sum += sumRecursiveBaselineDurationDays(String(childId), adapter);
|
|
13012
|
+
} else if (type !== "milestone") {
|
|
13013
|
+
sum += toNumber(active.durationDays);
|
|
13014
|
+
}
|
|
13015
|
+
}
|
|
13016
|
+
return sum;
|
|
13017
|
+
}
|
|
13018
|
+
function toNumber(v) {
|
|
13019
|
+
const n = typeof v === "string" ? parseFloat(v) : v;
|
|
13020
|
+
return typeof n === "number" && Number.isFinite(n) ? n : 0;
|
|
13021
|
+
}
|
|
13022
|
+
|
|
13023
|
+
// src/propagations/downward/recompute-all-ponderators.ts
|
|
13024
|
+
function recomputeAllPonderators(criterion, adapter) {
|
|
13025
|
+
adapter.forEachActivity((_a, id) => {
|
|
13026
|
+
adapter.setActivityField(id, COLUMN.PONDERATOR, 0);
|
|
13027
|
+
});
|
|
13028
|
+
adapter.forEachActivity((_a, id) => {
|
|
13029
|
+
if (adapter.getChildren(id).length > 0) {
|
|
13030
|
+
recomputePonderatorsForParent(String(id), criterion, adapter);
|
|
13031
|
+
}
|
|
13032
|
+
});
|
|
13033
|
+
}
|
|
13034
|
+
|
|
13035
|
+
// src/propagations/upward/progress-rollup.ts
|
|
13036
|
+
function recomputeAllProgressRollup(adapter) {
|
|
13037
|
+
for (const parentId of parentsDeepestFirst(adapter)) {
|
|
13038
|
+
rollupParent(parentId, adapter);
|
|
13039
|
+
}
|
|
13040
|
+
}
|
|
13041
|
+
function parentsDeepestFirst(adapter) {
|
|
13042
|
+
const parents = /* @__PURE__ */ new Set();
|
|
13043
|
+
adapter.forEachActivity((_activity, id) => {
|
|
13044
|
+
if (adapter.getChildren(id).length > 0) parents.add(id);
|
|
13045
|
+
});
|
|
13046
|
+
const depthById = /* @__PURE__ */ new Map();
|
|
13047
|
+
for (const id of parents) depthById.set(id, depthOf2(id, adapter));
|
|
13048
|
+
return [...parents].sort(
|
|
13049
|
+
(a, b) => (depthById.get(b) ?? 0) - (depthById.get(a) ?? 0)
|
|
13050
|
+
);
|
|
13051
|
+
}
|
|
13052
|
+
function depthOf2(id, adapter) {
|
|
13053
|
+
let depth = 0;
|
|
13054
|
+
let current = id;
|
|
13055
|
+
while (current && current !== "0") {
|
|
13056
|
+
if (!adapter.getActivity(current)) break;
|
|
13057
|
+
depth += 1;
|
|
13058
|
+
current = adapter.getParentId(current);
|
|
13059
|
+
}
|
|
13060
|
+
return depth;
|
|
13061
|
+
}
|
|
13062
|
+
function rollupParent(parentId, adapter) {
|
|
13063
|
+
const childIds = adapter.getChildren(parentId);
|
|
13064
|
+
if (childIds.length === 0) return;
|
|
13065
|
+
const children = [];
|
|
13066
|
+
for (const childId of childIds) {
|
|
13067
|
+
const child = adapter.getActivity(childId);
|
|
13068
|
+
if (!child) continue;
|
|
13069
|
+
children.push({
|
|
13070
|
+
progress: Number(child.progress ?? 0),
|
|
13071
|
+
ponderator: Number(child.ponderator ?? 0)
|
|
13072
|
+
});
|
|
13073
|
+
}
|
|
13074
|
+
const rollup = computeWeightedProgressRollup(children);
|
|
13075
|
+
if (rollup !== null) {
|
|
13076
|
+
adapter.setActivityField(
|
|
13077
|
+
parentId,
|
|
13078
|
+
COLUMN.PROGRESS,
|
|
13079
|
+
roundProgressPerLevel(rollup)
|
|
13080
|
+
);
|
|
13081
|
+
}
|
|
13082
|
+
}
|
|
13083
|
+
|
|
13084
|
+
// src/dispatch/shared/baseline-weighted-fields.ts
|
|
13085
|
+
function recomputeBaselineWeightedFields(deps, criterion) {
|
|
13086
|
+
recomputeAllPonderators(criterion, deps.adapter);
|
|
13087
|
+
recomputeAllProgressRollup(deps.adapter);
|
|
13088
|
+
if (deps.now) {
|
|
13089
|
+
runExpectedProgressBase(
|
|
13090
|
+
deps.adapter,
|
|
13091
|
+
deps.now,
|
|
13092
|
+
deps.defaultBaseCalendarId ?? null
|
|
13093
|
+
);
|
|
13094
|
+
applyExpectedProgressLive(deps.adapter, deps.now);
|
|
13095
|
+
}
|
|
13096
|
+
emitRealCost(deps.adapter);
|
|
13097
|
+
if (deps.now) applyStatusPass(deps.adapter, deps.sector.statusCriteria);
|
|
13098
|
+
}
|
|
13099
|
+
|
|
13100
|
+
// src/dispatch/handlers/baseline-apply.ts
|
|
13101
|
+
function activeBaselineSignature(deps) {
|
|
13102
|
+
return JSON.stringify(
|
|
13103
|
+
deps.adapter.getAllIds().map((id) => {
|
|
13104
|
+
const point = deps.adapter.getActivity(id)?.baselinePoints.find((candidate) => candidate.isActiveVersion);
|
|
13105
|
+
return point ? [
|
|
13106
|
+
String(id),
|
|
13107
|
+
point.versionId,
|
|
13108
|
+
point.startDate?.getTime() ?? null,
|
|
13109
|
+
point.endDate?.getTime() ?? null,
|
|
13110
|
+
point.durationDays,
|
|
13111
|
+
point.cost,
|
|
13112
|
+
point.workHours,
|
|
13113
|
+
point.baseCalendarId,
|
|
13114
|
+
point.hoursPerDay,
|
|
13115
|
+
point.hoursPerWeek
|
|
13116
|
+
] : [String(id), null];
|
|
13117
|
+
})
|
|
13118
|
+
);
|
|
13119
|
+
}
|
|
13120
|
+
function dispatchBaselineApply(action, deps) {
|
|
13121
|
+
const beforeSnap = snapshotActivities(
|
|
13122
|
+
deps.adapter,
|
|
13123
|
+
new Set(deps.adapter.getAllIds())
|
|
13124
|
+
);
|
|
13125
|
+
const activeBaselineBefore = activeBaselineSignature(deps);
|
|
13126
|
+
const changedIds = applyBaselineOverlay(
|
|
13127
|
+
deps.adapter,
|
|
13128
|
+
action.points,
|
|
13129
|
+
deps.now,
|
|
13130
|
+
deps.reporter,
|
|
13131
|
+
deps.defaultBaseCalendarId ?? null
|
|
13132
|
+
);
|
|
13133
|
+
if (activeBaselineSignature(deps) !== activeBaselineBefore) {
|
|
13134
|
+
recomputeBaselineWeightedFields(
|
|
13135
|
+
deps,
|
|
13136
|
+
deps.sector.activityCreter ?? "DURATION"
|
|
13137
|
+
);
|
|
13138
|
+
}
|
|
13139
|
+
return {
|
|
13140
|
+
ok: true,
|
|
13141
|
+
changes: assembleChangeSet(deps.adapter, {
|
|
13142
|
+
source: action,
|
|
13143
|
+
beforeSnap,
|
|
13144
|
+
touchedIds: changedIds,
|
|
13145
|
+
scheduledIds: [],
|
|
13146
|
+
hoursPerDay: deps.sector.hoursPerDay
|
|
13147
|
+
})
|
|
13148
|
+
};
|
|
13149
|
+
}
|
|
13150
|
+
|
|
13151
|
+
// src/dispatch/handlers/ponderator-criterion-set.ts
|
|
13152
|
+
function assertValidCriterion(value) {
|
|
13153
|
+
if (value === "DURATION" || value === "COST" || value === "HH") return;
|
|
13154
|
+
throw new Error(
|
|
13155
|
+
`ponderator-criterion-set: invalid criterion "${String(value)}"`
|
|
13156
|
+
);
|
|
13157
|
+
}
|
|
13158
|
+
function dispatchPonderatorCriterionSet(action, deps) {
|
|
13159
|
+
assertValidCriterion(action.criterion);
|
|
13160
|
+
const allIds = new Set(deps.adapter.getAllIds());
|
|
13161
|
+
const beforeSnap = snapshotActivities(deps.adapter, allIds);
|
|
13162
|
+
recomputeBaselineWeightedFields(deps, action.criterion);
|
|
13163
|
+
deps.sector.activityCreter = action.criterion;
|
|
13164
|
+
return {
|
|
13165
|
+
ok: true,
|
|
13166
|
+
changes: assembleChangeSet(deps.adapter, {
|
|
13167
|
+
source: action,
|
|
13168
|
+
beforeSnap,
|
|
13169
|
+
touchedIds: allIds,
|
|
13170
|
+
scheduledIds: [],
|
|
13171
|
+
hoursPerDay: deps.sector.hoursPerDay
|
|
13172
|
+
})
|
|
13173
|
+
};
|
|
13174
|
+
}
|
|
13175
|
+
|
|
13176
|
+
// src/dispatch/handlers/status-criteria-set.ts
|
|
13177
|
+
function dispatchStatusCriteriaSet(action, deps) {
|
|
13178
|
+
const resolved = resolveStatusCriteria(action.criteria);
|
|
13179
|
+
const allIds = new Set(deps.adapter.getAllIds());
|
|
13180
|
+
const beforeSnap = snapshotActivities(deps.adapter, allIds);
|
|
13181
|
+
const changedIds = applyStatusPass(deps.adapter, resolved);
|
|
13182
|
+
deps.sector.statusCriteria = resolved;
|
|
13183
|
+
return {
|
|
13184
|
+
ok: true,
|
|
13185
|
+
changes: assembleChangeSet(deps.adapter, {
|
|
13186
|
+
source: action,
|
|
13187
|
+
beforeSnap,
|
|
13188
|
+
touchedIds: changedIds,
|
|
13189
|
+
scheduledIds: [],
|
|
13190
|
+
hoursPerDay: deps.sector.hoursPerDay
|
|
13191
|
+
})
|
|
13192
|
+
};
|
|
13193
|
+
}
|
|
13194
|
+
|
|
12561
13195
|
// src/dispatch/dispatch.ts
|
|
12562
13196
|
async function dispatch(action, options, deps) {
|
|
13197
|
+
if (action.kind === "persistence-acknowledge") {
|
|
13198
|
+
return dispatchPersistenceAcknowledge(action, deps);
|
|
13199
|
+
}
|
|
13200
|
+
if (action.kind === "baseline-apply") {
|
|
13201
|
+
return dispatchBaselineApply(action, deps);
|
|
13202
|
+
}
|
|
13203
|
+
if (action.kind === "ponderator-criterion-set") {
|
|
13204
|
+
return dispatchPonderatorCriterionSet(action, deps);
|
|
13205
|
+
}
|
|
13206
|
+
if (action.kind === "status-criteria-set") {
|
|
13207
|
+
return dispatchStatusCriteriaSet(action, deps);
|
|
13208
|
+
}
|
|
12563
13209
|
if (action.kind === "link-create" || action.kind === "link-update" || action.kind === "link-delete") {
|
|
12564
13210
|
return dispatchLink(action, options, deps);
|
|
12565
13211
|
}
|
|
@@ -15515,8 +16161,15 @@ var WriteCapture = class {
|
|
|
15515
16161
|
/** Pre-applyResults clone of an activity the autoscheduler will move (first-wins). */
|
|
15516
16162
|
noteScheduledBefore(activityId, current) {
|
|
15517
16163
|
const journal = this._journal;
|
|
15518
|
-
if (!journal
|
|
15519
|
-
|
|
16164
|
+
if (!journal) return;
|
|
16165
|
+
const beforeImage = cloneCoreActivity(current);
|
|
16166
|
+
if (!journal.scheduledBefore.has(activityId)) {
|
|
16167
|
+
journal.scheduledBefore.set(activityId, beforeImage);
|
|
16168
|
+
}
|
|
16169
|
+
if (!journal.before.has(activityId)) {
|
|
16170
|
+
journal.before.set(activityId, beforeImage);
|
|
16171
|
+
}
|
|
16172
|
+
journal.dirty.add(activityId);
|
|
15520
16173
|
}
|
|
15521
16174
|
/** Field write on a link — pre-mutation clone on first write per link id. */
|
|
15522
16175
|
noteLinkField(linkId, current) {
|
|
@@ -15530,20 +16183,6 @@ var WriteCapture = class {
|
|
|
15530
16183
|
});
|
|
15531
16184
|
}
|
|
15532
16185
|
};
|
|
15533
|
-
function cloneCoreActivity(activity) {
|
|
15534
|
-
return {
|
|
15535
|
-
...activity,
|
|
15536
|
-
startDate: new Date(activity.startDate),
|
|
15537
|
-
endDate: new Date(activity.endDate),
|
|
15538
|
-
constraintDate: activity.constraintDate ? new Date(activity.constraintDate) : null,
|
|
15539
|
-
dateOrigin: activity.dateOrigin ? new Date(activity.dateOrigin) : null,
|
|
15540
|
-
newActivityIds: [...activity.newActivityIds],
|
|
15541
|
-
pendingRequestIds: [...activity.pendingRequestIds],
|
|
15542
|
-
responsableIds: [...activity.responsableIds],
|
|
15543
|
-
tagIds: [...activity.tagIds],
|
|
15544
|
-
baselinePoints: [...activity.baselinePoints]
|
|
15545
|
-
};
|
|
15546
|
-
}
|
|
15547
16186
|
function cloneLink(link) {
|
|
15548
16187
|
return { ...link };
|
|
15549
16188
|
}
|
|
@@ -15723,6 +16362,18 @@ var HierarchyIndex = class {
|
|
|
15723
16362
|
arr.push(activity.id);
|
|
15724
16363
|
this._childrenByParent.set(key, arr);
|
|
15725
16364
|
}
|
|
16365
|
+
const compareIds = (left, right) => {
|
|
16366
|
+
const leftActivity = this.activities.get(left);
|
|
16367
|
+
const rightActivity = this.activities.get(right);
|
|
16368
|
+
if (!(leftActivity && rightActivity)) {
|
|
16369
|
+
return String(left).localeCompare(String(right));
|
|
16370
|
+
}
|
|
16371
|
+
return compareActivitiesInVisualOrder(leftActivity, rightActivity);
|
|
16372
|
+
};
|
|
16373
|
+
this._roots.sort(compareIds);
|
|
16374
|
+
for (const children of this._childrenByParent.values()) {
|
|
16375
|
+
children.sort(compareIds);
|
|
16376
|
+
}
|
|
15726
16377
|
}
|
|
15727
16378
|
};
|
|
15728
16379
|
|
|
@@ -15785,6 +16436,13 @@ var ScheduleState = class {
|
|
|
15785
16436
|
// whether a soft constraint repositioned the activity. Never persisted,
|
|
15786
16437
|
// never in the ChangeSet — not domain data on CoreActivity.
|
|
15787
16438
|
_lastStartDate = /* @__PURE__ */ new Map();
|
|
16439
|
+
// Transient gesture state: what a leaf looked like right before it gained its
|
|
16440
|
+
// first child and became a summary. Read by the demotion to give the activity
|
|
16441
|
+
// its own values back instead of the aggregate its children left behind. Not
|
|
16442
|
+
// persisted and not in the ChangeSet: it only makes sense inside the session
|
|
16443
|
+
// that performed the promotion. Kept (not consumed) so undo/redo of a
|
|
16444
|
+
// demotion restores identically every time.
|
|
16445
|
+
_promotionSnapshot = /* @__PURE__ */ new Map();
|
|
15788
16446
|
_links = /* @__PURE__ */ new Map();
|
|
15789
16447
|
_outgoing = /* @__PURE__ */ new Map();
|
|
15790
16448
|
_incoming = /* @__PURE__ */ new Map();
|
|
@@ -15800,6 +16458,7 @@ var ScheduleState = class {
|
|
|
15800
16458
|
_viewState = new ViewStateStore();
|
|
15801
16459
|
_viewStateBefore = null;
|
|
15802
16460
|
_lastStartDateBefore = null;
|
|
16461
|
+
_promotionSnapshotBefore = null;
|
|
15803
16462
|
// Calendar arithmetic + in-dispatch memoization. Assigned in the
|
|
15804
16463
|
// constructor once the calendar reader is built. See `CalendarCalculator`.
|
|
15805
16464
|
_calendar;
|
|
@@ -15884,6 +16543,19 @@ var ScheduleState = class {
|
|
|
15884
16543
|
this._captureLastStartDateOnce();
|
|
15885
16544
|
this._lastStartDate.set(String(activityId), startDate);
|
|
15886
16545
|
}
|
|
16546
|
+
getPromotionSnapshot(activityId) {
|
|
16547
|
+
return this._promotionSnapshot.get(String(activityId)) ?? null;
|
|
16548
|
+
}
|
|
16549
|
+
setPromotionSnapshot(activityId, snapshot) {
|
|
16550
|
+
this._capturePromotionSnapshotOnce();
|
|
16551
|
+
this._promotionSnapshot.set(String(activityId), snapshot);
|
|
16552
|
+
}
|
|
16553
|
+
_capturePromotionSnapshotOnce() {
|
|
16554
|
+
if (this._writeCapture.peek() === null) return;
|
|
16555
|
+
if (this._promotionSnapshotBefore === null) {
|
|
16556
|
+
this._promotionSnapshotBefore = new Map(this._promotionSnapshot);
|
|
16557
|
+
}
|
|
16558
|
+
}
|
|
15887
16559
|
_captureLastStartDateOnce() {
|
|
15888
16560
|
if (this._writeCapture.peek() === null) return;
|
|
15889
16561
|
if (this._lastStartDateBefore === null) {
|
|
@@ -16000,6 +16672,7 @@ var ScheduleState = class {
|
|
|
16000
16672
|
this._writeCapture.begin();
|
|
16001
16673
|
this._viewStateBefore = null;
|
|
16002
16674
|
this._lastStartDateBefore = null;
|
|
16675
|
+
this._promotionSnapshotBefore = null;
|
|
16003
16676
|
}
|
|
16004
16677
|
/** The live journal, or null when no capture is active. */
|
|
16005
16678
|
peekWriteCapture() {
|
|
@@ -16010,6 +16683,7 @@ var ScheduleState = class {
|
|
|
16010
16683
|
this._writeCapture.end();
|
|
16011
16684
|
this._viewStateBefore = null;
|
|
16012
16685
|
this._lastStartDateBefore = null;
|
|
16686
|
+
this._promotionSnapshotBefore = null;
|
|
16013
16687
|
}
|
|
16014
16688
|
// -- Replay-specific mutators --------------------------------------------
|
|
16015
16689
|
setActivityField(activityId, field, value) {
|
|
@@ -16161,439 +16835,156 @@ var ScheduleState = class {
|
|
|
16161
16835
|
if (this._viewStateBefore !== null) {
|
|
16162
16836
|
this._viewState.restore(this._viewStateBefore);
|
|
16163
16837
|
}
|
|
16838
|
+
if (this._promotionSnapshotBefore !== null) {
|
|
16839
|
+
this._promotionSnapshot = this._promotionSnapshotBefore;
|
|
16840
|
+
}
|
|
16164
16841
|
if (this._lastStartDateBefore !== null) {
|
|
16165
16842
|
this._lastStartDate = this._lastStartDateBefore;
|
|
16166
16843
|
}
|
|
16167
16844
|
this._cache.ids = null;
|
|
16168
|
-
this._cache.visualOrderIds = null;
|
|
16169
|
-
this._hierarchy.markDirty();
|
|
16170
|
-
}
|
|
16171
|
-
_restoreCorrelatives(correlativeBefore) {
|
|
16172
|
-
for (const [id, before] of correlativeBefore) {
|
|
16173
|
-
const live = this._activities.get(id);
|
|
16174
|
-
if (live) live.correlativeId = before;
|
|
16175
|
-
}
|
|
16176
|
-
}
|
|
16177
|
-
_undoLinkAdds(ops) {
|
|
16178
|
-
for (const op of ops)
|
|
16179
|
-
if (op.kind === "link-add") this._detachLink(op.linkId);
|
|
16180
|
-
}
|
|
16181
|
-
_undoInserts(ops) {
|
|
16182
|
-
for (const op of ops)
|
|
16183
|
-
if (op.kind === "insert") this._activities.delete(op.activityId);
|
|
16184
|
-
}
|
|
16185
|
-
_reInsertRemovedActivities(ops) {
|
|
16186
|
-
for (const op of ops)
|
|
16187
|
-
if (op.kind === "remove") this._activities.set(op.activityId, op.before);
|
|
16188
|
-
}
|
|
16189
|
-
_reAddRemovedLinks(ops) {
|
|
16190
|
-
for (const op of ops)
|
|
16191
|
-
if (op.kind === "link-remove") this._attachLink(op.before);
|
|
16192
|
-
}
|
|
16193
|
-
_restoreLinkFields(ops) {
|
|
16194
|
-
for (const op of ops)
|
|
16195
|
-
if (op.kind === "link-field" && this._links.has(op.linkId))
|
|
16196
|
-
this._links.set(op.linkId, op.before);
|
|
16197
|
-
}
|
|
16198
|
-
_restoreActivityFields(before) {
|
|
16199
|
-
for (const [id, snapshot] of before) {
|
|
16200
|
-
const live = this._activities.get(id);
|
|
16201
|
-
if (live) this._restoreScalarFields(live, snapshot);
|
|
16202
|
-
}
|
|
16203
|
-
}
|
|
16204
|
-
_restoreScalarFields(live, before) {
|
|
16205
|
-
for (const key of Object.keys(live)) {
|
|
16206
|
-
if (!Object.hasOwn(before, key)) Reflect.deleteProperty(live, key);
|
|
16207
|
-
}
|
|
16208
|
-
for (const key of Object.keys(before)) {
|
|
16209
|
-
Reflect.set(live, key, Reflect.get(before, key));
|
|
16210
|
-
}
|
|
16211
|
-
}
|
|
16212
|
-
_attachLink(link) {
|
|
16213
|
-
this._links.set(String(link.id), { ...link });
|
|
16214
|
-
this._indexLink(link);
|
|
16215
|
-
}
|
|
16216
|
-
_detachLink(linkId) {
|
|
16217
|
-
const link = this.getLink(linkId);
|
|
16218
|
-
if (!link) return;
|
|
16219
|
-
this._links.delete(String(linkId));
|
|
16220
|
-
this._deindexLink(link);
|
|
16221
|
-
}
|
|
16222
|
-
};
|
|
16223
|
-
var EMPTY_LINK_IDS = [];
|
|
16224
|
-
function isMutableLinkField(field) {
|
|
16225
|
-
return field === LINK_PROPERTY.LAG || field === LINK_PROPERTY.TYPE;
|
|
16226
|
-
}
|
|
16227
|
-
function fieldAffectsVisualOrder(field) {
|
|
16228
|
-
return field === ACTIVITY_PROPERTY.PARENT || field === ACTIVITY_PROPERTY.CORRELATIVE_ID;
|
|
16229
|
-
}
|
|
16230
|
-
function detachLinkRef(refs, linkId) {
|
|
16231
|
-
return refs.filter((ref) => String(ref) !== String(linkId));
|
|
16232
|
-
}
|
|
16233
|
-
function pushLinkRef(map, key, linkId) {
|
|
16234
|
-
const refs = map.get(key);
|
|
16235
|
-
if (refs) refs.push(linkId);
|
|
16236
|
-
else map.set(key, [linkId]);
|
|
16237
|
-
}
|
|
16238
|
-
function buildFlags(snapshot) {
|
|
16239
|
-
const rawFlags = snapshot.runtimeFlags ?? {};
|
|
16240
|
-
return {
|
|
16241
|
-
isPasting: Boolean(rawFlags.isPasting),
|
|
16242
|
-
isBulkOperation: Boolean(rawFlags.isBulkOperation),
|
|
16243
|
-
dragWithMultiple: Boolean(rawFlags.dragWithMultiple),
|
|
16244
|
-
draggingSingleMilestone: Boolean(rawFlags.draggingSingleMilestone),
|
|
16245
|
-
creatingActivity: false,
|
|
16246
|
-
avoidAutoScheduleBeforeDrag: false,
|
|
16247
|
-
maxPerformance: Boolean(rawFlags.maxPerformance),
|
|
16248
|
-
allCheckedTaskIds: []
|
|
16249
|
-
};
|
|
16250
|
-
}
|
|
16251
|
-
|
|
16252
|
-
// src/init/read-api.ts
|
|
16253
|
-
function readActivity(state, id) {
|
|
16254
|
-
return state.getActivity(id);
|
|
16255
|
-
}
|
|
16256
|
-
function readAllActivities(state) {
|
|
16257
|
-
return state.getAllActivities();
|
|
16258
|
-
}
|
|
16259
|
-
function readAllIds(state) {
|
|
16260
|
-
return state.getAllIds().map(String);
|
|
16261
|
-
}
|
|
16262
|
-
function forEachActivityId(state, visit) {
|
|
16263
|
-
state.forEachActivity((_activity, id) => visit(id));
|
|
16264
|
-
}
|
|
16265
|
-
function readChildren(state, parentId) {
|
|
16266
|
-
const childIds = parentId === ROOT_PARENT_ID ? readChildrenIds(state, ROOT_PARENT_ID) : state.getChildren(parentId);
|
|
16267
|
-
const out = [];
|
|
16268
|
-
for (const id of childIds) {
|
|
16269
|
-
const snap = state.getActivity(id);
|
|
16270
|
-
if (snap) out.push(snap);
|
|
16271
|
-
}
|
|
16272
|
-
out.sort((a, b) => (a.correlativeId ?? 0) - (b.correlativeId ?? 0));
|
|
16273
|
-
return out;
|
|
16274
|
-
}
|
|
16275
|
-
function readChildrenIds(state, parentId) {
|
|
16276
|
-
const key = parentId;
|
|
16277
|
-
if (key === ROOT_PARENT_ID) {
|
|
16278
|
-
const roots = [];
|
|
16279
|
-
state.forEachActivity((activity, id) => {
|
|
16280
|
-
if (isRootParent(activity.parentId)) roots.push(id);
|
|
16281
|
-
});
|
|
16282
|
-
return roots;
|
|
16283
|
-
}
|
|
16284
|
-
return [...state.getChildren(key)].map(String);
|
|
16285
|
-
}
|
|
16286
|
-
function readSelectedActivityIds(state) {
|
|
16287
|
-
return state.checkedIds().map(String);
|
|
16288
|
-
}
|
|
16289
|
-
function readHasChild(state, parentId) {
|
|
16290
|
-
return state.getChildren(parentId).length > 0;
|
|
16291
|
-
}
|
|
16292
|
-
function readLink(state, id) {
|
|
16293
|
-
const l = state.getLink(id);
|
|
16294
|
-
return l ? snapshotToLink(l) : null;
|
|
16295
|
-
}
|
|
16296
|
-
function readAllLinks(state) {
|
|
16297
|
-
return state.getAllLinks().map((l) => snapshotToLink(l));
|
|
16298
|
-
}
|
|
16299
|
-
|
|
16300
|
-
// src/propagations/downward/recompute-ponderator-for-parent.ts
|
|
16301
|
-
function recomputePonderatorsForParent(parentId, criterion, adapter) {
|
|
16302
|
-
if (!parentId || parentId === "0") return;
|
|
16303
|
-
const childIds = adapter.getChildren(parentId);
|
|
16304
|
-
if (childIds.length === 0) return;
|
|
16305
|
-
const pesoById = /* @__PURE__ */ new Map();
|
|
16306
|
-
let denominator = 0;
|
|
16307
|
-
for (const childId of childIds) {
|
|
16308
|
-
const peso = criterionValue(String(childId), criterion, adapter);
|
|
16309
|
-
pesoById.set(String(childId), peso);
|
|
16310
|
-
denominator += peso;
|
|
16311
|
-
}
|
|
16312
|
-
const relationValue = denominator ? 100 / denominator : 0;
|
|
16313
|
-
for (const childId of childIds) {
|
|
16314
|
-
const child = adapter.getActivity(childId);
|
|
16315
|
-
if (!child) continue;
|
|
16316
|
-
const points = child.baselinePoints;
|
|
16317
|
-
const active = getActiveBaseline(child);
|
|
16318
|
-
if (active) {
|
|
16319
|
-
const peso = pesoById.get(String(childId)) ?? 0;
|
|
16320
|
-
adapter.setActivityField(
|
|
16321
|
-
childId,
|
|
16322
|
-
COLUMN.PONDERATOR,
|
|
16323
|
-
relationValue * peso
|
|
16324
|
-
);
|
|
16325
|
-
} else if (!Array.isArray(points) || points.length === 0) {
|
|
16326
|
-
adapter.setActivityField(childId, COLUMN.PONDERATOR, 0);
|
|
16327
|
-
}
|
|
16328
|
-
}
|
|
16329
|
-
}
|
|
16330
|
-
function criterionValue(childId, criterion, adapter) {
|
|
16331
|
-
const child = adapter.getActivity(childId);
|
|
16332
|
-
if (!child) return 0;
|
|
16333
|
-
const active = getActiveBaseline(child);
|
|
16334
|
-
if (!active) return 0;
|
|
16335
|
-
if (criterion === "COST") return toNumber(active.cost);
|
|
16336
|
-
if (criterion === "HH") return toNumber(active.workHours);
|
|
16337
|
-
const type = child.type;
|
|
16338
|
-
if (type === "project")
|
|
16339
|
-
return sumRecursiveBaselineDurationDays(childId, adapter);
|
|
16340
|
-
if (type === "milestone") return 0;
|
|
16341
|
-
return toNumber(active.durationDays);
|
|
16342
|
-
}
|
|
16343
|
-
function sumRecursiveBaselineDurationDays(activityId, adapter) {
|
|
16344
|
-
let sum = 0;
|
|
16345
|
-
for (const childId of adapter.getChildren(activityId)) {
|
|
16346
|
-
const child = adapter.getActivity(childId);
|
|
16347
|
-
if (!child) continue;
|
|
16348
|
-
const active = getActiveBaseline(child);
|
|
16349
|
-
if (!active) continue;
|
|
16350
|
-
const type = child.type;
|
|
16351
|
-
if (type === "project") {
|
|
16352
|
-
sum += sumRecursiveBaselineDurationDays(String(childId), adapter);
|
|
16353
|
-
} else if (type !== "milestone") {
|
|
16354
|
-
sum += toNumber(active.durationDays);
|
|
16355
|
-
}
|
|
16356
|
-
}
|
|
16357
|
-
return sum;
|
|
16358
|
-
}
|
|
16359
|
-
function toNumber(v) {
|
|
16360
|
-
const n = typeof v === "string" ? parseFloat(v) : v;
|
|
16361
|
-
return typeof n === "number" && Number.isFinite(n) ? n : 0;
|
|
16362
|
-
}
|
|
16363
|
-
|
|
16364
|
-
// src/propagations/downward/recompute-all-ponderators.ts
|
|
16365
|
-
function recomputeAllPonderators(criterion, adapter) {
|
|
16366
|
-
adapter.forEachActivity((_a, id) => {
|
|
16367
|
-
adapter.setActivityField(id, COLUMN.PONDERATOR, 0);
|
|
16368
|
-
});
|
|
16369
|
-
adapter.forEachActivity((_a, id) => {
|
|
16370
|
-
if (adapter.getChildren(id).length > 0) {
|
|
16371
|
-
recomputePonderatorsForParent(String(id), criterion, adapter);
|
|
16845
|
+
this._cache.visualOrderIds = null;
|
|
16846
|
+
this._hierarchy.markDirty();
|
|
16847
|
+
}
|
|
16848
|
+
_restoreCorrelatives(correlativeBefore) {
|
|
16849
|
+
for (const [id, before] of correlativeBefore) {
|
|
16850
|
+
const live = this._activities.get(id);
|
|
16851
|
+
if (live) live.correlativeId = before;
|
|
16372
16852
|
}
|
|
16373
|
-
});
|
|
16374
|
-
}
|
|
16375
|
-
|
|
16376
|
-
// src/propagations/upward/progress-rollup.ts
|
|
16377
|
-
function recomputeAllProgressRollup(adapter) {
|
|
16378
|
-
for (const parentId of parentsDeepestFirst(adapter)) {
|
|
16379
|
-
rollupParent(parentId, adapter);
|
|
16380
16853
|
}
|
|
16381
|
-
|
|
16382
|
-
|
|
16383
|
-
|
|
16384
|
-
adapter.forEachActivity((_activity, id) => {
|
|
16385
|
-
if (adapter.getChildren(id).length > 0) parents.add(id);
|
|
16386
|
-
});
|
|
16387
|
-
const depthById = /* @__PURE__ */ new Map();
|
|
16388
|
-
for (const id of parents) depthById.set(id, depthOf2(id, adapter));
|
|
16389
|
-
return [...parents].sort(
|
|
16390
|
-
(a, b) => (depthById.get(b) ?? 0) - (depthById.get(a) ?? 0)
|
|
16391
|
-
);
|
|
16392
|
-
}
|
|
16393
|
-
function depthOf2(id, adapter) {
|
|
16394
|
-
let depth = 0;
|
|
16395
|
-
let current = id;
|
|
16396
|
-
while (current && current !== "0") {
|
|
16397
|
-
if (!adapter.getActivity(current)) break;
|
|
16398
|
-
depth += 1;
|
|
16399
|
-
current = adapter.getParentId(current);
|
|
16854
|
+
_undoLinkAdds(ops) {
|
|
16855
|
+
for (const op of ops)
|
|
16856
|
+
if (op.kind === "link-add") this._detachLink(op.linkId);
|
|
16400
16857
|
}
|
|
16401
|
-
|
|
16402
|
-
|
|
16403
|
-
|
|
16404
|
-
const childIds = adapter.getChildren(parentId);
|
|
16405
|
-
if (childIds.length === 0) return;
|
|
16406
|
-
const children = [];
|
|
16407
|
-
for (const childId of childIds) {
|
|
16408
|
-
const child = adapter.getActivity(childId);
|
|
16409
|
-
if (!child) continue;
|
|
16410
|
-
children.push({
|
|
16411
|
-
progress: Number(child.progress ?? 0),
|
|
16412
|
-
ponderator: Number(child.ponderator ?? 0)
|
|
16413
|
-
});
|
|
16858
|
+
_undoInserts(ops) {
|
|
16859
|
+
for (const op of ops)
|
|
16860
|
+
if (op.kind === "insert") this._activities.delete(op.activityId);
|
|
16414
16861
|
}
|
|
16415
|
-
|
|
16416
|
-
|
|
16417
|
-
|
|
16418
|
-
parentId,
|
|
16419
|
-
COLUMN.PROGRESS,
|
|
16420
|
-
roundProgressPerLevel(rollup)
|
|
16421
|
-
);
|
|
16862
|
+
_reInsertRemovedActivities(ops) {
|
|
16863
|
+
for (const op of ops)
|
|
16864
|
+
if (op.kind === "remove") this._activities.set(op.activityId, op.before);
|
|
16422
16865
|
}
|
|
16423
|
-
|
|
16424
|
-
|
|
16425
|
-
|
|
16426
|
-
function parseBaselineDate(value) {
|
|
16427
|
-
return typeof value === "string" && value.length > 0 ? parseBackendDate(value) : value instanceof Date ? value : null;
|
|
16428
|
-
}
|
|
16429
|
-
function parseFiniteNonNegative(value) {
|
|
16430
|
-
const numeric = typeof value === "number" ? value : typeof value === "string" && value.trim() !== "" ? Number(value) : Number.NaN;
|
|
16431
|
-
if (!Number.isFinite(numeric) || numeric < 0) return null;
|
|
16432
|
-
return numeric;
|
|
16433
|
-
}
|
|
16434
|
-
function normalizeBaselinePoint(point, reporter) {
|
|
16435
|
-
const durationDays = parseFiniteNonNegative(point.duration);
|
|
16436
|
-
const cost = parseFiniteNonNegative(point.cost);
|
|
16437
|
-
const workHours = parseFiniteNonNegative(point.hh_work);
|
|
16438
|
-
if (durationDays === null || cost === null || workHours === null) {
|
|
16439
|
-
reporter.warn(
|
|
16440
|
-
`[baseline] dropping point with non-finite/negative magnitude \u2014 duration=${JSON.stringify(point.duration)}, cost=${JSON.stringify(point.cost)}, hh_work=${JSON.stringify(point.hh_work)}`
|
|
16441
|
-
);
|
|
16442
|
-
return null;
|
|
16866
|
+
_reAddRemovedLinks(ops) {
|
|
16867
|
+
for (const op of ops)
|
|
16868
|
+
if (op.kind === "link-remove") this._attachLink(op.before);
|
|
16443
16869
|
}
|
|
16444
|
-
|
|
16445
|
-
|
|
16446
|
-
|
|
16447
|
-
|
|
16448
|
-
cost,
|
|
16449
|
-
workHours,
|
|
16450
|
-
versionId: typeof point.sectorbaselineversionId === "number" ? point.sectorbaselineversionId : null,
|
|
16451
|
-
isActiveVersion: Boolean(point.sectorbaselineversion?.active),
|
|
16452
|
-
baseCalendarId: point.baseCalendarId != null ? String(point.baseCalendarId) : null,
|
|
16453
|
-
hoursPerDay: typeof point.hoursPerDay === "number" ? point.hoursPerDay : null,
|
|
16454
|
-
hoursPerWeek: typeof point.hoursPerWeek === "number" ? point.hoursPerWeek : null
|
|
16455
|
-
};
|
|
16456
|
-
}
|
|
16457
|
-
|
|
16458
|
-
// src/baselines/apply-baseline-points.ts
|
|
16459
|
-
function applyBaselinePoints(adapter, points, reporter) {
|
|
16460
|
-
const idByProplanner = /* @__PURE__ */ new Map();
|
|
16461
|
-
adapter.forEachActivity((a, id) => {
|
|
16462
|
-
const pid = a.proplannerId;
|
|
16463
|
-
if (typeof pid === "number") idByProplanner.set(pid, id);
|
|
16464
|
-
});
|
|
16465
|
-
const grouped = /* @__PURE__ */ new Map();
|
|
16466
|
-
for (const p of points) {
|
|
16467
|
-
const activityId = p.activityId;
|
|
16468
|
-
if (typeof activityId !== "number") continue;
|
|
16469
|
-
const coreId = idByProplanner.get(activityId);
|
|
16470
|
-
if (coreId === void 0) continue;
|
|
16471
|
-
const arr = grouped.get(coreId);
|
|
16472
|
-
if (arr) arr.push(p);
|
|
16473
|
-
else grouped.set(coreId, [p]);
|
|
16870
|
+
_restoreLinkFields(ops) {
|
|
16871
|
+
for (const op of ops)
|
|
16872
|
+
if (op.kind === "link-field" && this._links.has(op.linkId))
|
|
16873
|
+
this._links.set(op.linkId, op.before);
|
|
16474
16874
|
}
|
|
16475
|
-
|
|
16476
|
-
|
|
16477
|
-
|
|
16478
|
-
|
|
16479
|
-
|
|
16480
|
-
group.map((point) => normalizeBaselinePoint(point, reporter)).filter((point) => point !== null)
|
|
16481
|
-
);
|
|
16482
|
-
changed.push(coreId);
|
|
16875
|
+
_restoreActivityFields(before) {
|
|
16876
|
+
for (const [id, snapshot] of before) {
|
|
16877
|
+
const live = this._activities.get(id);
|
|
16878
|
+
if (live) this._restoreScalarFields(live, snapshot);
|
|
16879
|
+
}
|
|
16483
16880
|
}
|
|
16484
|
-
|
|
16485
|
-
|
|
16486
|
-
|
|
16487
|
-
if (Array.isArray(existing) && existing.length > 0) {
|
|
16488
|
-
adapter.setActivityField(id, "baselinePoints", []);
|
|
16489
|
-
changed.push(id);
|
|
16881
|
+
_restoreScalarFields(live, before) {
|
|
16882
|
+
for (const key of Object.keys(live)) {
|
|
16883
|
+
if (!Object.hasOwn(before, key)) Reflect.deleteProperty(live, key);
|
|
16490
16884
|
}
|
|
16491
|
-
|
|
16492
|
-
|
|
16885
|
+
for (const key of Object.keys(before)) {
|
|
16886
|
+
Reflect.set(live, key, Reflect.get(before, key));
|
|
16887
|
+
}
|
|
16888
|
+
}
|
|
16889
|
+
_attachLink(link) {
|
|
16890
|
+
this._links.set(String(link.id), { ...link });
|
|
16891
|
+
this._indexLink(link);
|
|
16892
|
+
}
|
|
16893
|
+
_detachLink(linkId) {
|
|
16894
|
+
const link = this.getLink(linkId);
|
|
16895
|
+
if (!link) return;
|
|
16896
|
+
this._links.delete(String(linkId));
|
|
16897
|
+
this._deindexLink(link);
|
|
16898
|
+
}
|
|
16899
|
+
};
|
|
16900
|
+
var EMPTY_LINK_IDS = [];
|
|
16901
|
+
function isMutableLinkField(field) {
|
|
16902
|
+
return field === LINK_PROPERTY.LAG || field === LINK_PROPERTY.TYPE;
|
|
16493
16903
|
}
|
|
16494
|
-
|
|
16495
|
-
|
|
16496
|
-
|
|
16497
|
-
|
|
16498
|
-
|
|
16904
|
+
function fieldAffectsVisualOrder(field) {
|
|
16905
|
+
return field === ACTIVITY_PROPERTY.PARENT || field === ACTIVITY_PROPERTY.CORRELATIVE_ID;
|
|
16906
|
+
}
|
|
16907
|
+
function detachLinkRef(refs, linkId) {
|
|
16908
|
+
return refs.filter((ref) => String(ref) !== String(linkId));
|
|
16909
|
+
}
|
|
16910
|
+
function pushLinkRef(map, key, linkId) {
|
|
16911
|
+
const refs = map.get(key);
|
|
16912
|
+
if (refs) refs.push(linkId);
|
|
16913
|
+
else map.set(key, [linkId]);
|
|
16914
|
+
}
|
|
16915
|
+
function buildFlags(snapshot) {
|
|
16916
|
+
const rawFlags = snapshot.runtimeFlags ?? {};
|
|
16499
16917
|
return {
|
|
16500
|
-
|
|
16501
|
-
|
|
16502
|
-
|
|
16503
|
-
|
|
16504
|
-
|
|
16918
|
+
isPasting: Boolean(rawFlags.isPasting),
|
|
16919
|
+
isBulkOperation: Boolean(rawFlags.isBulkOperation),
|
|
16920
|
+
dragWithMultiple: Boolean(rawFlags.dragWithMultiple),
|
|
16921
|
+
draggingSingleMilestone: Boolean(rawFlags.draggingSingleMilestone),
|
|
16922
|
+
creatingActivity: false,
|
|
16923
|
+
avoidAutoScheduleBeforeDrag: false,
|
|
16924
|
+
maxPerformance: Boolean(rawFlags.maxPerformance),
|
|
16925
|
+
allCheckedTaskIds: []
|
|
16505
16926
|
};
|
|
16506
16927
|
}
|
|
16507
|
-
function emitBaselineSnapshotColumns(state) {
|
|
16508
|
-
const changed = [];
|
|
16509
|
-
state.forEachActivity((activity, id) => {
|
|
16510
|
-
const snapshot = buildBaselineSnapshot(activity);
|
|
16511
|
-
if (!snapshot) return;
|
|
16512
|
-
state.setActivityField(id, "baselineSnapshot", snapshot);
|
|
16513
|
-
changed.push(id);
|
|
16514
|
-
});
|
|
16515
|
-
return changed;
|
|
16516
|
-
}
|
|
16517
16928
|
|
|
16518
|
-
// src/
|
|
16519
|
-
function
|
|
16520
|
-
|
|
16521
|
-
const changed = /* @__PURE__ */ new Set();
|
|
16522
|
-
for (const id of applyBaselinePoints(
|
|
16523
|
-
state,
|
|
16524
|
-
points,
|
|
16525
|
-
reporter
|
|
16526
|
-
)) {
|
|
16527
|
-
changed.add(id);
|
|
16528
|
-
}
|
|
16529
|
-
if (now) {
|
|
16530
|
-
for (const id of runExpectedProgressBase(state, now, defaultBaseCalendarId))
|
|
16531
|
-
changed.add(id);
|
|
16532
|
-
}
|
|
16533
|
-
for (const id of emitBaselineSnapshotColumns(state)) changed.add(id);
|
|
16534
|
-
for (const id of emitRealCost(state)) changed.add(id);
|
|
16535
|
-
return [...changed];
|
|
16929
|
+
// src/shared/clone-domain-value.ts
|
|
16930
|
+
function cloneDomainValue(value) {
|
|
16931
|
+
return structuredClone(value);
|
|
16536
16932
|
}
|
|
16537
16933
|
|
|
16538
|
-
// src/init/
|
|
16539
|
-
function
|
|
16540
|
-
const
|
|
16541
|
-
return
|
|
16934
|
+
// src/init/read-api.ts
|
|
16935
|
+
function readActivity(state, id) {
|
|
16936
|
+
const activity = state.getActivity(id);
|
|
16937
|
+
return activity ? cloneDomainValue(activity) : null;
|
|
16542
16938
|
}
|
|
16543
|
-
function
|
|
16544
|
-
|
|
16545
|
-
return typeof v === "number" && Number.isFinite(v) ? v : 0;
|
|
16939
|
+
function readAllActivities(state) {
|
|
16940
|
+
return state.getAllActivities().map(cloneDomainValue);
|
|
16546
16941
|
}
|
|
16547
|
-
function
|
|
16548
|
-
|
|
16549
|
-
state.forEachActivity((a, id) => {
|
|
16550
|
-
before.set(id, readPonderator(a));
|
|
16551
|
-
});
|
|
16552
|
-
recomputeAllPonderators(criterion, state);
|
|
16553
|
-
const changed = [];
|
|
16554
|
-
state.forEachActivity((a, id) => {
|
|
16555
|
-
if (readPonderator(a) !== (before.get(id) ?? 0)) {
|
|
16556
|
-
changed.push(structuredCloneActivity(a));
|
|
16557
|
-
}
|
|
16558
|
-
});
|
|
16559
|
-
return changed;
|
|
16942
|
+
function readAllIds(state) {
|
|
16943
|
+
return state.getAllIds().map(String);
|
|
16560
16944
|
}
|
|
16561
|
-
function
|
|
16562
|
-
|
|
16563
|
-
state.forEachActivity((a, id) => {
|
|
16564
|
-
before.set(id, readProgress(a));
|
|
16565
|
-
});
|
|
16566
|
-
recomputeAllProgressRollup(state);
|
|
16567
|
-
const changed = [];
|
|
16568
|
-
state.forEachActivity((a, id) => {
|
|
16569
|
-
if (readProgress(a) !== (before.get(id) ?? 0)) {
|
|
16570
|
-
changed.push(structuredCloneActivity(a));
|
|
16571
|
-
}
|
|
16572
|
-
});
|
|
16573
|
-
return changed;
|
|
16945
|
+
function forEachActivityId(state, visit) {
|
|
16946
|
+
state.forEachActivity((_activity, id) => visit(id));
|
|
16574
16947
|
}
|
|
16575
|
-
function
|
|
16576
|
-
const
|
|
16577
|
-
|
|
16578
|
-
|
|
16579
|
-
now,
|
|
16580
|
-
reporter,
|
|
16581
|
-
defaultBaseCalendarId
|
|
16582
|
-
);
|
|
16583
|
-
const changed = [];
|
|
16584
|
-
for (const id of changedIds) {
|
|
16948
|
+
function readChildren(state, parentId) {
|
|
16949
|
+
const childIds = parentId === ROOT_PARENT_ID ? readChildrenIds(state, ROOT_PARENT_ID) : state.getChildren(parentId);
|
|
16950
|
+
const out = [];
|
|
16951
|
+
for (const id of childIds) {
|
|
16585
16952
|
const snap = state.getActivity(id);
|
|
16586
|
-
if (snap)
|
|
16953
|
+
if (snap) out.push(cloneDomainValue(snap));
|
|
16954
|
+
}
|
|
16955
|
+
out.sort((a, b) => (a.correlativeId ?? 0) - (b.correlativeId ?? 0));
|
|
16956
|
+
return out;
|
|
16957
|
+
}
|
|
16958
|
+
function readChildrenIds(state, parentId) {
|
|
16959
|
+
const key = parentId;
|
|
16960
|
+
if (key === ROOT_PARENT_ID) {
|
|
16961
|
+
const roots = [];
|
|
16962
|
+
state.forEachActivity((activity, id) => {
|
|
16963
|
+
if (isRootParent(activity.parentId)) roots.push(id);
|
|
16964
|
+
});
|
|
16965
|
+
return roots;
|
|
16587
16966
|
}
|
|
16588
|
-
return
|
|
16967
|
+
return [...state.getChildren(key)].map(String);
|
|
16589
16968
|
}
|
|
16590
|
-
function
|
|
16591
|
-
|
|
16592
|
-
|
|
16593
|
-
|
|
16594
|
-
|
|
16969
|
+
function readSelectedActivityIds(state) {
|
|
16970
|
+
return state.checkedIds().map(String);
|
|
16971
|
+
}
|
|
16972
|
+
function readHasChild(state, parentId) {
|
|
16973
|
+
if (parentId === ROOT_PARENT_ID) {
|
|
16974
|
+
let hasRoot = false;
|
|
16975
|
+
state.forEachActivity((activity) => {
|
|
16976
|
+
hasRoot ||= isRootParent(activity.parentId);
|
|
16977
|
+
});
|
|
16978
|
+
return hasRoot;
|
|
16595
16979
|
}
|
|
16596
|
-
return
|
|
16980
|
+
return state.getChildren(parentId).length > 0;
|
|
16981
|
+
}
|
|
16982
|
+
function readLink(state, id) {
|
|
16983
|
+
const l = state.getLink(id);
|
|
16984
|
+
return l ? snapshotToLink(l) : null;
|
|
16985
|
+
}
|
|
16986
|
+
function readAllLinks(state) {
|
|
16987
|
+
return state.getAllLinks().map((l) => snapshotToLink(l));
|
|
16597
16988
|
}
|
|
16598
16989
|
|
|
16599
16990
|
// src/internal/state/project-work-hours.ts
|
|
@@ -16703,8 +17094,12 @@ function mergeCoalesced(top, next) {
|
|
|
16703
17094
|
};
|
|
16704
17095
|
return buildUndoEntry(changeSet);
|
|
16705
17096
|
}
|
|
16706
|
-
function
|
|
16707
|
-
|
|
17097
|
+
function getDispatchHistoryPolicy(action) {
|
|
17098
|
+
if (action.kind === "persistence-acknowledge") return "clear-on-success";
|
|
17099
|
+
if (action.kind === "sir-sync" || action.kind === "activity-lookahead-sync" || action.kind === "baseline-apply" || action.kind === "ponderator-criterion-set" || action.kind === "status-criteria-set") {
|
|
17100
|
+
return "skip";
|
|
17101
|
+
}
|
|
17102
|
+
return "record";
|
|
16708
17103
|
}
|
|
16709
17104
|
function needsResync(entry) {
|
|
16710
17105
|
for (const change of entry.changeSet.activities) {
|
|
@@ -16724,6 +17119,7 @@ function buildInverseChangeSet(state, entry, side) {
|
|
|
16724
17119
|
activities.push({
|
|
16725
17120
|
id: activityId,
|
|
16726
17121
|
kind: "updated",
|
|
17122
|
+
fields: historyFields(change.fields, side),
|
|
16727
17123
|
after: snapshot ? structuredCloneActivity(snapshot) : null
|
|
16728
17124
|
});
|
|
16729
17125
|
} else if (change.kind === "deleted") {
|
|
@@ -16757,6 +17153,7 @@ function buildInverseChangeSet(state, entry, side) {
|
|
|
16757
17153
|
links.push({
|
|
16758
17154
|
id: linkId,
|
|
16759
17155
|
kind: "updated",
|
|
17156
|
+
fields: historyFields(change.fields, side),
|
|
16760
17157
|
after: lk ? snapshotToLink(lk) : null
|
|
16761
17158
|
});
|
|
16762
17159
|
} else if (change.kind === "deleted") {
|
|
@@ -16796,6 +17193,21 @@ function buildInverseChangeSet(state, entry, side) {
|
|
|
16796
17193
|
viewState
|
|
16797
17194
|
};
|
|
16798
17195
|
}
|
|
17196
|
+
function historyFields(fields, side) {
|
|
17197
|
+
if (fields == null) return void 0;
|
|
17198
|
+
return Object.fromEntries(
|
|
17199
|
+
Object.entries(fields).map(([field, values]) => [
|
|
17200
|
+
field,
|
|
17201
|
+
side === "before" ? {
|
|
17202
|
+
before: cloneDomainValue(values.after),
|
|
17203
|
+
after: cloneDomainValue(values.before)
|
|
17204
|
+
} : {
|
|
17205
|
+
before: cloneDomainValue(values.before),
|
|
17206
|
+
after: cloneDomainValue(values.after)
|
|
17207
|
+
}
|
|
17208
|
+
])
|
|
17209
|
+
);
|
|
17210
|
+
}
|
|
16799
17211
|
function invertViewStateChange(change) {
|
|
16800
17212
|
return {
|
|
16801
17213
|
activityId: change.activityId,
|
|
@@ -16971,6 +17383,7 @@ var UndoRecorder = class {
|
|
|
16971
17383
|
clear() {
|
|
16972
17384
|
this.undoStack.length = 0;
|
|
16973
17385
|
this.redoStack.length = 0;
|
|
17386
|
+
this.resetCoalesce();
|
|
16974
17387
|
}
|
|
16975
17388
|
};
|
|
16976
17389
|
|
|
@@ -17333,8 +17746,7 @@ function parseActivity(raw, context) {
|
|
|
17333
17746
|
expectedProgress: null,
|
|
17334
17747
|
expectedProgressBaseline: null,
|
|
17335
17748
|
status: null,
|
|
17336
|
-
criticalPath: null
|
|
17337
|
-
promotionRestore: null
|
|
17749
|
+
criticalPath: null
|
|
17338
17750
|
};
|
|
17339
17751
|
}
|
|
17340
17752
|
function forceRootProjectToRoot(activities) {
|
|
@@ -18339,6 +18751,117 @@ function snapDemotedLeafTiming(state, activityId) {
|
|
|
18339
18751
|
state.setActivityField(activityId, ACTIVITY_PROPERTY.END_DATE, end);
|
|
18340
18752
|
}
|
|
18341
18753
|
|
|
18754
|
+
// src/propagations/upward/recompute-real-work.ts
|
|
18755
|
+
function recomputeCanonicalRealWork(state) {
|
|
18756
|
+
const rootIds = [];
|
|
18757
|
+
const changedIds = [];
|
|
18758
|
+
state.forEachActivity((activity, activityId) => {
|
|
18759
|
+
if (activity.parentId === null) rootIds.push(String(activityId));
|
|
18760
|
+
});
|
|
18761
|
+
const visit = (activityId) => {
|
|
18762
|
+
const activity = state.getActivity(activityId);
|
|
18763
|
+
if (!activity) return 0;
|
|
18764
|
+
const childIds = [...state.getChildren(activityId)];
|
|
18765
|
+
const realWork = childIds.length === 0 ? computeLeafRealWork(activity.workHours, activity.progress) : childIds.reduce(
|
|
18766
|
+
(total, childId) => total + visit(String(childId)),
|
|
18767
|
+
0
|
|
18768
|
+
);
|
|
18769
|
+
state.setActivityField(
|
|
18770
|
+
activityId,
|
|
18771
|
+
ACTIVITY_PROPERTY.REAL_WORK_HOURS,
|
|
18772
|
+
realWork
|
|
18773
|
+
);
|
|
18774
|
+
changedIds.push(activityId);
|
|
18775
|
+
return realWork;
|
|
18776
|
+
};
|
|
18777
|
+
for (const rootId of rootIds) visit(rootId);
|
|
18778
|
+
return changedIds;
|
|
18779
|
+
}
|
|
18780
|
+
|
|
18781
|
+
// src/init/initial-passes.ts
|
|
18782
|
+
async function runInitialPasses(deps) {
|
|
18783
|
+
const { state, sector, scheduler, skipAutoSchedule, now } = deps;
|
|
18784
|
+
recomputeCorrelativeIds(state);
|
|
18785
|
+
if (sector.updateDurationForPrimaveraEndDate) {
|
|
18786
|
+
recomputeDurationsFromDates(state);
|
|
18787
|
+
}
|
|
18788
|
+
normalizeLoadedConstraintDates(state);
|
|
18789
|
+
recomputeCanonicalRealWork(state);
|
|
18790
|
+
if (skipAutoSchedule) {
|
|
18791
|
+
if (now) {
|
|
18792
|
+
applyExpectedProgressLive(state, now);
|
|
18793
|
+
applyStatusPass(state, sector.statusCriteria);
|
|
18794
|
+
}
|
|
18795
|
+
return;
|
|
18796
|
+
}
|
|
18797
|
+
const result = await scheduler.schedule({});
|
|
18798
|
+
applyResults(state, result);
|
|
18799
|
+
normalizeMilestoneConstraintDatesForDisplay(state);
|
|
18800
|
+
recomputeSkippedLeafEnds(state);
|
|
18801
|
+
await updateParentBoundsFromChildren(state, void 0, false);
|
|
18802
|
+
if (now) {
|
|
18803
|
+
applyExpectedProgressLive(state, now);
|
|
18804
|
+
applyStatusPass(state, sector.statusCriteria);
|
|
18805
|
+
}
|
|
18806
|
+
}
|
|
18807
|
+
function recomputeSkippedLeafEnds(state) {
|
|
18808
|
+
state.forEachActivity((activity) => {
|
|
18809
|
+
if (activity.autoScheduling) return;
|
|
18810
|
+
if (!activity.startDate || activity.durationHours == null) return;
|
|
18811
|
+
if (state.getChildren(activity.id).length > 0) return;
|
|
18812
|
+
activity.endDate = state.calculateEndDate({
|
|
18813
|
+
startDate: activity.startDate,
|
|
18814
|
+
durationHours: activity.durationHours,
|
|
18815
|
+
task: activity
|
|
18816
|
+
});
|
|
18817
|
+
});
|
|
18818
|
+
}
|
|
18819
|
+
function recomputeDurationsFromDates(state) {
|
|
18820
|
+
state.forEachActivity((activity) => {
|
|
18821
|
+
if (!activity.startDate || !activity.endDate) return;
|
|
18822
|
+
activity.durationHours = state.calculateDuration({
|
|
18823
|
+
startDate: activity.startDate,
|
|
18824
|
+
endDate: activity.endDate,
|
|
18825
|
+
task: activity
|
|
18826
|
+
});
|
|
18827
|
+
});
|
|
18828
|
+
}
|
|
18829
|
+
function normalizeLoadedConstraintDates(state) {
|
|
18830
|
+
state.forEachActivity((activity) => {
|
|
18831
|
+
const type = activity.constraintType;
|
|
18832
|
+
if (!type || !activity.constraintDate) return;
|
|
18833
|
+
const constraintDate = activity.constraintDate;
|
|
18834
|
+
if (activity.type === "milestone" && (constraintDate.getUTCHours() !== 0 || constraintDate.getUTCMinutes() !== 0)) {
|
|
18835
|
+
return;
|
|
18836
|
+
}
|
|
18837
|
+
const calendar = state.calendarReader.getCalendar(
|
|
18838
|
+
String(activity.calendarId)
|
|
18839
|
+
);
|
|
18840
|
+
if (!calendar) return;
|
|
18841
|
+
activity.constraintDate = normalizeConstraintDate(
|
|
18842
|
+
activity.constraintDate,
|
|
18843
|
+
calendar,
|
|
18844
|
+
type
|
|
18845
|
+
);
|
|
18846
|
+
});
|
|
18847
|
+
}
|
|
18848
|
+
function normalizeMilestoneConstraintDatesForDisplay(state) {
|
|
18849
|
+
state.forEachActivity((activity) => {
|
|
18850
|
+
if (activity.type !== "milestone") return;
|
|
18851
|
+
const type = activity.constraintType;
|
|
18852
|
+
if (!type || !activity.constraintDate) return;
|
|
18853
|
+
const calendar = state.calendarReader.getCalendar(
|
|
18854
|
+
String(activity.calendarId)
|
|
18855
|
+
);
|
|
18856
|
+
if (!calendar) return;
|
|
18857
|
+
activity.constraintDate = normalizeConstraintDate(
|
|
18858
|
+
activity.constraintDate,
|
|
18859
|
+
calendar,
|
|
18860
|
+
type
|
|
18861
|
+
);
|
|
18862
|
+
});
|
|
18863
|
+
}
|
|
18864
|
+
|
|
18342
18865
|
// src/init/initialize-core.ts
|
|
18343
18866
|
var SCHEDULE_CORE_STATUS = {
|
|
18344
18867
|
READY: "ready",
|
|
@@ -18426,48 +18949,8 @@ function initializeCore(input) {
|
|
|
18426
18949
|
}
|
|
18427
18950
|
|
|
18428
18951
|
// src/init/schedule-core.ts
|
|
18429
|
-
function assertValidPersistenceAssignments(assignments, entityName, readCurrent, ownerByBackendId) {
|
|
18430
|
-
const seenIds = /* @__PURE__ */ new Set();
|
|
18431
|
-
const seenBackendIds = /* @__PURE__ */ new Set();
|
|
18432
|
-
for (const assignment of assignments) {
|
|
18433
|
-
const id = String(assignment.id);
|
|
18434
|
-
if (id.length === 0 || seenIds.has(id)) {
|
|
18435
|
-
throw new Error(
|
|
18436
|
-
`acknowledgePersistence: duplicate or empty ${entityName} id "${id}"`
|
|
18437
|
-
);
|
|
18438
|
-
}
|
|
18439
|
-
if (!Number.isSafeInteger(assignment.proplannerId) || assignment.proplannerId <= 0 || seenBackendIds.has(assignment.proplannerId)) {
|
|
18440
|
-
throw new Error(
|
|
18441
|
-
`acknowledgePersistence: invalid or duplicate ${entityName} proplannerId ${String(assignment.proplannerId)}`
|
|
18442
|
-
);
|
|
18443
|
-
}
|
|
18444
|
-
const state = readCurrent(id);
|
|
18445
|
-
if (!state.exists) {
|
|
18446
|
-
throw new Error(
|
|
18447
|
-
`acknowledgePersistence: unknown ${entityName} id "${id}"`
|
|
18448
|
-
);
|
|
18449
|
-
}
|
|
18450
|
-
if (state.current !== null && state.current !== assignment.proplannerId) {
|
|
18451
|
-
throw new Error(
|
|
18452
|
-
`acknowledgePersistence: ${entityName} "${id}" already has proplannerId ${String(state.current)}`
|
|
18453
|
-
);
|
|
18454
|
-
}
|
|
18455
|
-
const existingOwner = ownerByBackendId.get(assignment.proplannerId);
|
|
18456
|
-
if (existingOwner !== void 0 && existingOwner !== id) {
|
|
18457
|
-
throw new Error(
|
|
18458
|
-
`acknowledgePersistence: ${entityName} proplannerId ${String(assignment.proplannerId)} already belongs to "${existingOwner}"`
|
|
18459
|
-
);
|
|
18460
|
-
}
|
|
18461
|
-
seenIds.add(id);
|
|
18462
|
-
seenBackendIds.add(assignment.proplannerId);
|
|
18463
|
-
}
|
|
18464
|
-
}
|
|
18465
18952
|
var ScheduleCore = class {
|
|
18466
18953
|
_status = SCHEDULE_CORE_STATUS.READY;
|
|
18467
|
-
/** True while an async dispatch is suspended inside the write-capture window.
|
|
18468
|
-
* A sync facade mutation running in that gap would corrupt the in-flight
|
|
18469
|
-
* journal, so sync mutators refuse to run while it is set. */
|
|
18470
|
-
_dispatchInFlight = false;
|
|
18471
18954
|
coreRuntime;
|
|
18472
18955
|
_undo = new UndoRecorder();
|
|
18473
18956
|
_opQueue = Promise.resolve();
|
|
@@ -18518,7 +19001,7 @@ var ScheduleCore = class {
|
|
|
18518
19001
|
return this._status;
|
|
18519
19002
|
}
|
|
18520
19003
|
getSector() {
|
|
18521
|
-
return this.coreRuntime.sector;
|
|
19004
|
+
return cloneDomainValue(this.coreRuntime.sector);
|
|
18522
19005
|
}
|
|
18523
19006
|
getActivityView(id) {
|
|
18524
19007
|
this.assertReady();
|
|
@@ -18544,7 +19027,7 @@ var ScheduleCore = class {
|
|
|
18544
19027
|
this.assertReady();
|
|
18545
19028
|
const snapshot = this.coreRuntime.state.getActivity(activityId);
|
|
18546
19029
|
if (!snapshot) return null;
|
|
18547
|
-
return snapshot[property];
|
|
19030
|
+
return cloneDomainValue(snapshot[property]);
|
|
18548
19031
|
}
|
|
18549
19032
|
getAllIds() {
|
|
18550
19033
|
this.assertReady();
|
|
@@ -18571,7 +19054,7 @@ var ScheduleCore = class {
|
|
|
18571
19054
|
*/
|
|
18572
19055
|
getVisualOrderIds() {
|
|
18573
19056
|
this.assertReady();
|
|
18574
|
-
return this.coreRuntime.state.getVisualOrderIds();
|
|
19057
|
+
return [...this.coreRuntime.state.getVisualOrderIds()];
|
|
18575
19058
|
}
|
|
18576
19059
|
hasChild(parentId) {
|
|
18577
19060
|
this.assertReady();
|
|
@@ -18579,15 +19062,21 @@ var ScheduleCore = class {
|
|
|
18579
19062
|
}
|
|
18580
19063
|
getCalendar(id) {
|
|
18581
19064
|
this.assertReady();
|
|
18582
|
-
|
|
19065
|
+
const calendar = this.coreRuntime.calendars.get(id);
|
|
19066
|
+
return calendar ? cloneDomainValue(calendar) : null;
|
|
18583
19067
|
}
|
|
18584
19068
|
getAllCalendars() {
|
|
18585
19069
|
this.assertReady();
|
|
18586
|
-
return Array.from(
|
|
19070
|
+
return Array.from(
|
|
19071
|
+
this.coreRuntime.calendars.values(),
|
|
19072
|
+
(calendar) => cloneDomainValue(calendar)
|
|
19073
|
+
);
|
|
18587
19074
|
}
|
|
18588
19075
|
getBaseCalendars() {
|
|
18589
19076
|
this.assertReady();
|
|
18590
|
-
return this.coreRuntime.baseCalendars
|
|
19077
|
+
return this.coreRuntime.baseCalendars.map(
|
|
19078
|
+
(calendar) => cloneDomainValue(calendar)
|
|
19079
|
+
);
|
|
18591
19080
|
}
|
|
18592
19081
|
isCustomIdInUse(customId, currentCustomId = null) {
|
|
18593
19082
|
this.assertReady();
|
|
@@ -18604,184 +19093,9 @@ var ScheduleCore = class {
|
|
|
18604
19093
|
this.assertReady();
|
|
18605
19094
|
return this._saveTracker.modifiedLinks(this.getAllLinksView());
|
|
18606
19095
|
}
|
|
18607
|
-
markLinksPersisted() {
|
|
18608
|
-
this._saveTracker.snapshotLinks(this.getAllLinksView());
|
|
18609
|
-
}
|
|
18610
19096
|
getModifiedActivities() {
|
|
18611
19097
|
this.assertReady();
|
|
18612
|
-
return this._saveTracker.modifiedActivities(
|
|
18613
|
-
this.coreRuntime.state.getAllActivities()
|
|
18614
|
-
);
|
|
18615
|
-
}
|
|
18616
|
-
markActivitiesPersisted() {
|
|
18617
|
-
this._saveTracker.snapshotActivities(
|
|
18618
|
-
this.coreRuntime.state.getAllActivities()
|
|
18619
|
-
);
|
|
18620
|
-
}
|
|
18621
|
-
/**
|
|
18622
|
-
* Reconciles the backend identities returned by a successful schedule save.
|
|
18623
|
-
*
|
|
18624
|
-
* This is an application-boundary acknowledgement, not an editable schedule
|
|
18625
|
-
* gesture: it does not autoschedule, recompute, emit an undo entry, or invent
|
|
18626
|
-
* domain changes. Every assignment is validated before the first mutation so
|
|
18627
|
-
* a malformed/partial response cannot leave the core half-reconciled. Once
|
|
18628
|
-
* applied, the complete live graph becomes the new save-tracker baseline.
|
|
18629
|
-
*/
|
|
18630
|
-
acknowledgePersistence(acknowledgement) {
|
|
18631
|
-
this.assertReady();
|
|
18632
|
-
const activities = acknowledgement.activities ?? [];
|
|
18633
|
-
const links = acknowledgement.links ?? [];
|
|
18634
|
-
const activityOwnerByBackendId = /* @__PURE__ */ new Map();
|
|
18635
|
-
for (const activity of this.coreRuntime.state.getAllActivities()) {
|
|
18636
|
-
if (activity.proplannerId != null) {
|
|
18637
|
-
activityOwnerByBackendId.set(
|
|
18638
|
-
activity.proplannerId,
|
|
18639
|
-
String(activity.id)
|
|
18640
|
-
);
|
|
18641
|
-
}
|
|
18642
|
-
}
|
|
18643
|
-
const linkOwnerByBackendId = /* @__PURE__ */ new Map();
|
|
18644
|
-
for (const link of this.coreRuntime.state.getAllLinks()) {
|
|
18645
|
-
if (link.proplannerId != null) {
|
|
18646
|
-
linkOwnerByBackendId.set(link.proplannerId, String(link.id));
|
|
18647
|
-
}
|
|
18648
|
-
}
|
|
18649
|
-
assertValidPersistenceAssignments(
|
|
18650
|
-
activities,
|
|
18651
|
-
"activity",
|
|
18652
|
-
(id) => {
|
|
18653
|
-
const activity = this.coreRuntime.state.getActivity(id);
|
|
18654
|
-
return {
|
|
18655
|
-
exists: activity !== null,
|
|
18656
|
-
current: activity?.proplannerId ?? null
|
|
18657
|
-
};
|
|
18658
|
-
},
|
|
18659
|
-
activityOwnerByBackendId
|
|
18660
|
-
);
|
|
18661
|
-
assertValidPersistenceAssignments(
|
|
18662
|
-
links,
|
|
18663
|
-
"link",
|
|
18664
|
-
(id) => {
|
|
18665
|
-
const link = this.coreRuntime.state.getLink(id);
|
|
18666
|
-
return {
|
|
18667
|
-
exists: link !== null,
|
|
18668
|
-
current: link?.proplannerId ?? null
|
|
18669
|
-
};
|
|
18670
|
-
},
|
|
18671
|
-
linkOwnerByBackendId
|
|
18672
|
-
);
|
|
18673
|
-
this.coreRuntime.state.batchUpdate(() => {
|
|
18674
|
-
for (const assignment of activities) {
|
|
18675
|
-
this.coreRuntime.state.setActivityField(
|
|
18676
|
-
assignment.id,
|
|
18677
|
-
"proplannerId",
|
|
18678
|
-
assignment.proplannerId
|
|
18679
|
-
);
|
|
18680
|
-
}
|
|
18681
|
-
for (const assignment of links) {
|
|
18682
|
-
this.coreRuntime.state.setLinkProplannerId(
|
|
18683
|
-
assignment.id,
|
|
18684
|
-
assignment.proplannerId
|
|
18685
|
-
);
|
|
18686
|
-
}
|
|
18687
|
-
});
|
|
18688
|
-
this.markActivitiesPersisted();
|
|
18689
|
-
this.markLinksPersisted();
|
|
18690
|
-
}
|
|
18691
|
-
applyBaselines(points) {
|
|
18692
|
-
this.assertReady();
|
|
18693
|
-
const now = this.coreRuntime.clock ? endOfLocalDay(this.coreRuntime.clock()) : null;
|
|
18694
|
-
const defaultBaseCalendarId = this.coreRuntime.baseCalendars.find((calendar) => calendar.baseDefault)?.id ?? null;
|
|
18695
|
-
return applyBaselines(
|
|
18696
|
-
this.coreRuntime.state,
|
|
18697
|
-
this.coreRuntime.sector.hoursPerDay,
|
|
18698
|
-
points,
|
|
18699
|
-
now,
|
|
18700
|
-
this.coreRuntime.reporter,
|
|
18701
|
-
defaultBaseCalendarId
|
|
18702
|
-
);
|
|
18703
|
-
}
|
|
18704
|
-
/**
|
|
18705
|
-
* Whole-tree ponderator recompute (zeroes, then redistributes 100 within
|
|
18706
|
-
* each parent from its children's active baselines, weighted by `criterion`).
|
|
18707
|
-
* Returns the activities whose `ponderator` changed, for a prop-only repaint.
|
|
18708
|
-
* The base rollup (`applyBaselines`) depends on fresh ponderators, so callers
|
|
18709
|
-
* run this before it on a criterion change or baseline save.
|
|
18710
|
-
*/
|
|
18711
|
-
recomputeAllPonderators(criterion) {
|
|
18712
|
-
this.assertReady();
|
|
18713
|
-
return recomputeAllPonderators2(
|
|
18714
|
-
this.coreRuntime.state,
|
|
18715
|
-
this.coreRuntime.sector.hoursPerDay,
|
|
18716
|
-
criterion
|
|
18717
|
-
);
|
|
18718
|
-
}
|
|
18719
|
-
/**
|
|
18720
|
-
* Recompute the weighted-progress rollup of every parent, bottom-up.
|
|
18721
|
-
* Returns the activities whose `progress` changed, for a prop-only repaint.
|
|
18722
|
-
*/
|
|
18723
|
-
recomputeAllProgressRollup() {
|
|
18724
|
-
this.assertReady();
|
|
18725
|
-
return recomputeAllProgressRollup2(
|
|
18726
|
-
this.coreRuntime.state,
|
|
18727
|
-
this.coreRuntime.sector.hoursPerDay
|
|
18728
|
-
);
|
|
18729
|
-
}
|
|
18730
|
-
/**
|
|
18731
|
-
* Set the project's status criterion (the Baseline↔Actual toggle) and
|
|
18732
|
-
* recompute every activity's `status` against it. Stores the criterion so
|
|
18733
|
-
* future dispatches keep deriving status with it. Returns the activities
|
|
18734
|
-
* whose `status` changed, for a prop-only repaint.
|
|
18735
|
-
*/
|
|
18736
|
-
setStatusCriteria(criteria) {
|
|
18737
|
-
this.assertReady();
|
|
18738
|
-
const resolved = resolveStatusCriteria(criteria);
|
|
18739
|
-
this.coreRuntime.sector.statusCriteria = resolved;
|
|
18740
|
-
return recomputeStatus(
|
|
18741
|
-
this.coreRuntime.state,
|
|
18742
|
-
this.coreRuntime.sector.hoursPerDay,
|
|
18743
|
-
resolved
|
|
18744
|
-
);
|
|
18745
|
-
}
|
|
18746
|
-
allocateActivityId() {
|
|
18747
|
-
this.assertReady();
|
|
18748
|
-
return this.coreRuntime.activityIdGenerator.next();
|
|
18749
|
-
}
|
|
18750
|
-
createActivity(input) {
|
|
18751
|
-
this.assertReady();
|
|
18752
|
-
if (this._dispatchInFlight) {
|
|
18753
|
-
throw new Error(
|
|
18754
|
-
"[ScheduleCore] createActivity called during an in-flight dispatch"
|
|
18755
|
-
);
|
|
18756
|
-
}
|
|
18757
|
-
const action = { kind: "activity-create", ...input };
|
|
18758
|
-
this.coreRuntime.state.beginWriteCapture();
|
|
18759
|
-
this.coreRuntime.customIdTracker.beginCustomIdTransaction();
|
|
18760
|
-
let result;
|
|
18761
|
-
try {
|
|
18762
|
-
result = createActivitySync(action, {
|
|
18763
|
-
adapter: this.coreRuntime.state,
|
|
18764
|
-
scheduler: this.coreRuntime.scheduler,
|
|
18765
|
-
sector: this.coreRuntime.sector,
|
|
18766
|
-
calendars: this.coreRuntime.calendars,
|
|
18767
|
-
activityIdGen: this.coreRuntime.activityIdGenerator,
|
|
18768
|
-
uidGen: this.coreRuntime.uniqueCorrelativeIdGenerator,
|
|
18769
|
-
customIdTracker: this.coreRuntime.customIdTracker
|
|
18770
|
-
});
|
|
18771
|
-
if (!result.ok) this._rollback();
|
|
18772
|
-
} catch (error) {
|
|
18773
|
-
this._rollback();
|
|
18774
|
-
throw error;
|
|
18775
|
-
} finally {
|
|
18776
|
-
this.coreRuntime.state.endWriteCapture();
|
|
18777
|
-
this.coreRuntime.customIdTracker.commitCustomIdTransaction();
|
|
18778
|
-
}
|
|
18779
|
-
if (!result.ok) return result;
|
|
18780
|
-
return {
|
|
18781
|
-
ok: true,
|
|
18782
|
-
activity: result.activity,
|
|
18783
|
-
changes: result.changes
|
|
18784
|
-
};
|
|
19098
|
+
return this._saveTracker.modifiedActivities(this.coreRuntime.state.getAllActivities()).map(cloneDomainValue);
|
|
18785
19099
|
}
|
|
18786
19100
|
_enqueue(work) {
|
|
18787
19101
|
const workPromise = this._opQueue.then(work, work);
|
|
@@ -18801,10 +19115,9 @@ var ScheduleCore = class {
|
|
|
18801
19115
|
dateFormat: this.coreRuntime.sector.dateFormat,
|
|
18802
19116
|
inputUnit: options.inputUnit ?? "days"
|
|
18803
19117
|
});
|
|
18804
|
-
const
|
|
19118
|
+
const historyPolicy = getDispatchHistoryPolicy(action);
|
|
18805
19119
|
this.coreRuntime.state.beginWriteCapture();
|
|
18806
19120
|
this.coreRuntime.customIdTracker.beginCustomIdTransaction();
|
|
18807
|
-
this._dispatchInFlight = true;
|
|
18808
19121
|
let result;
|
|
18809
19122
|
try {
|
|
18810
19123
|
result = await dispatch(action, options, {
|
|
@@ -18817,6 +19130,7 @@ var ScheduleCore = class {
|
|
|
18817
19130
|
linkIdGen: this.coreRuntime.linkIdGenerator,
|
|
18818
19131
|
uidGen: this.coreRuntime.uniqueCorrelativeIdGenerator,
|
|
18819
19132
|
customIdTracker: this.coreRuntime.customIdTracker,
|
|
19133
|
+
reporter: this.coreRuntime.reporter,
|
|
18820
19134
|
defaultBaseCalendarId: this.coreRuntime.baseCalendars.find(
|
|
18821
19135
|
(calendar) => calendar.baseDefault
|
|
18822
19136
|
)?.id ?? null,
|
|
@@ -18827,11 +19141,10 @@ var ScheduleCore = class {
|
|
|
18827
19141
|
this._rollback();
|
|
18828
19142
|
throw error;
|
|
18829
19143
|
} finally {
|
|
18830
|
-
this._dispatchInFlight = false;
|
|
18831
19144
|
this.coreRuntime.state.endWriteCapture();
|
|
18832
19145
|
this.coreRuntime.customIdTracker.commitCustomIdTransaction();
|
|
18833
19146
|
}
|
|
18834
|
-
if (result.ok &&
|
|
19147
|
+
if (result.ok && historyPolicy === "record" && changeSetIsSubstantive(result.changes)) {
|
|
18835
19148
|
const created = captureCreatedSnapshots(
|
|
18836
19149
|
this.coreRuntime.state,
|
|
18837
19150
|
result.changes
|
|
@@ -18848,11 +19161,18 @@ var ScheduleCore = class {
|
|
|
18848
19161
|
Date.now()
|
|
18849
19162
|
);
|
|
18850
19163
|
}
|
|
19164
|
+
if (result.ok && historyPolicy === "clear-on-success") {
|
|
19165
|
+
this._saveTracker.snapshotActivities(
|
|
19166
|
+
this.coreRuntime.state.getAllActivities()
|
|
19167
|
+
);
|
|
19168
|
+
this._saveTracker.snapshotLinks(this.getAllLinksView());
|
|
19169
|
+
this._undo.clear();
|
|
19170
|
+
}
|
|
18851
19171
|
if (!result.ok) return result;
|
|
18852
|
-
if (changeSetIsSubstantive(result.changes)) {
|
|
19172
|
+
if (dispatchChangesSchedulingState(action) && changeSetIsSubstantive(result.changes)) {
|
|
18853
19173
|
this._recordScheduleMutation(options.skipCriticalPath !== true);
|
|
18854
19174
|
}
|
|
18855
|
-
return
|
|
19175
|
+
return cloneDomainValue(result);
|
|
18856
19176
|
}
|
|
18857
19177
|
/**
|
|
18858
19178
|
* Starts or joins the Critical Path calculation for the current schedule
|
|
@@ -18862,9 +19182,11 @@ var ScheduleCore = class {
|
|
|
18862
19182
|
* ineligible to commit.
|
|
18863
19183
|
*/
|
|
18864
19184
|
recomputeCriticalPath() {
|
|
18865
|
-
|
|
19185
|
+
const operation = this._enqueue(async () => ({
|
|
18866
19186
|
job: this._startCriticalPathForCurrentRevision()
|
|
18867
19187
|
})).then(({ job }) => job);
|
|
19188
|
+
this._criticalPathReady = operation;
|
|
19189
|
+
return operation;
|
|
18868
19190
|
}
|
|
18869
19191
|
isCriticalPathSettled() {
|
|
18870
19192
|
return this._criticalPathRevision === this._scheduleRevision && this._activeCriticalPath === null;
|
|
@@ -18985,12 +19307,42 @@ var ScheduleCore = class {
|
|
|
18985
19307
|
}
|
|
18986
19308
|
return { changes };
|
|
18987
19309
|
}
|
|
19310
|
+
/**
|
|
19311
|
+
* Undo/Redo restores the user's historical mutation while retaining current
|
|
19312
|
+
* non-historical truth (for example a refreshed baseline). Re-derive every
|
|
19313
|
+
* value that depends on both so the restored model is immediately coherent.
|
|
19314
|
+
*/
|
|
19315
|
+
_recomputeAfterHistoryRestore() {
|
|
19316
|
+
const state = this.coreRuntime.state;
|
|
19317
|
+
recomputeAllProgressRollup(state);
|
|
19318
|
+
recomputeCanonicalRealWork(state);
|
|
19319
|
+
emitRealCost(state);
|
|
19320
|
+
if (this.coreRuntime.clock) {
|
|
19321
|
+
const now = endOfLocalDay(this.coreRuntime.clock());
|
|
19322
|
+
applyExpectedProgressLive(state, now);
|
|
19323
|
+
let hasActiveBaseline2 = false;
|
|
19324
|
+
state.forEachActivity((activity) => {
|
|
19325
|
+
hasActiveBaseline2 ||= getActiveBaseline(activity) !== null;
|
|
19326
|
+
});
|
|
19327
|
+
if (hasActiveBaseline2) {
|
|
19328
|
+
runExpectedProgressBase(
|
|
19329
|
+
state,
|
|
19330
|
+
now,
|
|
19331
|
+
this.coreRuntime.baseCalendars.find(
|
|
19332
|
+
(calendar) => calendar.baseDefault
|
|
19333
|
+
)?.id ?? null
|
|
19334
|
+
);
|
|
19335
|
+
}
|
|
19336
|
+
applyStatusPass(state, this.coreRuntime.sector.statusCriteria);
|
|
19337
|
+
}
|
|
19338
|
+
}
|
|
18988
19339
|
undo() {
|
|
18989
19340
|
const operation = this._enqueue(async () => {
|
|
18990
19341
|
this.assertReady();
|
|
18991
19342
|
const entry = this._undo.takeUndo();
|
|
18992
19343
|
if (!entry) return null;
|
|
18993
19344
|
applyUndo(this.coreRuntime.state, entry);
|
|
19345
|
+
this._recomputeAfterHistoryRestore();
|
|
18994
19346
|
this._recordScheduleMutation(false);
|
|
18995
19347
|
if (needsResync(entry)) this._resyncCustomIdTrackerFromModel();
|
|
18996
19348
|
this._undo.pushRedo(entry);
|
|
@@ -19018,6 +19370,7 @@ var ScheduleCore = class {
|
|
|
19018
19370
|
const entry = this._undo.takeRedo();
|
|
19019
19371
|
if (!entry) return null;
|
|
19020
19372
|
applyRedo(this.coreRuntime.state, entry);
|
|
19373
|
+
this._recomputeAfterHistoryRestore();
|
|
19021
19374
|
this._recordScheduleMutation(false);
|
|
19022
19375
|
if (needsResync(entry)) this._resyncCustomIdTrackerFromModel();
|
|
19023
19376
|
this._undo.pushUndo(entry);
|
|
@@ -19039,15 +19392,20 @@ var ScheduleCore = class {
|
|
|
19039
19392
|
);
|
|
19040
19393
|
return operation;
|
|
19041
19394
|
}
|
|
19042
|
-
clearHistory() {
|
|
19043
|
-
this._undo.clear();
|
|
19044
|
-
}
|
|
19045
19395
|
canUndo() {
|
|
19046
19396
|
return this._undo.canUndo();
|
|
19047
19397
|
}
|
|
19048
19398
|
canRedo() {
|
|
19049
19399
|
return this._undo.canRedo();
|
|
19050
19400
|
}
|
|
19401
|
+
/**
|
|
19402
|
+
* Establishes a new persistence boundary without mutating schedule state.
|
|
19403
|
+
* Completed saves call this synchronously so neither prior undo entries nor
|
|
19404
|
+
* their redo branch can cross the persisted boundary.
|
|
19405
|
+
*/
|
|
19406
|
+
clearHistory() {
|
|
19407
|
+
this._undo.clear();
|
|
19408
|
+
}
|
|
19051
19409
|
undoDepth() {
|
|
19052
19410
|
return this._undo.undoDepth();
|
|
19053
19411
|
}
|
|
@@ -19133,6 +19491,10 @@ var DEFAULT_HOURS_PER_DAY = 8;
|
|
|
19133
19491
|
|
|
19134
19492
|
// src/dispatch/action-kinds.ts
|
|
19135
19493
|
var DISPATCH_ACTION_KIND = {
|
|
19494
|
+
PERSISTENCE_ACKNOWLEDGE: "persistence-acknowledge",
|
|
19495
|
+
BASELINE_APPLY: "baseline-apply",
|
|
19496
|
+
PONDERATOR_CRITERION_SET: "ponderator-criterion-set",
|
|
19497
|
+
STATUS_CRITERIA_SET: "status-criteria-set",
|
|
19136
19498
|
INLINE_EDIT: "inline-edit",
|
|
19137
19499
|
DATES_BATCH: "dates-batch",
|
|
19138
19500
|
BULK_EDIT: "bulk-edit",
|
|
@@ -19154,6 +19516,10 @@ var DISPATCH_ACTION_KIND = {
|
|
|
19154
19516
|
ACTIVITY_LOOKAHEAD_SYNC: "activity-lookahead-sync"
|
|
19155
19517
|
};
|
|
19156
19518
|
var KIND_CATALOG_COVERS_UNION = {
|
|
19519
|
+
[DISPATCH_ACTION_KIND.PERSISTENCE_ACKNOWLEDGE]: true,
|
|
19520
|
+
[DISPATCH_ACTION_KIND.BASELINE_APPLY]: true,
|
|
19521
|
+
[DISPATCH_ACTION_KIND.PONDERATOR_CRITERION_SET]: true,
|
|
19522
|
+
[DISPATCH_ACTION_KIND.STATUS_CRITERIA_SET]: true,
|
|
19157
19523
|
[DISPATCH_ACTION_KIND.INLINE_EDIT]: true,
|
|
19158
19524
|
[DISPATCH_ACTION_KIND.DATES_BATCH]: true,
|
|
19159
19525
|
[DISPATCH_ACTION_KIND.BULK_EDIT]: true,
|
|
@@ -19202,7 +19568,6 @@ exports.REJECTION_REASON = REJECTION_REASON;
|
|
|
19202
19568
|
exports.ROOT_PARENT_ID = ROOT_PARENT_ID;
|
|
19203
19569
|
exports.ScheduleCore = ScheduleCore;
|
|
19204
19570
|
exports.WORK_TIME_DIRECTION = WORK_TIME_DIRECTION;
|
|
19205
|
-
exports.applyBaselinePoints = applyBaselinePoints;
|
|
19206
19571
|
exports.checkNoUpdatedLinks = checkNoUpdatedLinks;
|
|
19207
19572
|
exports.computeExpectedProgress = computeExpectedProgress;
|
|
19208
19573
|
exports.expectedProgressFromBaseline = expectedProgressFromBaseline;
|
|
@@ -19211,8 +19576,6 @@ exports.getUnsavedActivities = getUnsavedActivities;
|
|
|
19211
19576
|
exports.isRootParent = isRootParent;
|
|
19212
19577
|
exports.normalizeParentKey = normalizeParentKey;
|
|
19213
19578
|
exports.parseFromBackend = parseFromBackend;
|
|
19214
|
-
exports.recomputeAllPonderators = recomputeAllPonderators;
|
|
19215
|
-
exports.recomputeAllProgressRollup = recomputeAllProgressRollup;
|
|
19216
19579
|
exports.willRunCriticalPath = willRunCriticalPath;
|
|
19217
19580
|
exports.yieldToBrowser = yieldToBrowser;
|
|
19218
19581
|
//# sourceMappingURL=index.cjs.map
|