@outbuild-company/schedule-core 1.24.0 → 1.26.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 +167 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +25 -5
- package/dist/index.d.ts +25 -5
- package/dist/index.js +167 -52
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -630,17 +630,19 @@ function createActivitiesApi(engine) {
|
|
|
630
630
|
}
|
|
631
631
|
function createCellsApi(engine) {
|
|
632
632
|
return {
|
|
633
|
-
copy: (activityId, column, context = {}) => engine.dispatch({
|
|
633
|
+
copy: (activityId, column, copiedText, context = {}) => engine.dispatch({
|
|
634
634
|
...context,
|
|
635
635
|
kind: DISPATCH_ACTION_KIND.CELL_COPY,
|
|
636
636
|
activityId,
|
|
637
|
-
column
|
|
637
|
+
column,
|
|
638
|
+
...copiedText === void 0 ? {} : { copiedText }
|
|
638
639
|
}),
|
|
639
|
-
paste: (activityIds, column, context = {}) => engine.dispatch({
|
|
640
|
+
paste: (activityIds, column, clipboardText, context = {}) => engine.dispatch({
|
|
640
641
|
...context,
|
|
641
642
|
kind: DISPATCH_ACTION_KIND.CELL_PASTE_COPIED,
|
|
642
643
|
activityIds,
|
|
643
|
-
column
|
|
644
|
+
column,
|
|
645
|
+
...clipboardText === void 0 ? {} : { clipboardText }
|
|
644
646
|
}),
|
|
645
647
|
clearClipboard: (context = {}) => engine.dispatch({
|
|
646
648
|
...context,
|
|
@@ -957,6 +959,7 @@ var REJECTION_REASON = {
|
|
|
957
959
|
NO_ACTIVITY_SELECTION: "no_activity_selection",
|
|
958
960
|
CLIPBOARD_EMPTY: "clipboard_empty",
|
|
959
961
|
CLIPBOARD_SNAPSHOT_INVALID: "clipboard_snapshot_invalid",
|
|
962
|
+
CELL_PASTE_COLUMN_MISMATCH: "cell_paste_column_mismatch",
|
|
960
963
|
ACTIVITY_PASTE_INVARIANT_FAILED: "activity_paste_invariant_failed",
|
|
961
964
|
SOLE_SCHEDULE_ROOT: "sole_schedule_root",
|
|
962
965
|
ANCHOR_SIBLING_CONFLICT: "anchor_sibling_conflict",
|
|
@@ -6287,7 +6290,9 @@ var P6_PERCENT_COMPLETE_TYPE = {
|
|
|
6287
6290
|
var P6_ACTIVITY_TYPE = {
|
|
6288
6291
|
TASK: "task",
|
|
6289
6292
|
LEVEL_OF_EFFORT: "level_of_effort",
|
|
6290
|
-
START_MILESTONE: "start_milestone"
|
|
6293
|
+
START_MILESTONE: "start_milestone",
|
|
6294
|
+
RESOURCE_DEPENDENT: "resource_dependent"
|
|
6295
|
+
};
|
|
6291
6296
|
var P6_EXECUTION_STATUS = {
|
|
6292
6297
|
NOT_STARTED: "not_started",
|
|
6293
6298
|
IN_PROGRESS: "in_progress",
|
|
@@ -18016,6 +18021,7 @@ var LOAD_DIAGNOSTIC_SAMPLE_LIMIT = 10;
|
|
|
18016
18021
|
var LOAD_DIAGNOSTIC_CODE = {
|
|
18017
18022
|
INVALID_BASELINE_POINT: "invalid_baseline_point",
|
|
18018
18023
|
UNKNOWN_CONSTRAINT: "unknown_constraint",
|
|
18024
|
+
PROGRESS_OUT_OF_RANGE: "progress_out_of_range",
|
|
18019
18025
|
ORPHAN_ACTIVITY: "orphan_activity",
|
|
18020
18026
|
INVALID_LINK: "invalid_link",
|
|
18021
18027
|
DUPLICATE_LINK: "duplicate_link"
|
|
@@ -18023,6 +18029,7 @@ var LOAD_DIAGNOSTIC_CODE = {
|
|
|
18023
18029
|
var LOAD_DIAGNOSTIC_CODE_ORDER = [
|
|
18024
18030
|
LOAD_DIAGNOSTIC_CODE.INVALID_BASELINE_POINT,
|
|
18025
18031
|
LOAD_DIAGNOSTIC_CODE.UNKNOWN_CONSTRAINT,
|
|
18032
|
+
LOAD_DIAGNOSTIC_CODE.PROGRESS_OUT_OF_RANGE,
|
|
18026
18033
|
LOAD_DIAGNOSTIC_CODE.ORPHAN_ACTIVITY,
|
|
18027
18034
|
LOAD_DIAGNOSTIC_CODE.INVALID_LINK,
|
|
18028
18035
|
LOAD_DIAGNOSTIC_CODE.DUPLICATE_LINK
|
|
@@ -19008,7 +19015,12 @@ function dispatchCellCopy(action, deps) {
|
|
|
19008
19015
|
return { ok: false, reason: REJECTION_REASON.INVALID_VALUE };
|
|
19009
19016
|
}
|
|
19010
19017
|
const raw = action.column === COLUMN.DURATION ? canonicalValue / deps.hoursPerDay : cloneDomainValue(canonicalValue);
|
|
19011
|
-
deps.clipboard.value = {
|
|
19018
|
+
deps.clipboard.value = {
|
|
19019
|
+
kind: CELL_CLIPBOARD_KIND.FIELD,
|
|
19020
|
+
raw,
|
|
19021
|
+
sourceColumn: action.column,
|
|
19022
|
+
text: action.copiedText ?? null
|
|
19023
|
+
};
|
|
19012
19024
|
return emptyChangeSet(action);
|
|
19013
19025
|
}
|
|
19014
19026
|
function dispatchCellClipboardClear(action, clipboard) {
|
|
@@ -19017,6 +19029,39 @@ function dispatchCellClipboardClear(action, clipboard) {
|
|
|
19017
19029
|
}
|
|
19018
19030
|
|
|
19019
19031
|
// src/cell-copy-paste/paste.ts
|
|
19032
|
+
var RESTRICTED_CELL_COLUMNS = /* @__PURE__ */ new Set([
|
|
19033
|
+
COLUMN.TAGS,
|
|
19034
|
+
COLUMN.RESPONSABLES,
|
|
19035
|
+
COLUMN.SUBCONTRACT_ID,
|
|
19036
|
+
COLUMN.CONSTRAINT_TYPE,
|
|
19037
|
+
COLUMN.CALENDAR_ID
|
|
19038
|
+
]);
|
|
19039
|
+
function isIncompatibleCellPaste(sourceColumn, targetColumn) {
|
|
19040
|
+
if (sourceColumn === targetColumn) return false;
|
|
19041
|
+
return RESTRICTED_CELL_COLUMNS.has(sourceColumn) || RESTRICTED_CELL_COLUMNS.has(targetColumn);
|
|
19042
|
+
}
|
|
19043
|
+
function resolveExternalPasteText(stashedField, clipboardText) {
|
|
19044
|
+
if (clipboardText === void 0) return null;
|
|
19045
|
+
const rawIsTrustworthy = stashedField !== null && (stashedField.text === null || stashedField.text === clipboardText);
|
|
19046
|
+
return rawIsTrustworthy ? null : clipboardText;
|
|
19047
|
+
}
|
|
19048
|
+
function resolveFieldPasteValue(clipboard, column, clipboardText) {
|
|
19049
|
+
const stashedField = clipboard !== null && clipboard.kind === CELL_CLIPBOARD_KIND.FIELD ? clipboard : null;
|
|
19050
|
+
const externalText = resolveExternalPasteText(stashedField, clipboardText);
|
|
19051
|
+
if (externalText !== null) {
|
|
19052
|
+
return { ok: true, newValue: externalText };
|
|
19053
|
+
}
|
|
19054
|
+
if (clipboard !== null && clipboard.kind !== CELL_CLIPBOARD_KIND.FIELD) {
|
|
19055
|
+
return { ok: false, reason: REJECTION_REASON.INVALID_VALUE };
|
|
19056
|
+
}
|
|
19057
|
+
if (stashedField === null) {
|
|
19058
|
+
return { ok: false, reason: REJECTION_REASON.CLIPBOARD_EMPTY };
|
|
19059
|
+
}
|
|
19060
|
+
if (isIncompatibleCellPaste(stashedField.sourceColumn, column)) {
|
|
19061
|
+
return { ok: false, reason: REJECTION_REASON.CELL_PASTE_COLUMN_MISMATCH };
|
|
19062
|
+
}
|
|
19063
|
+
return { ok: true, newValue: stashedField.raw };
|
|
19064
|
+
}
|
|
19020
19065
|
function toDiffPlaceholder(activityId) {
|
|
19021
19066
|
return String(activityId);
|
|
19022
19067
|
}
|
|
@@ -19049,11 +19094,45 @@ function linkOperationsForTarget(targetActivityId, isPredecessors, clipboard, de
|
|
|
19049
19094
|
});
|
|
19050
19095
|
return diff.operations;
|
|
19051
19096
|
}
|
|
19052
|
-
async function
|
|
19053
|
-
const clipboard = deps.cellClipboard.value;
|
|
19097
|
+
async function dispatchCellPasteLinkColumn(action, clipboard, options, deps) {
|
|
19054
19098
|
if (clipboard === null) {
|
|
19055
19099
|
return { ok: false, reason: REJECTION_REASON.CLIPBOARD_EMPTY };
|
|
19056
19100
|
}
|
|
19101
|
+
if (clipboard.kind !== CELL_CLIPBOARD_KIND.LINKS) {
|
|
19102
|
+
return { ok: false, reason: REJECTION_REASON.INVALID_VALUE };
|
|
19103
|
+
}
|
|
19104
|
+
const hasSelfReference = action.activityIds.some(
|
|
19105
|
+
(activityId) => clipboard.specs.some(
|
|
19106
|
+
(spec) => String(spec.otherActivityId) === String(activityId)
|
|
19107
|
+
)
|
|
19108
|
+
);
|
|
19109
|
+
if (hasSelfReference) {
|
|
19110
|
+
return { ok: false, reason: LINK_REJECTION_REASON.SELF_LINK };
|
|
19111
|
+
}
|
|
19112
|
+
const isPredecessors = action.column === COLUMN.CUSTOM_PREDECESSORS;
|
|
19113
|
+
const operations = action.activityIds.flatMap(
|
|
19114
|
+
(activityId) => linkOperationsForTarget(activityId, isPredecessors, clipboard, deps)
|
|
19115
|
+
);
|
|
19116
|
+
const createEntries = operations.filter(
|
|
19117
|
+
(operation) => operation.kind === LINK_OPERATION_KIND.CREATE
|
|
19118
|
+
).map((operation) => ({
|
|
19119
|
+
operation,
|
|
19120
|
+
linkId: deps.linkIdGen.next()
|
|
19121
|
+
}));
|
|
19122
|
+
const creation = validateLinkCreateBatch(createEntries, {
|
|
19123
|
+
port: deps.adapter,
|
|
19124
|
+
rejectParentLinkMutations: options.rejectParentLinkMutations ?? false
|
|
19125
|
+
});
|
|
19126
|
+
if (!creation.applied) {
|
|
19127
|
+
return {
|
|
19128
|
+
ok: false,
|
|
19129
|
+
reason: creation.rejected ?? REJECTION_REASON.INVALID
|
|
19130
|
+
};
|
|
19131
|
+
}
|
|
19132
|
+
return dispatchLinkBatch(operations, action, options, deps);
|
|
19133
|
+
}
|
|
19134
|
+
async function dispatchCellPasteCopied(action, options, deps) {
|
|
19135
|
+
const clipboard = deps.cellClipboard.value;
|
|
19057
19136
|
if (action.activityIds.length === 0) {
|
|
19058
19137
|
return { ok: false, reason: REJECTION_REASON.ACTIVITY_IDS_EMPTY };
|
|
19059
19138
|
}
|
|
@@ -19064,53 +19143,25 @@ async function dispatchCellPasteCopied(action, options, deps) {
|
|
|
19064
19143
|
return { ok: false, reason: REJECTION_REASON.ACTIVITY_NOT_FOUND };
|
|
19065
19144
|
}
|
|
19066
19145
|
if (action.column === COLUMN.CUSTOM_PREDECESSORS || action.column === COLUMN.CUSTOM_SUCESSORS) {
|
|
19067
|
-
|
|
19068
|
-
return { ok: false, reason: REJECTION_REASON.INVALID_VALUE };
|
|
19069
|
-
}
|
|
19070
|
-
const hasSelfReference = action.activityIds.some(
|
|
19071
|
-
(activityId) => clipboard.specs.some(
|
|
19072
|
-
(spec) => String(spec.otherActivityId) === String(activityId)
|
|
19073
|
-
)
|
|
19074
|
-
);
|
|
19075
|
-
if (hasSelfReference) {
|
|
19076
|
-
return { ok: false, reason: LINK_REJECTION_REASON.SELF_LINK };
|
|
19077
|
-
}
|
|
19078
|
-
const isPredecessors = action.column === COLUMN.CUSTOM_PREDECESSORS;
|
|
19079
|
-
const operations = action.activityIds.flatMap(
|
|
19080
|
-
(activityId) => linkOperationsForTarget(activityId, isPredecessors, clipboard, deps)
|
|
19081
|
-
);
|
|
19082
|
-
const createEntries = operations.filter(
|
|
19083
|
-
(operation) => operation.kind === LINK_OPERATION_KIND.CREATE
|
|
19084
|
-
).map((operation) => ({
|
|
19085
|
-
operation,
|
|
19086
|
-
linkId: deps.linkIdGen.next()
|
|
19087
|
-
}));
|
|
19088
|
-
const creation = validateLinkCreateBatch(createEntries, {
|
|
19089
|
-
port: deps.adapter,
|
|
19090
|
-
rejectParentLinkMutations: options.rejectParentLinkMutations ?? false
|
|
19091
|
-
});
|
|
19092
|
-
if (!creation.applied) {
|
|
19093
|
-
return {
|
|
19094
|
-
ok: false,
|
|
19095
|
-
reason: creation.rejected ?? REJECTION_REASON.INVALID
|
|
19096
|
-
};
|
|
19097
|
-
}
|
|
19098
|
-
return dispatchLinkBatch(operations, action, options, deps);
|
|
19099
|
-
}
|
|
19100
|
-
if (clipboard.kind !== CELL_CLIPBOARD_KIND.FIELD) {
|
|
19101
|
-
return { ok: false, reason: REJECTION_REASON.INVALID_VALUE };
|
|
19146
|
+
return dispatchCellPasteLinkColumn(action, clipboard, options, deps);
|
|
19102
19147
|
}
|
|
19103
19148
|
if (!findPipelineForColumn(action.column)) {
|
|
19104
19149
|
return { ok: false, reason: REJECTION_REASON.NO_PIPELINE_FOR_COLUMN };
|
|
19105
19150
|
}
|
|
19106
19151
|
const column = action.column;
|
|
19152
|
+
const resolution = resolveFieldPasteValue(
|
|
19153
|
+
clipboard,
|
|
19154
|
+
column,
|
|
19155
|
+
action.clipboardText
|
|
19156
|
+
);
|
|
19157
|
+
if (!resolution.ok) return resolution;
|
|
19107
19158
|
const result = await dispatchBulkEdit(
|
|
19108
19159
|
{
|
|
19109
19160
|
kind: DISPATCH_ACTION_KIND.BULK_EDIT,
|
|
19110
19161
|
edits: action.activityIds.map((activityId) => ({
|
|
19111
19162
|
activityId,
|
|
19112
19163
|
column,
|
|
19113
|
-
newValue:
|
|
19164
|
+
newValue: resolution.newValue
|
|
19114
19165
|
})),
|
|
19115
19166
|
...action.eventSource === void 0 ? {} : { eventSource: action.eventSource }
|
|
19116
19167
|
},
|
|
@@ -24828,12 +24879,21 @@ function normalizePersistedActivityId(rawId) {
|
|
|
24828
24879
|
}
|
|
24829
24880
|
return rawId;
|
|
24830
24881
|
}
|
|
24831
|
-
function parseProgress(raw) {
|
|
24882
|
+
function parseProgress(raw, reporter, recordDiagnostic, activityId) {
|
|
24832
24883
|
const progress = Number(raw);
|
|
24833
|
-
if (!Number.isFinite(progress)
|
|
24884
|
+
if (!Number.isFinite(progress)) {
|
|
24834
24885
|
throw new TypeError(`invalid activity progress ${String(raw)}`);
|
|
24835
24886
|
}
|
|
24836
|
-
|
|
24887
|
+
const isBelowNotStarted = progress < NOT_STARTED_PROGRESS;
|
|
24888
|
+
const isAboveCompleted = progress > MAX_TOLERATED_PROGRESS;
|
|
24889
|
+
const isWithinRange = !isBelowNotStarted && !isAboveCompleted;
|
|
24890
|
+
if (isWithinRange) return progress;
|
|
24891
|
+
const clamped = isBelowNotStarted ? NOT_STARTED_PROGRESS : COMPLETED_PROGRESS;
|
|
24892
|
+
recordDiagnostic(LOAD_DIAGNOSTIC_CODE.PROGRESS_OUT_OF_RANGE, activityId);
|
|
24893
|
+
reporter.warn(
|
|
24894
|
+
`[parseFromBackend] activity "${activityId}" progress ${String(raw)} is out of range \u2014 clamping to ${clamped}`
|
|
24895
|
+
);
|
|
24896
|
+
return clamped;
|
|
24837
24897
|
}
|
|
24838
24898
|
function parseCriticality(raw, reporter) {
|
|
24839
24899
|
if (typeof raw.is_critical === "boolean") return raw.is_critical;
|
|
@@ -24866,7 +24926,12 @@ function parseActivity(raw, context) {
|
|
|
24866
24926
|
context.defaultCalendarId
|
|
24867
24927
|
);
|
|
24868
24928
|
const inheritedDefaultCalendar = raw.calendarId == null || !context.knownCalendarIds.has(String(raw.calendarId));
|
|
24869
|
-
const progress = parseProgress(
|
|
24929
|
+
const progress = parseProgress(
|
|
24930
|
+
raw.progress,
|
|
24931
|
+
context.reporter,
|
|
24932
|
+
context.recordDiagnostic,
|
|
24933
|
+
String(raw.unique_id)
|
|
24934
|
+
);
|
|
24870
24935
|
const { constraintType, constraintDate } = resolveConstraint(
|
|
24871
24936
|
raw,
|
|
24872
24937
|
context.reporter,
|
|
@@ -30095,6 +30160,39 @@ function blockedActivities(code, message, activityIds, missingInputs = []) {
|
|
|
30095
30160
|
};
|
|
30096
30161
|
}
|
|
30097
30162
|
|
|
30163
|
+
// src/p6/rolled-expected-finish.ts
|
|
30164
|
+
var PINNABLE_ACTIVITY_TYPES = /* @__PURE__ */ new Set([
|
|
30165
|
+
P6_ACTIVITY_TYPE.TASK,
|
|
30166
|
+
P6_ACTIVITY_TYPE.RESOURCE_DEPENDENT
|
|
30167
|
+
]);
|
|
30168
|
+
var NO_ROLLED_EXPECTED_FINISHES = /* @__PURE__ */ new Map();
|
|
30169
|
+
function planRolledExpectedFinishes(input) {
|
|
30170
|
+
const adoptsShownFinishes = input.settings.useExpectedFinishDates && rollsDataDateForward(input.previousSettings, input.settings);
|
|
30171
|
+
if (!adoptsShownFinishes) return NO_ROLLED_EXPECTED_FINISHES;
|
|
30172
|
+
const pinned = /* @__PURE__ */ new Map();
|
|
30173
|
+
for (const [activityId, state] of input.activities) {
|
|
30174
|
+
const shownFinish = state.remainingEarlyFinish;
|
|
30175
|
+
if (shownFinish === null) continue;
|
|
30176
|
+
if (!needsExpectedFinishPin(state)) continue;
|
|
30177
|
+
pinned.set(activityId, new Date(shownFinish));
|
|
30178
|
+
}
|
|
30179
|
+
return pinned;
|
|
30180
|
+
}
|
|
30181
|
+
function rollsDataDateForward(previous, next) {
|
|
30182
|
+
const previousDataDate = previous.dataDate;
|
|
30183
|
+
const nextDataDate = next.dataDate;
|
|
30184
|
+
if (previousDataDate === null || nextDataDate === null) return false;
|
|
30185
|
+
return nextDataDate.getTime() > previousDataDate.getTime();
|
|
30186
|
+
}
|
|
30187
|
+
function needsExpectedFinishPin(state) {
|
|
30188
|
+
return state.executionStatus === P6_EXECUTION_STATUS.IN_PROGRESS && state.expectedFinish === null && hasPinnableActivityType(state);
|
|
30189
|
+
}
|
|
30190
|
+
function hasPinnableActivityType(state) {
|
|
30191
|
+
const { activityType } = state;
|
|
30192
|
+
if (activityType === void 0) return true;
|
|
30193
|
+
return PINNABLE_ACTIVITY_TYPES.has(activityType);
|
|
30194
|
+
}
|
|
30195
|
+
|
|
30098
30196
|
// src/p6/commands.ts
|
|
30099
30197
|
function dataDateScheduleReadiness(input) {
|
|
30100
30198
|
const preflight = getP6SchedulePreflight({
|
|
@@ -30208,8 +30306,17 @@ function prepareDataDateSchedule(input) {
|
|
|
30208
30306
|
preflight.settings,
|
|
30209
30307
|
beforeProjectState
|
|
30210
30308
|
);
|
|
30309
|
+
const rolledExpectedFinishes = planRolledExpectedFinishes({
|
|
30310
|
+
previousSettings: preflight.previousSettings,
|
|
30311
|
+
settings: preflight.settings,
|
|
30312
|
+
activities: preflight.activities
|
|
30313
|
+
});
|
|
30211
30314
|
const calculated = calculateP6Schedule({
|
|
30212
|
-
adapter: calculationState(
|
|
30315
|
+
adapter: calculationState(
|
|
30316
|
+
input.state,
|
|
30317
|
+
preflight.activities,
|
|
30318
|
+
rolledExpectedFinishes
|
|
30319
|
+
),
|
|
30213
30320
|
settings: preflight.settings,
|
|
30214
30321
|
project: {
|
|
30215
30322
|
projectId: String(input.sector.projectId),
|
|
@@ -30255,11 +30362,19 @@ function requireProjectState(projectState) {
|
|
|
30255
30362
|
"P6 capability is not enabled for this Schedule"
|
|
30256
30363
|
);
|
|
30257
30364
|
}
|
|
30258
|
-
function calculationState(current, schedulableActivities) {
|
|
30365
|
+
function calculationState(current, schedulableActivities, rolledExpectedFinishes) {
|
|
30259
30366
|
const state = current.fork();
|
|
30260
30367
|
state.forEachActivity((activity) => {
|
|
30261
|
-
if (schedulableActivities.has(activity.id))
|
|
30262
|
-
|
|
30368
|
+
if (!schedulableActivities.has(activity.id)) {
|
|
30369
|
+
state.setActivityField(activity.id, "p6", void 0);
|
|
30370
|
+
return;
|
|
30371
|
+
}
|
|
30372
|
+
const rolledExpectedFinish = rolledExpectedFinishes.get(activity.id);
|
|
30373
|
+
if (rolledExpectedFinish === void 0 || activity.p6 === void 0) return;
|
|
30374
|
+
state.setActivityField(activity.id, "p6", {
|
|
30375
|
+
...activity.p6,
|
|
30376
|
+
expectedFinish: rolledExpectedFinish
|
|
30377
|
+
});
|
|
30263
30378
|
});
|
|
30264
30379
|
return state;
|
|
30265
30380
|
}
|