@outbuild-company/schedule-core 1.20.1 → 1.22.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 +538 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +72 -1
- package/dist/index.d.ts +72 -1
- package/dist/index.js +538 -12
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -343,6 +343,10 @@ var DISPATCH_ACTION_KIND = {
|
|
|
343
343
|
ACTIVITY_COPY: "activity-copy",
|
|
344
344
|
CALENDAR_RECONCILE: "calendar-reconcile",
|
|
345
345
|
ACTIVITY_PASTE_COPIED: "activity-paste-copied",
|
|
346
|
+
ACTIVITY_DUPLICATE: "activity-duplicate",
|
|
347
|
+
CELL_COPY: "cell-copy",
|
|
348
|
+
CELL_CLIPBOARD_CLEAR: "cell-clipboard-clear",
|
|
349
|
+
CELL_PASTE_COPIED: "cell-paste-copied",
|
|
346
350
|
PERSISTENCE_ACKNOWLEDGE: "persistence-acknowledge",
|
|
347
351
|
BASELINE_APPLY: "baseline-apply",
|
|
348
352
|
PONDERATOR_CRITERION_SET: "ponderator-criterion-set",
|
|
@@ -591,6 +595,11 @@ function createActivitiesApi(engine) {
|
|
|
591
595
|
kind: DISPATCH_ACTION_KIND.ACTIVITY_PASTE_COPIED,
|
|
592
596
|
destination: { afterSiblingId }
|
|
593
597
|
}),
|
|
598
|
+
duplicate: (activityIds, context = {}) => engine.dispatch({
|
|
599
|
+
...context,
|
|
600
|
+
kind: DISPATCH_ACTION_KIND.ACTIVITY_DUPLICATE,
|
|
601
|
+
activityIds
|
|
602
|
+
}),
|
|
594
603
|
clearClipboard: (context = {}) => engine.dispatch({
|
|
595
604
|
...context,
|
|
596
605
|
kind: DISPATCH_ACTION_KIND.ACTIVITY_CLIPBOARD_CLEAR
|
|
@@ -609,6 +618,26 @@ function createActivitiesApi(engine) {
|
|
|
609
618
|
createDateGesturePreview: (gesture) => engine.createDateGesturePreview(gesture)
|
|
610
619
|
};
|
|
611
620
|
}
|
|
621
|
+
function createCellsApi(engine) {
|
|
622
|
+
return {
|
|
623
|
+
copy: (activityId, column, context = {}) => engine.dispatch({
|
|
624
|
+
...context,
|
|
625
|
+
kind: DISPATCH_ACTION_KIND.CELL_COPY,
|
|
626
|
+
activityId,
|
|
627
|
+
column
|
|
628
|
+
}),
|
|
629
|
+
paste: (activityIds, column, context = {}) => engine.dispatch({
|
|
630
|
+
...context,
|
|
631
|
+
kind: DISPATCH_ACTION_KIND.CELL_PASTE_COPIED,
|
|
632
|
+
activityIds,
|
|
633
|
+
column
|
|
634
|
+
}),
|
|
635
|
+
clearClipboard: (context = {}) => engine.dispatch({
|
|
636
|
+
...context,
|
|
637
|
+
kind: DISPATCH_ACTION_KIND.CELL_CLIPBOARD_CLEAR
|
|
638
|
+
})
|
|
639
|
+
};
|
|
640
|
+
}
|
|
612
641
|
function createLinksApi(engine) {
|
|
613
642
|
return {
|
|
614
643
|
get: (id) => engine.getLinkView(id),
|
|
@@ -656,6 +685,7 @@ function createScheduleNamespaces(engine) {
|
|
|
656
685
|
);
|
|
657
686
|
return {
|
|
658
687
|
activities: createActivitiesApi(engine),
|
|
688
|
+
cells: createCellsApi(engine),
|
|
659
689
|
links: createLinksApi(engine),
|
|
660
690
|
calendars: {
|
|
661
691
|
get: (id) => engine.getCalendar(id),
|
|
@@ -917,6 +947,7 @@ var REJECTION_REASON = {
|
|
|
917
947
|
NO_ACTIVITY_SELECTION: "no_activity_selection",
|
|
918
948
|
CLIPBOARD_EMPTY: "clipboard_empty",
|
|
919
949
|
ACTIVITY_PASTE_INVARIANT_FAILED: "activity_paste_invariant_failed",
|
|
950
|
+
SOLE_SCHEDULE_ROOT: "sole_schedule_root",
|
|
920
951
|
ANCHOR_SIBLING_CONFLICT: "anchor_sibling_conflict",
|
|
921
952
|
ANCHOR_SIBLING_NOT_FOUND: "anchor_sibling_not_found",
|
|
922
953
|
ANCHOR_SIBLING_WRONG_PARENT: "anchor_sibling_wrong_parent",
|
|
@@ -3885,7 +3916,7 @@ function applyLinkOperation(op, deps) {
|
|
|
3885
3916
|
return applyDelete(op, deps);
|
|
3886
3917
|
}
|
|
3887
3918
|
}
|
|
3888
|
-
function
|
|
3919
|
+
function validateLinkCreateBatch(links, deps) {
|
|
3889
3920
|
if (links.length === 0) return { applied: true };
|
|
3890
3921
|
const existingLinks = deps.port.getAllLinks();
|
|
3891
3922
|
const duplicateKeys = /* @__PURE__ */ new Map();
|
|
@@ -3969,6 +4000,12 @@ function applyLinkCreates(links, deps) {
|
|
|
3969
4000
|
if (!effectiveVerdict.ok) {
|
|
3970
4001
|
return { applied: false, rejected: LINK_REJECTION_REASON.CYCLE };
|
|
3971
4002
|
}
|
|
4003
|
+
return { applied: true };
|
|
4004
|
+
}
|
|
4005
|
+
function applyLinkCreates(links, deps) {
|
|
4006
|
+
if (links.length === 0) return { applied: true };
|
|
4007
|
+
const validation = validateLinkCreateBatch(links, deps);
|
|
4008
|
+
if (!validation.applied) return validation;
|
|
3972
4009
|
for (const { operation, linkId } of links) {
|
|
3973
4010
|
const preserved = deps.preserved?.get(linkId);
|
|
3974
4011
|
deps.port.addLink({
|
|
@@ -11706,6 +11743,8 @@ var NON_SCHEDULING_INLINE_COLUMNS = /* @__PURE__ */ new Set([
|
|
|
11706
11743
|
var NON_SCHEDULING_KINDS = /* @__PURE__ */ new Set([
|
|
11707
11744
|
DISPATCH_ACTION_KIND.ACTIVITY_CLIPBOARD_CLEAR,
|
|
11708
11745
|
DISPATCH_ACTION_KIND.ACTIVITY_COPY,
|
|
11746
|
+
DISPATCH_ACTION_KIND.CELL_CLIPBOARD_CLEAR,
|
|
11747
|
+
DISPATCH_ACTION_KIND.CELL_COPY,
|
|
11709
11748
|
DISPATCH_ACTION_KIND.SELECTION_TOGGLE,
|
|
11710
11749
|
DISPATCH_ACTION_KIND.SELECTION_REPLACE,
|
|
11711
11750
|
DISPATCH_ACTION_KIND.VISIBILITY_SET,
|
|
@@ -11724,6 +11763,8 @@ var NON_SCHEDULING_KINDS = /* @__PURE__ */ new Set([
|
|
|
11724
11763
|
var PURE_VIEW_STATE_KINDS = /* @__PURE__ */ new Set([
|
|
11725
11764
|
DISPATCH_ACTION_KIND.ACTIVITY_CLIPBOARD_CLEAR,
|
|
11726
11765
|
DISPATCH_ACTION_KIND.ACTIVITY_COPY,
|
|
11766
|
+
DISPATCH_ACTION_KIND.CELL_CLIPBOARD_CLEAR,
|
|
11767
|
+
DISPATCH_ACTION_KIND.CELL_COPY,
|
|
11727
11768
|
DISPATCH_ACTION_KIND.SELECTION_TOGGLE,
|
|
11728
11769
|
DISPATCH_ACTION_KIND.SELECTION_REPLACE,
|
|
11729
11770
|
DISPATCH_ACTION_KIND.VISIBILITY_SET,
|
|
@@ -11741,7 +11782,7 @@ function reappliesViewState(action) {
|
|
|
11741
11782
|
}
|
|
11742
11783
|
var NO_STRUCTURAL_EXEMPTIONS = /* @__PURE__ */ new Set();
|
|
11743
11784
|
function editsOnlyNonSchedulingColumns(action) {
|
|
11744
|
-
if (action.kind === DISPATCH_ACTION_KIND.INLINE_EDIT) {
|
|
11785
|
+
if (action.kind === DISPATCH_ACTION_KIND.INLINE_EDIT || action.kind === DISPATCH_ACTION_KIND.CELL_PASTE_COPIED) {
|
|
11745
11786
|
return NON_SCHEDULING_INLINE_COLUMNS.has(action.column);
|
|
11746
11787
|
}
|
|
11747
11788
|
if (action.kind === DISPATCH_ACTION_KIND.BULK_EDIT) {
|
|
@@ -11752,7 +11793,7 @@ function editsOnlyNonSchedulingColumns(action) {
|
|
|
11752
11793
|
return false;
|
|
11753
11794
|
}
|
|
11754
11795
|
function editsOnlyDataDateColumns(action) {
|
|
11755
|
-
if (action.kind === DISPATCH_ACTION_KIND.INLINE_EDIT) {
|
|
11796
|
+
if (action.kind === DISPATCH_ACTION_KIND.INLINE_EDIT || action.kind === DISPATCH_ACTION_KIND.CELL_PASTE_COPIED) {
|
|
11756
11797
|
return DATA_DATE_COLUMNS.has(action.column);
|
|
11757
11798
|
}
|
|
11758
11799
|
return action.kind === DISPATCH_ACTION_KIND.BULK_EDIT && action.edits.every((edit) => DATA_DATE_COLUMNS.has(edit.column));
|
|
@@ -11794,6 +11835,9 @@ function dispatchChangesProgress(action) {
|
|
|
11794
11835
|
if (action.kind === DISPATCH_ACTION_KIND.BULK_EDIT) {
|
|
11795
11836
|
return action.edits.some((edit) => edit.column === COLUMN.PROGRESS);
|
|
11796
11837
|
}
|
|
11838
|
+
if (action.kind === DISPATCH_ACTION_KIND.CELL_PASTE_COPIED) {
|
|
11839
|
+
return action.column === COLUMN.PROGRESS;
|
|
11840
|
+
}
|
|
11797
11841
|
return false;
|
|
11798
11842
|
}
|
|
11799
11843
|
function resolveRunRealCost(action) {
|
|
@@ -11809,7 +11853,7 @@ var PROGRESS_AFFECTING_COLUMNS = /* @__PURE__ */ new Set([
|
|
|
11809
11853
|
]);
|
|
11810
11854
|
function shouldRecomputeParentProgress(action) {
|
|
11811
11855
|
if (action.kind === DISPATCH_ACTION_KIND.ACTIVITY_SET_PROGRESS) return true;
|
|
11812
|
-
if (action.kind === DISPATCH_ACTION_KIND.INLINE_EDIT) {
|
|
11856
|
+
if (action.kind === DISPATCH_ACTION_KIND.INLINE_EDIT || action.kind === DISPATCH_ACTION_KIND.CELL_PASTE_COPIED) {
|
|
11813
11857
|
return PROGRESS_AFFECTING_COLUMNS.has(action.column);
|
|
11814
11858
|
}
|
|
11815
11859
|
if (action.kind === DISPATCH_ACTION_KIND.BULK_EDIT) {
|
|
@@ -12781,6 +12825,15 @@ function mergeScheduledIds(firstSettleIds, secondSettleIds) {
|
|
|
12781
12825
|
}
|
|
12782
12826
|
|
|
12783
12827
|
// src/dispatch/shared/helpers.ts
|
|
12828
|
+
function getIncidentLinkSnapshots(adapter, activityId, isPredecessors) {
|
|
12829
|
+
const incidentLinkIds = isPredecessors ? adapter.getIncomingLinkIds(activityId) : adapter.getOutgoingLinkIds(activityId);
|
|
12830
|
+
const links = [];
|
|
12831
|
+
for (const linkId of incidentLinkIds) {
|
|
12832
|
+
const link = adapter.getLink(linkId);
|
|
12833
|
+
if (link) links.push(link);
|
|
12834
|
+
}
|
|
12835
|
+
return links;
|
|
12836
|
+
}
|
|
12784
12837
|
function buildLinkChangesForBatch(applied, beforeLinks, adapter) {
|
|
12785
12838
|
const out = [];
|
|
12786
12839
|
for (const { op, finalLinkId, rejected: rejected2 } of applied) {
|
|
@@ -14007,12 +14060,11 @@ async function dispatchInlineEditLinks(action, options, deps) {
|
|
|
14007
14060
|
byCorrelative.set(String(a.correlativeId), a.id);
|
|
14008
14061
|
});
|
|
14009
14062
|
const resolve = (corr) => byCorrelative.get(corr) ?? null;
|
|
14010
|
-
const
|
|
14011
|
-
|
|
14012
|
-
|
|
14013
|
-
|
|
14014
|
-
|
|
14015
|
-
}
|
|
14063
|
+
const currentLinks = getIncidentLinkSnapshots(
|
|
14064
|
+
adapter,
|
|
14065
|
+
action.activityId,
|
|
14066
|
+
isPredecessors
|
|
14067
|
+
);
|
|
14016
14068
|
const diff = isPredecessors ? diffLinks({
|
|
14017
14069
|
targetActivityId: action.activityId,
|
|
14018
14070
|
currentLinks,
|
|
@@ -18480,6 +18532,457 @@ async function dispatchActivityPasteCopied(action, options, deps) {
|
|
|
18480
18532
|
};
|
|
18481
18533
|
}
|
|
18482
18534
|
|
|
18535
|
+
// src/activity-copy-paste/duplicate.ts
|
|
18536
|
+
var CLONE_YIELD_EVERY_N = 200;
|
|
18537
|
+
var CREATE_OPTIONS = {
|
|
18538
|
+
skipCorrelativeRecompute: true,
|
|
18539
|
+
skipBeforeSnap: true,
|
|
18540
|
+
skipCacheInvalidation: true,
|
|
18541
|
+
skipRollupCascades: true
|
|
18542
|
+
};
|
|
18543
|
+
async function dispatchActivityDuplicate(action, options, deps) {
|
|
18544
|
+
const resolved = resolveDuplicateRuns(action.activityIds, deps.adapter);
|
|
18545
|
+
if (!resolved.ok) return resolved;
|
|
18546
|
+
const frozenParent = firstFrozenRunParent(resolved.runs, deps.adapter);
|
|
18547
|
+
if (frozenParent) {
|
|
18548
|
+
return { ok: false, reason: REJECTION_REASON.PARENT_FROZEN_BY_SIR };
|
|
18549
|
+
}
|
|
18550
|
+
deps.scheduler.invalidateAllCaches();
|
|
18551
|
+
const beforeSnapshot = await snapshotActivities(
|
|
18552
|
+
deps.adapter,
|
|
18553
|
+
/* @__PURE__ */ new Set()
|
|
18554
|
+
);
|
|
18555
|
+
const state = {
|
|
18556
|
+
originalToNew: /* @__PURE__ */ new Map(),
|
|
18557
|
+
createdIds: [],
|
|
18558
|
+
createdParentIds: []
|
|
18559
|
+
};
|
|
18560
|
+
for (const run of resolved.runs) {
|
|
18561
|
+
const lastOriginal = run.originals.at(-1);
|
|
18562
|
+
if (!lastOriginal) continue;
|
|
18563
|
+
let anchorId = lastOriginal.id;
|
|
18564
|
+
for (const original of run.originals) {
|
|
18565
|
+
anchorId = await cloneSubtree(
|
|
18566
|
+
original,
|
|
18567
|
+
run.parentId,
|
|
18568
|
+
anchorId,
|
|
18569
|
+
action,
|
|
18570
|
+
deps,
|
|
18571
|
+
state
|
|
18572
|
+
);
|
|
18573
|
+
}
|
|
18574
|
+
}
|
|
18575
|
+
recomputeCreatedParentRollups(state, deps);
|
|
18576
|
+
const correlativeShifts = recomputeCorrelativeIds(deps.adapter);
|
|
18577
|
+
const createdIdSet = new Set(state.createdIds.map(String));
|
|
18578
|
+
const touched = /* @__PURE__ */ new Set();
|
|
18579
|
+
seedJournalBeforeImages(
|
|
18580
|
+
deps.adapter,
|
|
18581
|
+
correlativeShifts,
|
|
18582
|
+
createdIdSet,
|
|
18583
|
+
beforeSnapshot
|
|
18584
|
+
);
|
|
18585
|
+
foldCorrelativeShifts(
|
|
18586
|
+
deps.adapter,
|
|
18587
|
+
correlativeShifts,
|
|
18588
|
+
createdIdSet,
|
|
18589
|
+
beforeSnapshot,
|
|
18590
|
+
touched
|
|
18591
|
+
);
|
|
18592
|
+
for (const createdId of state.createdIds) touched.add(String(createdId));
|
|
18593
|
+
const applied = replicateInternalLinks(state, deps);
|
|
18594
|
+
const { scheduledIds } = await runPostMutation(
|
|
18595
|
+
{
|
|
18596
|
+
adapter: deps.adapter,
|
|
18597
|
+
scheduler: deps.scheduler,
|
|
18598
|
+
sector: deps.sector,
|
|
18599
|
+
defaultBaseCalendarId: deps.defaultBaseCalendarId
|
|
18600
|
+
},
|
|
18601
|
+
{
|
|
18602
|
+
action,
|
|
18603
|
+
autoscheduleFrom: state.createdIds.length > 0 ? AUTOSCHEDULE_SCOPE.ROOTS : null,
|
|
18604
|
+
recomputeParentsFrom: state.createdIds,
|
|
18605
|
+
preventSummaryTargetPullback: true,
|
|
18606
|
+
now: deps.now,
|
|
18607
|
+
options
|
|
18608
|
+
}
|
|
18609
|
+
);
|
|
18610
|
+
return {
|
|
18611
|
+
ok: true,
|
|
18612
|
+
changes: await assembleChangeSet(deps.adapter, {
|
|
18613
|
+
source: action,
|
|
18614
|
+
beforeSnap: beforeSnapshot,
|
|
18615
|
+
touchedIds: touched,
|
|
18616
|
+
scheduledIds,
|
|
18617
|
+
links: buildLinkChangesForBatch(
|
|
18618
|
+
applied,
|
|
18619
|
+
/* @__PURE__ */ new Map(),
|
|
18620
|
+
deps.adapter
|
|
18621
|
+
),
|
|
18622
|
+
hoursPerDay: deps.sector.hoursPerDay
|
|
18623
|
+
})
|
|
18624
|
+
};
|
|
18625
|
+
}
|
|
18626
|
+
function resolveDuplicateRuns(activityIds, adapter) {
|
|
18627
|
+
if (activityIds.length === 0) {
|
|
18628
|
+
return { ok: false, reason: REJECTION_REASON.ACTIVITY_IDS_EMPTY };
|
|
18629
|
+
}
|
|
18630
|
+
const requested = /* @__PURE__ */ new Set();
|
|
18631
|
+
const originals = [];
|
|
18632
|
+
for (const rawId of activityIds) {
|
|
18633
|
+
const activityId = String(rawId);
|
|
18634
|
+
if (requested.has(activityId)) continue;
|
|
18635
|
+
const activity = adapter.getActivity(activityId);
|
|
18636
|
+
if (!activity) {
|
|
18637
|
+
return { ok: false, reason: REJECTION_REASON.ACTIVITY_NOT_FOUND };
|
|
18638
|
+
}
|
|
18639
|
+
requested.add(activityId);
|
|
18640
|
+
originals.push(activity);
|
|
18641
|
+
}
|
|
18642
|
+
const roots = originals.filter(
|
|
18643
|
+
(activity) => !hasAncestorInSet(activity.id, requested, adapter)
|
|
18644
|
+
);
|
|
18645
|
+
const duplicatesSoleScheduleRoot = adapter.getRootIds().length === 1 && roots.some((activity) => activity.parentId == null);
|
|
18646
|
+
if (duplicatesSoleScheduleRoot) {
|
|
18647
|
+
return { ok: false, reason: REJECTION_REASON.SOLE_SCHEDULE_ROOT };
|
|
18648
|
+
}
|
|
18649
|
+
return { ok: true, runs: groupIntoContiguousRuns(roots, adapter) };
|
|
18650
|
+
}
|
|
18651
|
+
function firstFrozenRunParent(runs, adapter) {
|
|
18652
|
+
const checked = /* @__PURE__ */ new Set();
|
|
18653
|
+
for (const run of runs) {
|
|
18654
|
+
if (run.parentId === ROOT_PARENT_ID || checked.has(String(run.parentId))) {
|
|
18655
|
+
continue;
|
|
18656
|
+
}
|
|
18657
|
+
checked.add(String(run.parentId));
|
|
18658
|
+
const parent = adapter.getActivity(run.parentId);
|
|
18659
|
+
if (parent && isFrozen(parent)) return parent;
|
|
18660
|
+
}
|
|
18661
|
+
return null;
|
|
18662
|
+
}
|
|
18663
|
+
function groupIntoContiguousRuns(roots, adapter) {
|
|
18664
|
+
const byParent = /* @__PURE__ */ new Map();
|
|
18665
|
+
for (const activity of roots) {
|
|
18666
|
+
const parentKey = normalizeParentKey(activity.parentId);
|
|
18667
|
+
const group = byParent.get(parentKey) ?? [];
|
|
18668
|
+
group.push(activity);
|
|
18669
|
+
byParent.set(parentKey, group);
|
|
18670
|
+
}
|
|
18671
|
+
const runs = [];
|
|
18672
|
+
for (const [parentKey, group] of byParent) {
|
|
18673
|
+
const parentId = parentKey === ROOT_PARENT_ID ? ROOT_PARENT_ID : parentKey;
|
|
18674
|
+
const positions = new Map(
|
|
18675
|
+
childrenInCorrelativeOrder(adapter, parentKey).map(
|
|
18676
|
+
(sibling, index) => [String(sibling.id), index]
|
|
18677
|
+
)
|
|
18678
|
+
);
|
|
18679
|
+
const positionOf = (activity) => positions.get(String(activity.id)) ?? -1;
|
|
18680
|
+
const ordered = [...group].sort(
|
|
18681
|
+
(left, right) => positionOf(left) - positionOf(right)
|
|
18682
|
+
);
|
|
18683
|
+
for (const originals of splitContiguous(ordered, positionOf)) {
|
|
18684
|
+
runs.push({ parentId, originals });
|
|
18685
|
+
}
|
|
18686
|
+
}
|
|
18687
|
+
return runs;
|
|
18688
|
+
}
|
|
18689
|
+
function splitContiguous(ordered, positionOf) {
|
|
18690
|
+
const runs = [];
|
|
18691
|
+
let previousPosition = null;
|
|
18692
|
+
for (const activity of ordered) {
|
|
18693
|
+
const position = positionOf(activity);
|
|
18694
|
+
const lastRun = runs.at(-1);
|
|
18695
|
+
if (lastRun && previousPosition !== null && position === previousPosition + 1) {
|
|
18696
|
+
lastRun.push(activity);
|
|
18697
|
+
} else {
|
|
18698
|
+
runs.push([activity]);
|
|
18699
|
+
}
|
|
18700
|
+
previousPosition = position;
|
|
18701
|
+
}
|
|
18702
|
+
return runs;
|
|
18703
|
+
}
|
|
18704
|
+
function seedJournalBeforeImages(adapter, shifts, excludeIds, beforeSnap) {
|
|
18705
|
+
const journal = adapter.peekWriteCapture();
|
|
18706
|
+
if (!journal) return;
|
|
18707
|
+
for (const shift of shifts) {
|
|
18708
|
+
if (excludeIds.has(shift.activityId) || beforeSnap.has(shift.activityId)) {
|
|
18709
|
+
continue;
|
|
18710
|
+
}
|
|
18711
|
+
const beforeImage = journal.before.get(shift.activityId);
|
|
18712
|
+
if (beforeImage) beforeSnap.set(shift.activityId, beforeImage);
|
|
18713
|
+
}
|
|
18714
|
+
}
|
|
18715
|
+
function childrenInCorrelativeOrder(adapter, parentKey) {
|
|
18716
|
+
return collectSiblings(adapter, parentKey).sort((left, right) => {
|
|
18717
|
+
const diff = readCorrelativeId(left) - readCorrelativeId(right);
|
|
18718
|
+
return diff || String(left.id).localeCompare(String(right.id));
|
|
18719
|
+
});
|
|
18720
|
+
}
|
|
18721
|
+
async function cloneSubtree(original, parentId, anchorId, action, deps, state) {
|
|
18722
|
+
const root = await createActivityCore(
|
|
18723
|
+
{
|
|
18724
|
+
kind: DISPATCH_ACTION_KIND.ACTIVITY_CREATE,
|
|
18725
|
+
parentId,
|
|
18726
|
+
afterSiblingId: anchorId,
|
|
18727
|
+
overrides: copyOverrides(original),
|
|
18728
|
+
...action.eventSource === void 0 ? {} : { eventSource: action.eventSource }
|
|
18729
|
+
},
|
|
18730
|
+
deps,
|
|
18731
|
+
{ ...CREATE_OPTIONS, customIdReferenceId: original.id }
|
|
18732
|
+
);
|
|
18733
|
+
if (!root.ok) throw invariantViolation("create", root.reason);
|
|
18734
|
+
registerCreated(state, original, root.newId, parentId);
|
|
18735
|
+
await cloneDescendantsIteratively(original, root.newId, action, deps, state);
|
|
18736
|
+
return root.newId;
|
|
18737
|
+
}
|
|
18738
|
+
async function cloneDescendantsIteratively(rootOriginal, rootNewParentId, action, deps, state) {
|
|
18739
|
+
const pending = new Queue();
|
|
18740
|
+
pending.enqueue({ original: rootOriginal, newParentId: rootNewParentId });
|
|
18741
|
+
let processed = 0;
|
|
18742
|
+
while (!pending.isEmpty()) {
|
|
18743
|
+
const { original, newParentId } = pending.dequeue();
|
|
18744
|
+
for (const child of childrenInCorrelativeOrder(
|
|
18745
|
+
deps.adapter,
|
|
18746
|
+
String(original.id)
|
|
18747
|
+
)) {
|
|
18748
|
+
const created = await createActivityCore(
|
|
18749
|
+
{
|
|
18750
|
+
kind: DISPATCH_ACTION_KIND.ACTIVITY_CREATE,
|
|
18751
|
+
parentId: newParentId,
|
|
18752
|
+
overrides: copyOverrides(child),
|
|
18753
|
+
...action.eventSource === void 0 ? {} : { eventSource: action.eventSource }
|
|
18754
|
+
},
|
|
18755
|
+
deps,
|
|
18756
|
+
CREATE_OPTIONS
|
|
18757
|
+
);
|
|
18758
|
+
if (!created.ok) throw invariantViolation("create", created.reason);
|
|
18759
|
+
registerCreated(state, child, created.newId, newParentId);
|
|
18760
|
+
pending.enqueue({ original: child, newParentId: created.newId });
|
|
18761
|
+
processed += 1;
|
|
18762
|
+
if (processed % CLONE_YIELD_EVERY_N === 0) await yieldToBrowser();
|
|
18763
|
+
}
|
|
18764
|
+
}
|
|
18765
|
+
}
|
|
18766
|
+
function invariantViolation(step, reason) {
|
|
18767
|
+
return new Error(
|
|
18768
|
+
`[ScheduleCore] activity-duplicate: unexpected ${step} rejection after preflight passed (${reason})`
|
|
18769
|
+
);
|
|
18770
|
+
}
|
|
18771
|
+
function registerCreated(state, original, newId, parentId) {
|
|
18772
|
+
state.originalToNew.set(String(original.id), newId);
|
|
18773
|
+
state.createdIds.push(newId);
|
|
18774
|
+
state.createdParentIds.push(parentId);
|
|
18775
|
+
}
|
|
18776
|
+
function recomputeCreatedParentRollups(state, deps) {
|
|
18777
|
+
const recomputed = /* @__PURE__ */ new Set();
|
|
18778
|
+
for (const parentId of [...state.createdParentIds].reverse()) {
|
|
18779
|
+
if (parentId === ROOT_PARENT_ID || recomputed.has(String(parentId))) {
|
|
18780
|
+
continue;
|
|
18781
|
+
}
|
|
18782
|
+
recomputed.add(String(parentId));
|
|
18783
|
+
recomputeRollupCascadesForParent(parentId, deps.adapter);
|
|
18784
|
+
}
|
|
18785
|
+
}
|
|
18786
|
+
function replicateInternalLinks(state, deps) {
|
|
18787
|
+
const applied = [];
|
|
18788
|
+
for (const originalId of state.originalToNew.keys()) {
|
|
18789
|
+
for (const linkId of deps.adapter.getOutgoingLinkIds(originalId)) {
|
|
18790
|
+
const link = deps.adapter.getLink(linkId);
|
|
18791
|
+
if (!link) continue;
|
|
18792
|
+
const source = state.originalToNew.get(String(link.source));
|
|
18793
|
+
const target = state.originalToNew.get(String(link.target));
|
|
18794
|
+
if (source === void 0 || target === void 0) continue;
|
|
18795
|
+
const operation = {
|
|
18796
|
+
kind: LINK_OPERATION_KIND.CREATE,
|
|
18797
|
+
source,
|
|
18798
|
+
target,
|
|
18799
|
+
type: link.type,
|
|
18800
|
+
lag: link.lag
|
|
18801
|
+
};
|
|
18802
|
+
const result = applyLinkOperation(operation, {
|
|
18803
|
+
port: deps.adapter,
|
|
18804
|
+
newLinkId: deps.linkIdGen.next
|
|
18805
|
+
});
|
|
18806
|
+
if (!result.applied) {
|
|
18807
|
+
throw invariantViolation(
|
|
18808
|
+
"link",
|
|
18809
|
+
result.rejected ?? REJECTION_REASON.INVALID
|
|
18810
|
+
);
|
|
18811
|
+
}
|
|
18812
|
+
applied.push({
|
|
18813
|
+
op: operation,
|
|
18814
|
+
finalLinkId: result.linkId,
|
|
18815
|
+
rejected: null
|
|
18816
|
+
});
|
|
18817
|
+
}
|
|
18818
|
+
}
|
|
18819
|
+
return applied;
|
|
18820
|
+
}
|
|
18821
|
+
|
|
18822
|
+
// src/cell-copy-paste/copy.ts
|
|
18823
|
+
var CELL_CLIPBOARD_KIND = {
|
|
18824
|
+
FIELD: "field",
|
|
18825
|
+
LINKS: "links"
|
|
18826
|
+
};
|
|
18827
|
+
function copyLinkSpecs(adapter, activityId, isPredecessors) {
|
|
18828
|
+
return getIncidentLinkSnapshots(adapter, activityId, isPredecessors).map(
|
|
18829
|
+
(link) => ({
|
|
18830
|
+
otherActivityId: isPredecessors ? link.source : link.target,
|
|
18831
|
+
type: link.type,
|
|
18832
|
+
lag: link.lag
|
|
18833
|
+
})
|
|
18834
|
+
);
|
|
18835
|
+
}
|
|
18836
|
+
function emptyChangeSet(action) {
|
|
18837
|
+
return {
|
|
18838
|
+
ok: true,
|
|
18839
|
+
changes: {
|
|
18840
|
+
source: action,
|
|
18841
|
+
activities: [],
|
|
18842
|
+
links: [],
|
|
18843
|
+
calendars: [],
|
|
18844
|
+
trackingEvents: []
|
|
18845
|
+
}
|
|
18846
|
+
};
|
|
18847
|
+
}
|
|
18848
|
+
function dispatchCellCopy(action, deps) {
|
|
18849
|
+
const activity = deps.adapter.getActivity(action.activityId);
|
|
18850
|
+
if (!activity) {
|
|
18851
|
+
return { ok: false, reason: REJECTION_REASON.ACTIVITY_NOT_FOUND };
|
|
18852
|
+
}
|
|
18853
|
+
if (action.column === COLUMN.CUSTOM_PREDECESSORS || action.column === COLUMN.CUSTOM_SUCESSORS) {
|
|
18854
|
+
deps.clipboard.value = {
|
|
18855
|
+
kind: CELL_CLIPBOARD_KIND.LINKS,
|
|
18856
|
+
specs: copyLinkSpecs(
|
|
18857
|
+
deps.adapter,
|
|
18858
|
+
action.activityId,
|
|
18859
|
+
action.column === COLUMN.CUSTOM_PREDECESSORS
|
|
18860
|
+
)
|
|
18861
|
+
};
|
|
18862
|
+
return emptyChangeSet(action);
|
|
18863
|
+
}
|
|
18864
|
+
const pipeline = findPipelineForColumn(action.column);
|
|
18865
|
+
if (!pipeline) {
|
|
18866
|
+
return { ok: false, reason: REJECTION_REASON.NO_PIPELINE_FOR_COLUMN };
|
|
18867
|
+
}
|
|
18868
|
+
const canonicalValue = readPipelineTargetValue(activity, pipeline.targetField);
|
|
18869
|
+
if (action.column === COLUMN.DURATION && !Number.isFinite(canonicalValue)) {
|
|
18870
|
+
return { ok: false, reason: REJECTION_REASON.INVALID_VALUE };
|
|
18871
|
+
}
|
|
18872
|
+
const raw = action.column === COLUMN.DURATION ? canonicalValue / deps.hoursPerDay : cloneDomainValue(canonicalValue);
|
|
18873
|
+
deps.clipboard.value = { kind: CELL_CLIPBOARD_KIND.FIELD, raw };
|
|
18874
|
+
return emptyChangeSet(action);
|
|
18875
|
+
}
|
|
18876
|
+
function dispatchCellClipboardClear(action, clipboard) {
|
|
18877
|
+
clipboard.value = null;
|
|
18878
|
+
return emptyChangeSet(action);
|
|
18879
|
+
}
|
|
18880
|
+
|
|
18881
|
+
// src/cell-copy-paste/paste.ts
|
|
18882
|
+
function toDiffPlaceholder(activityId) {
|
|
18883
|
+
return String(activityId);
|
|
18884
|
+
}
|
|
18885
|
+
function fromDiffPlaceholder(adapter, placeholder) {
|
|
18886
|
+
const activityId = placeholder;
|
|
18887
|
+
return adapter.activityExists(activityId) ? activityId : null;
|
|
18888
|
+
}
|
|
18889
|
+
function linkOperationsForTarget(targetActivityId, isPredecessors, clipboard, deps) {
|
|
18890
|
+
const desiredSpecs = clipboard.specs.map((spec) => ({
|
|
18891
|
+
correlativeId: toDiffPlaceholder(spec.otherActivityId),
|
|
18892
|
+
type: spec.type,
|
|
18893
|
+
lag: spec.lag
|
|
18894
|
+
}));
|
|
18895
|
+
const currentLinks = getIncidentLinkSnapshots(
|
|
18896
|
+
deps.adapter,
|
|
18897
|
+
targetActivityId,
|
|
18898
|
+
isPredecessors
|
|
18899
|
+
);
|
|
18900
|
+
const resolve = (placeholder) => fromDiffPlaceholder(deps.adapter, placeholder);
|
|
18901
|
+
const diff = isPredecessors ? diffLinks({
|
|
18902
|
+
targetActivityId,
|
|
18903
|
+
currentLinks,
|
|
18904
|
+
desiredSpecs,
|
|
18905
|
+
resolveActivityByCorrelative: resolve
|
|
18906
|
+
}) : diffOutgoingLinks({
|
|
18907
|
+
sourceActivityId: targetActivityId,
|
|
18908
|
+
currentLinks,
|
|
18909
|
+
desiredSpecs,
|
|
18910
|
+
resolveActivityByCorrelative: resolve
|
|
18911
|
+
});
|
|
18912
|
+
return diff.operations;
|
|
18913
|
+
}
|
|
18914
|
+
async function dispatchCellPasteCopied(action, options, deps) {
|
|
18915
|
+
const clipboard = deps.cellClipboard.value;
|
|
18916
|
+
if (clipboard === null) {
|
|
18917
|
+
return { ok: false, reason: REJECTION_REASON.CLIPBOARD_EMPTY };
|
|
18918
|
+
}
|
|
18919
|
+
if (action.activityIds.length === 0) {
|
|
18920
|
+
return { ok: false, reason: REJECTION_REASON.ACTIVITY_IDS_EMPTY };
|
|
18921
|
+
}
|
|
18922
|
+
const hasMissingActivity = action.activityIds.some(
|
|
18923
|
+
(activityId) => !deps.adapter.activityExists(activityId)
|
|
18924
|
+
);
|
|
18925
|
+
if (hasMissingActivity) {
|
|
18926
|
+
return { ok: false, reason: REJECTION_REASON.ACTIVITY_NOT_FOUND };
|
|
18927
|
+
}
|
|
18928
|
+
if (action.column === COLUMN.CUSTOM_PREDECESSORS || action.column === COLUMN.CUSTOM_SUCESSORS) {
|
|
18929
|
+
if (clipboard.kind !== CELL_CLIPBOARD_KIND.LINKS) {
|
|
18930
|
+
return { ok: false, reason: REJECTION_REASON.INVALID_VALUE };
|
|
18931
|
+
}
|
|
18932
|
+
const hasSelfReference = action.activityIds.some(
|
|
18933
|
+
(activityId) => clipboard.specs.some(
|
|
18934
|
+
(spec) => String(spec.otherActivityId) === String(activityId)
|
|
18935
|
+
)
|
|
18936
|
+
);
|
|
18937
|
+
if (hasSelfReference) {
|
|
18938
|
+
return { ok: false, reason: LINK_REJECTION_REASON.SELF_LINK };
|
|
18939
|
+
}
|
|
18940
|
+
const isPredecessors = action.column === COLUMN.CUSTOM_PREDECESSORS;
|
|
18941
|
+
const operations = action.activityIds.flatMap(
|
|
18942
|
+
(activityId) => linkOperationsForTarget(activityId, isPredecessors, clipboard, deps)
|
|
18943
|
+
);
|
|
18944
|
+
const createEntries = operations.filter(
|
|
18945
|
+
(operation) => operation.kind === LINK_OPERATION_KIND.CREATE
|
|
18946
|
+
).map((operation) => ({
|
|
18947
|
+
operation,
|
|
18948
|
+
linkId: deps.linkIdGen.next()
|
|
18949
|
+
}));
|
|
18950
|
+
const creation = validateLinkCreateBatch(createEntries, {
|
|
18951
|
+
port: deps.adapter,
|
|
18952
|
+
rejectParentLinkMutations: options.rejectParentLinkMutations ?? false
|
|
18953
|
+
});
|
|
18954
|
+
if (!creation.applied) {
|
|
18955
|
+
return {
|
|
18956
|
+
ok: false,
|
|
18957
|
+
reason: creation.rejected ?? REJECTION_REASON.INVALID
|
|
18958
|
+
};
|
|
18959
|
+
}
|
|
18960
|
+
return dispatchLinkBatch(operations, action, options, deps);
|
|
18961
|
+
}
|
|
18962
|
+
if (clipboard.kind !== CELL_CLIPBOARD_KIND.FIELD) {
|
|
18963
|
+
return { ok: false, reason: REJECTION_REASON.INVALID_VALUE };
|
|
18964
|
+
}
|
|
18965
|
+
if (!findPipelineForColumn(action.column)) {
|
|
18966
|
+
return { ok: false, reason: REJECTION_REASON.NO_PIPELINE_FOR_COLUMN };
|
|
18967
|
+
}
|
|
18968
|
+
const column = action.column;
|
|
18969
|
+
const result = await dispatchBulkEdit(
|
|
18970
|
+
{
|
|
18971
|
+
kind: DISPATCH_ACTION_KIND.BULK_EDIT,
|
|
18972
|
+
edits: action.activityIds.map((activityId) => ({
|
|
18973
|
+
activityId,
|
|
18974
|
+
column,
|
|
18975
|
+
newValue: clipboard.raw
|
|
18976
|
+
})),
|
|
18977
|
+
...action.eventSource === void 0 ? {} : { eventSource: action.eventSource }
|
|
18978
|
+
},
|
|
18979
|
+
options,
|
|
18980
|
+
deps
|
|
18981
|
+
);
|
|
18982
|
+
if (!result.ok) return result;
|
|
18983
|
+
return { ...result, changes: { ...result.changes, source: action } };
|
|
18984
|
+
}
|
|
18985
|
+
|
|
18483
18986
|
// src/dispatch/dispatch.ts
|
|
18484
18987
|
async function performDispatch(action, options, deps) {
|
|
18485
18988
|
if (action.kind === DISPATCH_ACTION_KIND.ACTIVITY_COPY) {
|
|
@@ -18497,6 +19000,22 @@ async function performDispatch(action, options, deps) {
|
|
|
18497
19000
|
if (action.kind === DISPATCH_ACTION_KIND.ACTIVITY_PASTE_COPIED) {
|
|
18498
19001
|
return dispatchActivityPasteCopied(action, options, deps);
|
|
18499
19002
|
}
|
|
19003
|
+
if (action.kind === DISPATCH_ACTION_KIND.ACTIVITY_DUPLICATE) {
|
|
19004
|
+
return dispatchActivityDuplicate(action, options, deps);
|
|
19005
|
+
}
|
|
19006
|
+
if (action.kind === DISPATCH_ACTION_KIND.CELL_COPY) {
|
|
19007
|
+
return dispatchCellCopy(action, {
|
|
19008
|
+
adapter: deps.adapter,
|
|
19009
|
+
clipboard: deps.cellClipboard,
|
|
19010
|
+
hoursPerDay: deps.sector.hoursPerDay
|
|
19011
|
+
});
|
|
19012
|
+
}
|
|
19013
|
+
if (action.kind === DISPATCH_ACTION_KIND.CELL_CLIPBOARD_CLEAR) {
|
|
19014
|
+
return dispatchCellClipboardClear(action, deps.cellClipboard);
|
|
19015
|
+
}
|
|
19016
|
+
if (action.kind === DISPATCH_ACTION_KIND.CELL_PASTE_COPIED) {
|
|
19017
|
+
return dispatchCellPasteCopied(action, options, deps);
|
|
19018
|
+
}
|
|
18500
19019
|
if (action.kind === ACTIVITY_BATCH_ACTION_KIND) {
|
|
18501
19020
|
return dispatchActivityBatch(action, options, deps);
|
|
18502
19021
|
}
|
|
@@ -30169,7 +30688,7 @@ function validateP6EndingActivitySearch(input) {
|
|
|
30169
30688
|
);
|
|
30170
30689
|
}
|
|
30171
30690
|
}
|
|
30172
|
-
function
|
|
30691
|
+
function emptyChangeSet2(source) {
|
|
30173
30692
|
return {
|
|
30174
30693
|
source,
|
|
30175
30694
|
activities: [],
|
|
@@ -30207,6 +30726,8 @@ function isCurrentFilterProjection(projection, filter, context) {
|
|
|
30207
30726
|
var ScheduleCore = class _ScheduleCore {
|
|
30208
30727
|
/** Activity reads and mutations. */
|
|
30209
30728
|
activities;
|
|
30729
|
+
/** Single-cell clipboard reads and mutations. */
|
|
30730
|
+
cells;
|
|
30210
30731
|
/** Dependency-link reads and mutations. */
|
|
30211
30732
|
links;
|
|
30212
30733
|
/** Calendar reads and reconciliation. */
|
|
@@ -30244,6 +30765,7 @@ var ScheduleCore = class _ScheduleCore {
|
|
|
30244
30765
|
schedule: (patch) => this._scheduleP6(patch)
|
|
30245
30766
|
});
|
|
30246
30767
|
_activityClipboard = { value: null };
|
|
30768
|
+
_cellClipboard = { value: null };
|
|
30247
30769
|
_status = SCHEDULE_CORE_STATUS.READY;
|
|
30248
30770
|
coreRuntime;
|
|
30249
30771
|
_isFork;
|
|
@@ -30288,6 +30810,9 @@ var ScheduleCore = class _ScheduleCore {
|
|
|
30288
30810
|
this._activityClipboard.value = cloneDomainValue(
|
|
30289
30811
|
source._activityClipboard.value
|
|
30290
30812
|
);
|
|
30813
|
+
this._cellClipboard.value = cloneDomainValue(
|
|
30814
|
+
source._cellClipboard.value
|
|
30815
|
+
);
|
|
30291
30816
|
this._undo = source._undo.fork();
|
|
30292
30817
|
this._saveTracker = source._saveTracker.fork();
|
|
30293
30818
|
this._scheduleRevision = source._scheduleRevision;
|
|
@@ -31516,7 +32041,7 @@ var ScheduleCore = class _ScheduleCore {
|
|
|
31516
32041
|
});
|
|
31517
32042
|
continue;
|
|
31518
32043
|
}
|
|
31519
|
-
const changes =
|
|
32044
|
+
const changes = emptyChangeSet2(action);
|
|
31520
32045
|
results.push({ ok: true, changes });
|
|
31521
32046
|
acceptedChangeSets.push(changes);
|
|
31522
32047
|
acceptedActions.push(action);
|
|
@@ -31645,6 +32170,7 @@ var ScheduleCore = class _ScheduleCore {
|
|
|
31645
32170
|
customIdTracker: this.coreRuntime.customIdTracker,
|
|
31646
32171
|
reporter: this.coreRuntime.reporter,
|
|
31647
32172
|
activityClipboard: this._activityClipboard,
|
|
32173
|
+
cellClipboard: this._cellClipboard,
|
|
31648
32174
|
stateRevision: this._stateRevision,
|
|
31649
32175
|
defaultBaseCalendarId: this.coreRuntime.baseCalendars.find(
|
|
31650
32176
|
(calendar) => calendar.baseDefault
|