@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.d.cts
CHANGED
|
@@ -724,6 +724,12 @@ interface ScheduleAutoScheduleAction {
|
|
|
724
724
|
*
|
|
725
725
|
* Link `lag` inputs are working days and are converted to stored working hours.
|
|
726
726
|
* Consumer analytics context is carried by optional `eventSource` fields.
|
|
727
|
+
*
|
|
728
|
+
* `CELL_COPY`'s `copiedText` and `CELL_PASTE_COPIED`'s `clipboardText` carry the
|
|
729
|
+
* host's OS-clipboard text alongside the structured value. When `clipboardText`
|
|
730
|
+
* no longer matches the `copiedText` stashed at copy time (or nothing was ever
|
|
731
|
+
* copied through the core), the paste falls back to that raw text through the
|
|
732
|
+
* target column's own `parseInput` instead of the stashed structured value.
|
|
727
733
|
*/
|
|
728
734
|
type DispatchAction = {
|
|
729
735
|
kind: typeof DISPATCH_ACTION_KIND.ACTIVITY_COPY;
|
|
@@ -752,6 +758,7 @@ type DispatchAction = {
|
|
|
752
758
|
kind: typeof DISPATCH_ACTION_KIND.CELL_COPY;
|
|
753
759
|
activityId: ActivityId;
|
|
754
760
|
column: EditableColumnName;
|
|
761
|
+
copiedText?: string;
|
|
755
762
|
eventSource?: string;
|
|
756
763
|
} | {
|
|
757
764
|
kind: typeof DISPATCH_ACTION_KIND.CELL_CLIPBOARD_CLEAR;
|
|
@@ -760,6 +767,7 @@ type DispatchAction = {
|
|
|
760
767
|
kind: typeof DISPATCH_ACTION_KIND.CELL_PASTE_COPIED;
|
|
761
768
|
activityIds: ReadonlyArray<ActivityId>;
|
|
762
769
|
column: EditableColumnName;
|
|
770
|
+
clipboardText?: string;
|
|
763
771
|
eventSource?: string;
|
|
764
772
|
} | {
|
|
765
773
|
kind: typeof DISPATCH_ACTION_KIND.PERSISTENCE_ACKNOWLEDGE;
|
|
@@ -2154,25 +2162,35 @@ interface ScheduleCellsApi {
|
|
|
2154
2162
|
* Copies one activity's cell value to core-owned clipboard state.
|
|
2155
2163
|
*
|
|
2156
2164
|
* Predecessor and successor columns copy the underlying dependency links;
|
|
2157
|
-
* every other column copies its canonical field value
|
|
2165
|
+
* every other column copies its canonical field value alongside `copiedText`,
|
|
2166
|
+
* the host's OS-clipboard text at copy time.
|
|
2158
2167
|
* @param activityId - Source activity.
|
|
2159
2168
|
* @param column - Source column.
|
|
2169
|
+
* @param copiedText - Host OS-clipboard text to stash alongside the value.
|
|
2160
2170
|
* @param context - Optional consumer event source.
|
|
2161
2171
|
* @returns The complete dispatch result.
|
|
2162
2172
|
*/
|
|
2163
|
-
copy(activityId: ActivityId, column: EditableColumnName, context?: MutationContext): Promise<DispatchResult>;
|
|
2173
|
+
copy(activityId: ActivityId, column: EditableColumnName, copiedText?: string, context?: MutationContext): Promise<DispatchResult>;
|
|
2164
2174
|
/**
|
|
2165
2175
|
* Pastes the copied cell value into one or more activities' column.
|
|
2166
2176
|
*
|
|
2167
2177
|
* Predecessor and successor columns paste cross-compatibly with each
|
|
2168
|
-
* other
|
|
2169
|
-
*
|
|
2178
|
+
* other and ignore `clipboardText`. For every other column: `tags`,
|
|
2179
|
+
* `responsables`, `subcontract_id`, `constraint_type` and `calendar_id`
|
|
2180
|
+
* only accept a paste whose source was the exact same column, rejected
|
|
2181
|
+
* with `CELL_PASTE_COLUMN_MISMATCH` otherwise; every other column pair is
|
|
2182
|
+
* left to the target column's own pipeline. When `clipboardText` no
|
|
2183
|
+
* longer matches the text stashed at copy time (or nothing was ever
|
|
2184
|
+
* copied through the core), the stashed value is dropped and
|
|
2185
|
+
* `clipboardText` itself is pasted through the target column's own
|
|
2186
|
+
* `parseInput` instead.
|
|
2170
2187
|
* @param activityIds - Destination activities.
|
|
2171
2188
|
* @param column - Destination column.
|
|
2189
|
+
* @param clipboardText - Host OS-clipboard text at paste time.
|
|
2172
2190
|
* @param context - Optional consumer event source.
|
|
2173
2191
|
* @returns The complete dispatch result.
|
|
2174
2192
|
*/
|
|
2175
|
-
paste(activityIds: ReadonlyArray<ActivityId>, column: EditableColumnName, context?: MutationContext): Promise<DispatchResult>;
|
|
2193
|
+
paste(activityIds: ReadonlyArray<ActivityId>, column: EditableColumnName, clipboardText?: string, context?: MutationContext): Promise<DispatchResult>;
|
|
2176
2194
|
/** @returns The complete result of clearing core-owned cell clipboard state. */
|
|
2177
2195
|
clearClipboard(context?: MutationContext): Promise<DispatchResult>;
|
|
2178
2196
|
}
|
|
@@ -2669,6 +2687,7 @@ type LinkRejection = (typeof LINK_REJECTION_REASON)[keyof typeof LINK_REJECTION_
|
|
|
2669
2687
|
declare const LOAD_DIAGNOSTIC_CODE: {
|
|
2670
2688
|
readonly INVALID_BASELINE_POINT: "invalid_baseline_point";
|
|
2671
2689
|
readonly UNKNOWN_CONSTRAINT: "unknown_constraint";
|
|
2690
|
+
readonly PROGRESS_OUT_OF_RANGE: "progress_out_of_range";
|
|
2672
2691
|
readonly ORPHAN_ACTIVITY: "orphan_activity";
|
|
2673
2692
|
readonly INVALID_LINK: "invalid_link";
|
|
2674
2693
|
readonly DUPLICATE_LINK: "duplicate_link";
|
|
@@ -3668,6 +3687,7 @@ declare const REJECTION_REASON: {
|
|
|
3668
3687
|
readonly NO_ACTIVITY_SELECTION: "no_activity_selection";
|
|
3669
3688
|
readonly CLIPBOARD_EMPTY: "clipboard_empty";
|
|
3670
3689
|
readonly CLIPBOARD_SNAPSHOT_INVALID: "clipboard_snapshot_invalid";
|
|
3690
|
+
readonly CELL_PASTE_COLUMN_MISMATCH: "cell_paste_column_mismatch";
|
|
3671
3691
|
readonly ACTIVITY_PASTE_INVARIANT_FAILED: "activity_paste_invariant_failed";
|
|
3672
3692
|
readonly SOLE_SCHEDULE_ROOT: "sole_schedule_root";
|
|
3673
3693
|
readonly ANCHOR_SIBLING_CONFLICT: "anchor_sibling_conflict";
|
package/dist/index.d.ts
CHANGED
|
@@ -724,6 +724,12 @@ interface ScheduleAutoScheduleAction {
|
|
|
724
724
|
*
|
|
725
725
|
* Link `lag` inputs are working days and are converted to stored working hours.
|
|
726
726
|
* Consumer analytics context is carried by optional `eventSource` fields.
|
|
727
|
+
*
|
|
728
|
+
* `CELL_COPY`'s `copiedText` and `CELL_PASTE_COPIED`'s `clipboardText` carry the
|
|
729
|
+
* host's OS-clipboard text alongside the structured value. When `clipboardText`
|
|
730
|
+
* no longer matches the `copiedText` stashed at copy time (or nothing was ever
|
|
731
|
+
* copied through the core), the paste falls back to that raw text through the
|
|
732
|
+
* target column's own `parseInput` instead of the stashed structured value.
|
|
727
733
|
*/
|
|
728
734
|
type DispatchAction = {
|
|
729
735
|
kind: typeof DISPATCH_ACTION_KIND.ACTIVITY_COPY;
|
|
@@ -752,6 +758,7 @@ type DispatchAction = {
|
|
|
752
758
|
kind: typeof DISPATCH_ACTION_KIND.CELL_COPY;
|
|
753
759
|
activityId: ActivityId;
|
|
754
760
|
column: EditableColumnName;
|
|
761
|
+
copiedText?: string;
|
|
755
762
|
eventSource?: string;
|
|
756
763
|
} | {
|
|
757
764
|
kind: typeof DISPATCH_ACTION_KIND.CELL_CLIPBOARD_CLEAR;
|
|
@@ -760,6 +767,7 @@ type DispatchAction = {
|
|
|
760
767
|
kind: typeof DISPATCH_ACTION_KIND.CELL_PASTE_COPIED;
|
|
761
768
|
activityIds: ReadonlyArray<ActivityId>;
|
|
762
769
|
column: EditableColumnName;
|
|
770
|
+
clipboardText?: string;
|
|
763
771
|
eventSource?: string;
|
|
764
772
|
} | {
|
|
765
773
|
kind: typeof DISPATCH_ACTION_KIND.PERSISTENCE_ACKNOWLEDGE;
|
|
@@ -2154,25 +2162,35 @@ interface ScheduleCellsApi {
|
|
|
2154
2162
|
* Copies one activity's cell value to core-owned clipboard state.
|
|
2155
2163
|
*
|
|
2156
2164
|
* Predecessor and successor columns copy the underlying dependency links;
|
|
2157
|
-
* every other column copies its canonical field value
|
|
2165
|
+
* every other column copies its canonical field value alongside `copiedText`,
|
|
2166
|
+
* the host's OS-clipboard text at copy time.
|
|
2158
2167
|
* @param activityId - Source activity.
|
|
2159
2168
|
* @param column - Source column.
|
|
2169
|
+
* @param copiedText - Host OS-clipboard text to stash alongside the value.
|
|
2160
2170
|
* @param context - Optional consumer event source.
|
|
2161
2171
|
* @returns The complete dispatch result.
|
|
2162
2172
|
*/
|
|
2163
|
-
copy(activityId: ActivityId, column: EditableColumnName, context?: MutationContext): Promise<DispatchResult>;
|
|
2173
|
+
copy(activityId: ActivityId, column: EditableColumnName, copiedText?: string, context?: MutationContext): Promise<DispatchResult>;
|
|
2164
2174
|
/**
|
|
2165
2175
|
* Pastes the copied cell value into one or more activities' column.
|
|
2166
2176
|
*
|
|
2167
2177
|
* Predecessor and successor columns paste cross-compatibly with each
|
|
2168
|
-
* other
|
|
2169
|
-
*
|
|
2178
|
+
* other and ignore `clipboardText`. For every other column: `tags`,
|
|
2179
|
+
* `responsables`, `subcontract_id`, `constraint_type` and `calendar_id`
|
|
2180
|
+
* only accept a paste whose source was the exact same column, rejected
|
|
2181
|
+
* with `CELL_PASTE_COLUMN_MISMATCH` otherwise; every other column pair is
|
|
2182
|
+
* left to the target column's own pipeline. When `clipboardText` no
|
|
2183
|
+
* longer matches the text stashed at copy time (or nothing was ever
|
|
2184
|
+
* copied through the core), the stashed value is dropped and
|
|
2185
|
+
* `clipboardText` itself is pasted through the target column's own
|
|
2186
|
+
* `parseInput` instead.
|
|
2170
2187
|
* @param activityIds - Destination activities.
|
|
2171
2188
|
* @param column - Destination column.
|
|
2189
|
+
* @param clipboardText - Host OS-clipboard text at paste time.
|
|
2172
2190
|
* @param context - Optional consumer event source.
|
|
2173
2191
|
* @returns The complete dispatch result.
|
|
2174
2192
|
*/
|
|
2175
|
-
paste(activityIds: ReadonlyArray<ActivityId>, column: EditableColumnName, context?: MutationContext): Promise<DispatchResult>;
|
|
2193
|
+
paste(activityIds: ReadonlyArray<ActivityId>, column: EditableColumnName, clipboardText?: string, context?: MutationContext): Promise<DispatchResult>;
|
|
2176
2194
|
/** @returns The complete result of clearing core-owned cell clipboard state. */
|
|
2177
2195
|
clearClipboard(context?: MutationContext): Promise<DispatchResult>;
|
|
2178
2196
|
}
|
|
@@ -2669,6 +2687,7 @@ type LinkRejection = (typeof LINK_REJECTION_REASON)[keyof typeof LINK_REJECTION_
|
|
|
2669
2687
|
declare const LOAD_DIAGNOSTIC_CODE: {
|
|
2670
2688
|
readonly INVALID_BASELINE_POINT: "invalid_baseline_point";
|
|
2671
2689
|
readonly UNKNOWN_CONSTRAINT: "unknown_constraint";
|
|
2690
|
+
readonly PROGRESS_OUT_OF_RANGE: "progress_out_of_range";
|
|
2672
2691
|
readonly ORPHAN_ACTIVITY: "orphan_activity";
|
|
2673
2692
|
readonly INVALID_LINK: "invalid_link";
|
|
2674
2693
|
readonly DUPLICATE_LINK: "duplicate_link";
|
|
@@ -3668,6 +3687,7 @@ declare const REJECTION_REASON: {
|
|
|
3668
3687
|
readonly NO_ACTIVITY_SELECTION: "no_activity_selection";
|
|
3669
3688
|
readonly CLIPBOARD_EMPTY: "clipboard_empty";
|
|
3670
3689
|
readonly CLIPBOARD_SNAPSHOT_INVALID: "clipboard_snapshot_invalid";
|
|
3690
|
+
readonly CELL_PASTE_COLUMN_MISMATCH: "cell_paste_column_mismatch";
|
|
3671
3691
|
readonly ACTIVITY_PASTE_INVARIANT_FAILED: "activity_paste_invariant_failed";
|
|
3672
3692
|
readonly SOLE_SCHEDULE_ROOT: "sole_schedule_root";
|
|
3673
3693
|
readonly ANCHOR_SIBLING_CONFLICT: "anchor_sibling_conflict";
|
package/dist/index.js
CHANGED
|
@@ -628,17 +628,19 @@ function createActivitiesApi(engine) {
|
|
|
628
628
|
}
|
|
629
629
|
function createCellsApi(engine) {
|
|
630
630
|
return {
|
|
631
|
-
copy: (activityId, column, context = {}) => engine.dispatch({
|
|
631
|
+
copy: (activityId, column, copiedText, context = {}) => engine.dispatch({
|
|
632
632
|
...context,
|
|
633
633
|
kind: DISPATCH_ACTION_KIND.CELL_COPY,
|
|
634
634
|
activityId,
|
|
635
|
-
column
|
|
635
|
+
column,
|
|
636
|
+
...copiedText === void 0 ? {} : { copiedText }
|
|
636
637
|
}),
|
|
637
|
-
paste: (activityIds, column, context = {}) => engine.dispatch({
|
|
638
|
+
paste: (activityIds, column, clipboardText, context = {}) => engine.dispatch({
|
|
638
639
|
...context,
|
|
639
640
|
kind: DISPATCH_ACTION_KIND.CELL_PASTE_COPIED,
|
|
640
641
|
activityIds,
|
|
641
|
-
column
|
|
642
|
+
column,
|
|
643
|
+
...clipboardText === void 0 ? {} : { clipboardText }
|
|
642
644
|
}),
|
|
643
645
|
clearClipboard: (context = {}) => engine.dispatch({
|
|
644
646
|
...context,
|
|
@@ -955,6 +957,7 @@ var REJECTION_REASON = {
|
|
|
955
957
|
NO_ACTIVITY_SELECTION: "no_activity_selection",
|
|
956
958
|
CLIPBOARD_EMPTY: "clipboard_empty",
|
|
957
959
|
CLIPBOARD_SNAPSHOT_INVALID: "clipboard_snapshot_invalid",
|
|
960
|
+
CELL_PASTE_COLUMN_MISMATCH: "cell_paste_column_mismatch",
|
|
958
961
|
ACTIVITY_PASTE_INVARIANT_FAILED: "activity_paste_invariant_failed",
|
|
959
962
|
SOLE_SCHEDULE_ROOT: "sole_schedule_root",
|
|
960
963
|
ANCHOR_SIBLING_CONFLICT: "anchor_sibling_conflict",
|
|
@@ -6285,7 +6288,9 @@ var P6_PERCENT_COMPLETE_TYPE = {
|
|
|
6285
6288
|
var P6_ACTIVITY_TYPE = {
|
|
6286
6289
|
TASK: "task",
|
|
6287
6290
|
LEVEL_OF_EFFORT: "level_of_effort",
|
|
6288
|
-
START_MILESTONE: "start_milestone"
|
|
6291
|
+
START_MILESTONE: "start_milestone",
|
|
6292
|
+
RESOURCE_DEPENDENT: "resource_dependent"
|
|
6293
|
+
};
|
|
6289
6294
|
var P6_EXECUTION_STATUS = {
|
|
6290
6295
|
NOT_STARTED: "not_started",
|
|
6291
6296
|
IN_PROGRESS: "in_progress",
|
|
@@ -18014,6 +18019,7 @@ var LOAD_DIAGNOSTIC_SAMPLE_LIMIT = 10;
|
|
|
18014
18019
|
var LOAD_DIAGNOSTIC_CODE = {
|
|
18015
18020
|
INVALID_BASELINE_POINT: "invalid_baseline_point",
|
|
18016
18021
|
UNKNOWN_CONSTRAINT: "unknown_constraint",
|
|
18022
|
+
PROGRESS_OUT_OF_RANGE: "progress_out_of_range",
|
|
18017
18023
|
ORPHAN_ACTIVITY: "orphan_activity",
|
|
18018
18024
|
INVALID_LINK: "invalid_link",
|
|
18019
18025
|
DUPLICATE_LINK: "duplicate_link"
|
|
@@ -18021,6 +18027,7 @@ var LOAD_DIAGNOSTIC_CODE = {
|
|
|
18021
18027
|
var LOAD_DIAGNOSTIC_CODE_ORDER = [
|
|
18022
18028
|
LOAD_DIAGNOSTIC_CODE.INVALID_BASELINE_POINT,
|
|
18023
18029
|
LOAD_DIAGNOSTIC_CODE.UNKNOWN_CONSTRAINT,
|
|
18030
|
+
LOAD_DIAGNOSTIC_CODE.PROGRESS_OUT_OF_RANGE,
|
|
18024
18031
|
LOAD_DIAGNOSTIC_CODE.ORPHAN_ACTIVITY,
|
|
18025
18032
|
LOAD_DIAGNOSTIC_CODE.INVALID_LINK,
|
|
18026
18033
|
LOAD_DIAGNOSTIC_CODE.DUPLICATE_LINK
|
|
@@ -19006,7 +19013,12 @@ function dispatchCellCopy(action, deps) {
|
|
|
19006
19013
|
return { ok: false, reason: REJECTION_REASON.INVALID_VALUE };
|
|
19007
19014
|
}
|
|
19008
19015
|
const raw = action.column === COLUMN.DURATION ? canonicalValue / deps.hoursPerDay : cloneDomainValue(canonicalValue);
|
|
19009
|
-
deps.clipboard.value = {
|
|
19016
|
+
deps.clipboard.value = {
|
|
19017
|
+
kind: CELL_CLIPBOARD_KIND.FIELD,
|
|
19018
|
+
raw,
|
|
19019
|
+
sourceColumn: action.column,
|
|
19020
|
+
text: action.copiedText ?? null
|
|
19021
|
+
};
|
|
19010
19022
|
return emptyChangeSet(action);
|
|
19011
19023
|
}
|
|
19012
19024
|
function dispatchCellClipboardClear(action, clipboard) {
|
|
@@ -19015,6 +19027,39 @@ function dispatchCellClipboardClear(action, clipboard) {
|
|
|
19015
19027
|
}
|
|
19016
19028
|
|
|
19017
19029
|
// src/cell-copy-paste/paste.ts
|
|
19030
|
+
var RESTRICTED_CELL_COLUMNS = /* @__PURE__ */ new Set([
|
|
19031
|
+
COLUMN.TAGS,
|
|
19032
|
+
COLUMN.RESPONSABLES,
|
|
19033
|
+
COLUMN.SUBCONTRACT_ID,
|
|
19034
|
+
COLUMN.CONSTRAINT_TYPE,
|
|
19035
|
+
COLUMN.CALENDAR_ID
|
|
19036
|
+
]);
|
|
19037
|
+
function isIncompatibleCellPaste(sourceColumn, targetColumn) {
|
|
19038
|
+
if (sourceColumn === targetColumn) return false;
|
|
19039
|
+
return RESTRICTED_CELL_COLUMNS.has(sourceColumn) || RESTRICTED_CELL_COLUMNS.has(targetColumn);
|
|
19040
|
+
}
|
|
19041
|
+
function resolveExternalPasteText(stashedField, clipboardText) {
|
|
19042
|
+
if (clipboardText === void 0) return null;
|
|
19043
|
+
const rawIsTrustworthy = stashedField !== null && (stashedField.text === null || stashedField.text === clipboardText);
|
|
19044
|
+
return rawIsTrustworthy ? null : clipboardText;
|
|
19045
|
+
}
|
|
19046
|
+
function resolveFieldPasteValue(clipboard, column, clipboardText) {
|
|
19047
|
+
const stashedField = clipboard !== null && clipboard.kind === CELL_CLIPBOARD_KIND.FIELD ? clipboard : null;
|
|
19048
|
+
const externalText = resolveExternalPasteText(stashedField, clipboardText);
|
|
19049
|
+
if (externalText !== null) {
|
|
19050
|
+
return { ok: true, newValue: externalText };
|
|
19051
|
+
}
|
|
19052
|
+
if (clipboard !== null && clipboard.kind !== CELL_CLIPBOARD_KIND.FIELD) {
|
|
19053
|
+
return { ok: false, reason: REJECTION_REASON.INVALID_VALUE };
|
|
19054
|
+
}
|
|
19055
|
+
if (stashedField === null) {
|
|
19056
|
+
return { ok: false, reason: REJECTION_REASON.CLIPBOARD_EMPTY };
|
|
19057
|
+
}
|
|
19058
|
+
if (isIncompatibleCellPaste(stashedField.sourceColumn, column)) {
|
|
19059
|
+
return { ok: false, reason: REJECTION_REASON.CELL_PASTE_COLUMN_MISMATCH };
|
|
19060
|
+
}
|
|
19061
|
+
return { ok: true, newValue: stashedField.raw };
|
|
19062
|
+
}
|
|
19018
19063
|
function toDiffPlaceholder(activityId) {
|
|
19019
19064
|
return String(activityId);
|
|
19020
19065
|
}
|
|
@@ -19047,11 +19092,45 @@ function linkOperationsForTarget(targetActivityId, isPredecessors, clipboard, de
|
|
|
19047
19092
|
});
|
|
19048
19093
|
return diff.operations;
|
|
19049
19094
|
}
|
|
19050
|
-
async function
|
|
19051
|
-
const clipboard = deps.cellClipboard.value;
|
|
19095
|
+
async function dispatchCellPasteLinkColumn(action, clipboard, options, deps) {
|
|
19052
19096
|
if (clipboard === null) {
|
|
19053
19097
|
return { ok: false, reason: REJECTION_REASON.CLIPBOARD_EMPTY };
|
|
19054
19098
|
}
|
|
19099
|
+
if (clipboard.kind !== CELL_CLIPBOARD_KIND.LINKS) {
|
|
19100
|
+
return { ok: false, reason: REJECTION_REASON.INVALID_VALUE };
|
|
19101
|
+
}
|
|
19102
|
+
const hasSelfReference = action.activityIds.some(
|
|
19103
|
+
(activityId) => clipboard.specs.some(
|
|
19104
|
+
(spec) => String(spec.otherActivityId) === String(activityId)
|
|
19105
|
+
)
|
|
19106
|
+
);
|
|
19107
|
+
if (hasSelfReference) {
|
|
19108
|
+
return { ok: false, reason: LINK_REJECTION_REASON.SELF_LINK };
|
|
19109
|
+
}
|
|
19110
|
+
const isPredecessors = action.column === COLUMN.CUSTOM_PREDECESSORS;
|
|
19111
|
+
const operations = action.activityIds.flatMap(
|
|
19112
|
+
(activityId) => linkOperationsForTarget(activityId, isPredecessors, clipboard, deps)
|
|
19113
|
+
);
|
|
19114
|
+
const createEntries = operations.filter(
|
|
19115
|
+
(operation) => operation.kind === LINK_OPERATION_KIND.CREATE
|
|
19116
|
+
).map((operation) => ({
|
|
19117
|
+
operation,
|
|
19118
|
+
linkId: deps.linkIdGen.next()
|
|
19119
|
+
}));
|
|
19120
|
+
const creation = validateLinkCreateBatch(createEntries, {
|
|
19121
|
+
port: deps.adapter,
|
|
19122
|
+
rejectParentLinkMutations: options.rejectParentLinkMutations ?? false
|
|
19123
|
+
});
|
|
19124
|
+
if (!creation.applied) {
|
|
19125
|
+
return {
|
|
19126
|
+
ok: false,
|
|
19127
|
+
reason: creation.rejected ?? REJECTION_REASON.INVALID
|
|
19128
|
+
};
|
|
19129
|
+
}
|
|
19130
|
+
return dispatchLinkBatch(operations, action, options, deps);
|
|
19131
|
+
}
|
|
19132
|
+
async function dispatchCellPasteCopied(action, options, deps) {
|
|
19133
|
+
const clipboard = deps.cellClipboard.value;
|
|
19055
19134
|
if (action.activityIds.length === 0) {
|
|
19056
19135
|
return { ok: false, reason: REJECTION_REASON.ACTIVITY_IDS_EMPTY };
|
|
19057
19136
|
}
|
|
@@ -19062,53 +19141,25 @@ async function dispatchCellPasteCopied(action, options, deps) {
|
|
|
19062
19141
|
return { ok: false, reason: REJECTION_REASON.ACTIVITY_NOT_FOUND };
|
|
19063
19142
|
}
|
|
19064
19143
|
if (action.column === COLUMN.CUSTOM_PREDECESSORS || action.column === COLUMN.CUSTOM_SUCESSORS) {
|
|
19065
|
-
|
|
19066
|
-
return { ok: false, reason: REJECTION_REASON.INVALID_VALUE };
|
|
19067
|
-
}
|
|
19068
|
-
const hasSelfReference = action.activityIds.some(
|
|
19069
|
-
(activityId) => clipboard.specs.some(
|
|
19070
|
-
(spec) => String(spec.otherActivityId) === String(activityId)
|
|
19071
|
-
)
|
|
19072
|
-
);
|
|
19073
|
-
if (hasSelfReference) {
|
|
19074
|
-
return { ok: false, reason: LINK_REJECTION_REASON.SELF_LINK };
|
|
19075
|
-
}
|
|
19076
|
-
const isPredecessors = action.column === COLUMN.CUSTOM_PREDECESSORS;
|
|
19077
|
-
const operations = action.activityIds.flatMap(
|
|
19078
|
-
(activityId) => linkOperationsForTarget(activityId, isPredecessors, clipboard, deps)
|
|
19079
|
-
);
|
|
19080
|
-
const createEntries = operations.filter(
|
|
19081
|
-
(operation) => operation.kind === LINK_OPERATION_KIND.CREATE
|
|
19082
|
-
).map((operation) => ({
|
|
19083
|
-
operation,
|
|
19084
|
-
linkId: deps.linkIdGen.next()
|
|
19085
|
-
}));
|
|
19086
|
-
const creation = validateLinkCreateBatch(createEntries, {
|
|
19087
|
-
port: deps.adapter,
|
|
19088
|
-
rejectParentLinkMutations: options.rejectParentLinkMutations ?? false
|
|
19089
|
-
});
|
|
19090
|
-
if (!creation.applied) {
|
|
19091
|
-
return {
|
|
19092
|
-
ok: false,
|
|
19093
|
-
reason: creation.rejected ?? REJECTION_REASON.INVALID
|
|
19094
|
-
};
|
|
19095
|
-
}
|
|
19096
|
-
return dispatchLinkBatch(operations, action, options, deps);
|
|
19097
|
-
}
|
|
19098
|
-
if (clipboard.kind !== CELL_CLIPBOARD_KIND.FIELD) {
|
|
19099
|
-
return { ok: false, reason: REJECTION_REASON.INVALID_VALUE };
|
|
19144
|
+
return dispatchCellPasteLinkColumn(action, clipboard, options, deps);
|
|
19100
19145
|
}
|
|
19101
19146
|
if (!findPipelineForColumn(action.column)) {
|
|
19102
19147
|
return { ok: false, reason: REJECTION_REASON.NO_PIPELINE_FOR_COLUMN };
|
|
19103
19148
|
}
|
|
19104
19149
|
const column = action.column;
|
|
19150
|
+
const resolution = resolveFieldPasteValue(
|
|
19151
|
+
clipboard,
|
|
19152
|
+
column,
|
|
19153
|
+
action.clipboardText
|
|
19154
|
+
);
|
|
19155
|
+
if (!resolution.ok) return resolution;
|
|
19105
19156
|
const result = await dispatchBulkEdit(
|
|
19106
19157
|
{
|
|
19107
19158
|
kind: DISPATCH_ACTION_KIND.BULK_EDIT,
|
|
19108
19159
|
edits: action.activityIds.map((activityId) => ({
|
|
19109
19160
|
activityId,
|
|
19110
19161
|
column,
|
|
19111
|
-
newValue:
|
|
19162
|
+
newValue: resolution.newValue
|
|
19112
19163
|
})),
|
|
19113
19164
|
...action.eventSource === void 0 ? {} : { eventSource: action.eventSource }
|
|
19114
19165
|
},
|
|
@@ -24826,12 +24877,21 @@ function normalizePersistedActivityId(rawId) {
|
|
|
24826
24877
|
}
|
|
24827
24878
|
return rawId;
|
|
24828
24879
|
}
|
|
24829
|
-
function parseProgress(raw) {
|
|
24880
|
+
function parseProgress(raw, reporter, recordDiagnostic, activityId) {
|
|
24830
24881
|
const progress = Number(raw);
|
|
24831
|
-
if (!Number.isFinite(progress)
|
|
24882
|
+
if (!Number.isFinite(progress)) {
|
|
24832
24883
|
throw new TypeError(`invalid activity progress ${String(raw)}`);
|
|
24833
24884
|
}
|
|
24834
|
-
|
|
24885
|
+
const isBelowNotStarted = progress < NOT_STARTED_PROGRESS;
|
|
24886
|
+
const isAboveCompleted = progress > MAX_TOLERATED_PROGRESS;
|
|
24887
|
+
const isWithinRange = !isBelowNotStarted && !isAboveCompleted;
|
|
24888
|
+
if (isWithinRange) return progress;
|
|
24889
|
+
const clamped = isBelowNotStarted ? NOT_STARTED_PROGRESS : COMPLETED_PROGRESS;
|
|
24890
|
+
recordDiagnostic(LOAD_DIAGNOSTIC_CODE.PROGRESS_OUT_OF_RANGE, activityId);
|
|
24891
|
+
reporter.warn(
|
|
24892
|
+
`[parseFromBackend] activity "${activityId}" progress ${String(raw)} is out of range \u2014 clamping to ${clamped}`
|
|
24893
|
+
);
|
|
24894
|
+
return clamped;
|
|
24835
24895
|
}
|
|
24836
24896
|
function parseCriticality(raw, reporter) {
|
|
24837
24897
|
if (typeof raw.is_critical === "boolean") return raw.is_critical;
|
|
@@ -24864,7 +24924,12 @@ function parseActivity(raw, context) {
|
|
|
24864
24924
|
context.defaultCalendarId
|
|
24865
24925
|
);
|
|
24866
24926
|
const inheritedDefaultCalendar = raw.calendarId == null || !context.knownCalendarIds.has(String(raw.calendarId));
|
|
24867
|
-
const progress = parseProgress(
|
|
24927
|
+
const progress = parseProgress(
|
|
24928
|
+
raw.progress,
|
|
24929
|
+
context.reporter,
|
|
24930
|
+
context.recordDiagnostic,
|
|
24931
|
+
String(raw.unique_id)
|
|
24932
|
+
);
|
|
24868
24933
|
const { constraintType, constraintDate } = resolveConstraint(
|
|
24869
24934
|
raw,
|
|
24870
24935
|
context.reporter,
|
|
@@ -30093,6 +30158,39 @@ function blockedActivities(code, message, activityIds, missingInputs = []) {
|
|
|
30093
30158
|
};
|
|
30094
30159
|
}
|
|
30095
30160
|
|
|
30161
|
+
// src/p6/rolled-expected-finish.ts
|
|
30162
|
+
var PINNABLE_ACTIVITY_TYPES = /* @__PURE__ */ new Set([
|
|
30163
|
+
P6_ACTIVITY_TYPE.TASK,
|
|
30164
|
+
P6_ACTIVITY_TYPE.RESOURCE_DEPENDENT
|
|
30165
|
+
]);
|
|
30166
|
+
var NO_ROLLED_EXPECTED_FINISHES = /* @__PURE__ */ new Map();
|
|
30167
|
+
function planRolledExpectedFinishes(input) {
|
|
30168
|
+
const adoptsShownFinishes = input.settings.useExpectedFinishDates && rollsDataDateForward(input.previousSettings, input.settings);
|
|
30169
|
+
if (!adoptsShownFinishes) return NO_ROLLED_EXPECTED_FINISHES;
|
|
30170
|
+
const pinned = /* @__PURE__ */ new Map();
|
|
30171
|
+
for (const [activityId, state] of input.activities) {
|
|
30172
|
+
const shownFinish = state.remainingEarlyFinish;
|
|
30173
|
+
if (shownFinish === null) continue;
|
|
30174
|
+
if (!needsExpectedFinishPin(state)) continue;
|
|
30175
|
+
pinned.set(activityId, new Date(shownFinish));
|
|
30176
|
+
}
|
|
30177
|
+
return pinned;
|
|
30178
|
+
}
|
|
30179
|
+
function rollsDataDateForward(previous, next) {
|
|
30180
|
+
const previousDataDate = previous.dataDate;
|
|
30181
|
+
const nextDataDate = next.dataDate;
|
|
30182
|
+
if (previousDataDate === null || nextDataDate === null) return false;
|
|
30183
|
+
return nextDataDate.getTime() > previousDataDate.getTime();
|
|
30184
|
+
}
|
|
30185
|
+
function needsExpectedFinishPin(state) {
|
|
30186
|
+
return state.executionStatus === P6_EXECUTION_STATUS.IN_PROGRESS && state.expectedFinish === null && hasPinnableActivityType(state);
|
|
30187
|
+
}
|
|
30188
|
+
function hasPinnableActivityType(state) {
|
|
30189
|
+
const { activityType } = state;
|
|
30190
|
+
if (activityType === void 0) return true;
|
|
30191
|
+
return PINNABLE_ACTIVITY_TYPES.has(activityType);
|
|
30192
|
+
}
|
|
30193
|
+
|
|
30096
30194
|
// src/p6/commands.ts
|
|
30097
30195
|
function dataDateScheduleReadiness(input) {
|
|
30098
30196
|
const preflight = getP6SchedulePreflight({
|
|
@@ -30206,8 +30304,17 @@ function prepareDataDateSchedule(input) {
|
|
|
30206
30304
|
preflight.settings,
|
|
30207
30305
|
beforeProjectState
|
|
30208
30306
|
);
|
|
30307
|
+
const rolledExpectedFinishes = planRolledExpectedFinishes({
|
|
30308
|
+
previousSettings: preflight.previousSettings,
|
|
30309
|
+
settings: preflight.settings,
|
|
30310
|
+
activities: preflight.activities
|
|
30311
|
+
});
|
|
30209
30312
|
const calculated = calculateP6Schedule({
|
|
30210
|
-
adapter: calculationState(
|
|
30313
|
+
adapter: calculationState(
|
|
30314
|
+
input.state,
|
|
30315
|
+
preflight.activities,
|
|
30316
|
+
rolledExpectedFinishes
|
|
30317
|
+
),
|
|
30211
30318
|
settings: preflight.settings,
|
|
30212
30319
|
project: {
|
|
30213
30320
|
projectId: String(input.sector.projectId),
|
|
@@ -30253,11 +30360,19 @@ function requireProjectState(projectState) {
|
|
|
30253
30360
|
"P6 capability is not enabled for this Schedule"
|
|
30254
30361
|
);
|
|
30255
30362
|
}
|
|
30256
|
-
function calculationState(current, schedulableActivities) {
|
|
30363
|
+
function calculationState(current, schedulableActivities, rolledExpectedFinishes) {
|
|
30257
30364
|
const state = current.fork();
|
|
30258
30365
|
state.forEachActivity((activity) => {
|
|
30259
|
-
if (schedulableActivities.has(activity.id))
|
|
30260
|
-
|
|
30366
|
+
if (!schedulableActivities.has(activity.id)) {
|
|
30367
|
+
state.setActivityField(activity.id, "p6", void 0);
|
|
30368
|
+
return;
|
|
30369
|
+
}
|
|
30370
|
+
const rolledExpectedFinish = rolledExpectedFinishes.get(activity.id);
|
|
30371
|
+
if (rolledExpectedFinish === void 0 || activity.p6 === void 0) return;
|
|
30372
|
+
state.setActivityField(activity.id, "p6", {
|
|
30373
|
+
...activity.p6,
|
|
30374
|
+
expectedFinish: rolledExpectedFinish
|
|
30375
|
+
});
|
|
30261
30376
|
});
|
|
30262
30377
|
return state;
|
|
30263
30378
|
}
|