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