@outbuild-company/schedule-core 1.10.3 → 1.11.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/index.cjs CHANGED
@@ -4284,15 +4284,28 @@ var setDuration = (value) => ({
4284
4284
  });
4285
4285
 
4286
4286
  // src/columns/start-date/start-date-pipeline.ts
4287
+ var SIR_APPLY_EVENT_SOURCE = "sir-apply";
4287
4288
  var startDatePipeline = {
4288
4289
  targetField: "startDate",
4289
- canEdit(activity, hierarchy) {
4290
+ canEdit(activity, hierarchy, edit) {
4290
4291
  if (isSummaryActivity2(activity, hierarchy)) {
4291
4292
  return cannotEdit("summary", "summary_column_value");
4292
4293
  }
4293
- if (hasProgress(activity)) {
4294
+ if (!hasProgress(activity)) return canEdit();
4295
+ if (edit?.eventSource !== SIR_APPLY_EVENT_SOURCE) {
4294
4296
  return cannotEdit("has_progress", "cant_edit_activity_with_progress");
4295
4297
  }
4298
+ if (isCompletedActivity(activity)) {
4299
+ return cannotEdit("completed", "cant_edit_completed_activity");
4300
+ }
4301
+ if (!isValidDate(edit.newValue)) return canEdit();
4302
+ if (isSameDay(activity.startDate, edit.newValue)) return canEdit();
4303
+ if (edit.newValue.getTime() > activity.startDate.getTime()) {
4304
+ return cannotEdit(
4305
+ "sir_start_after_progress",
4306
+ "sir_cant_move_start_after_progress"
4307
+ );
4308
+ }
4296
4309
  return canEdit();
4297
4310
  },
4298
4311
  parseInput(rawValue, _activity, _ctx) {
@@ -13862,7 +13875,7 @@ async function dispatchBulkEdit(action, options, deps) {
13862
13875
  const warnings = [];
13863
13876
  let needsAutoSchedule = false;
13864
13877
  for (const edit of action.edits) {
13865
- const outcome = applyOneEdit2(edit, deps);
13878
+ const outcome = applyOneEdit2(edit, deps, action.eventSource);
13866
13879
  verdicts.push(outcome.verdict);
13867
13880
  if (!outcome.verdict.ok || !outcome.changes) continue;
13868
13881
  const constraintWarning = toConstraintWarning(
@@ -13958,7 +13971,7 @@ async function dispatchBulkEdit(action, options, deps) {
13958
13971
  })
13959
13972
  };
13960
13973
  }
13961
- function applyOneEdit2(edit, deps) {
13974
+ function applyOneEdit2(edit, deps, eventSource) {
13962
13975
  const { ctx } = deps;
13963
13976
  const activityId = edit.activityId;
13964
13977
  const pipeline = findPipelineForColumn(edit.column);
@@ -13983,7 +13996,10 @@ function applyOneEdit2(edit, deps) {
13983
13996
  changes: null
13984
13997
  };
13985
13998
  }
13986
- const editGate = pipeline.canEdit(activitySnap, ctx.hierarchy);
13999
+ const editGate = pipeline.canEdit(activitySnap, ctx.hierarchy, {
14000
+ eventSource,
14001
+ newValue: edit.newValue
14002
+ });
13987
14003
  if (!editGate.allowed) {
13988
14004
  return {
13989
14005
  verdict: {
@@ -14390,6 +14406,64 @@ async function dispatchStatusCriteriaSet(action, deps) {
14390
14406
  };
14391
14407
  }
14392
14408
 
14409
+ // src/dispatch/handlers/calendar-reconcile.ts
14410
+ async function dispatchCalendarReconcile(action, options, deps) {
14411
+ const beforeSnap = /* @__PURE__ */ new Map();
14412
+ const touchedIds = /* @__PURE__ */ new Set();
14413
+ for (const activity of deps.adapter.getAllActivities()) {
14414
+ if (!shouldReconcile(activity, deps)) continue;
14415
+ const calendar = deps.ctx.calendars.getCalendar(activity.calendarId);
14416
+ if (!calendar) continue;
14417
+ const startDate = calendar.getClosestWorkTime({
14418
+ date: activity.startDate,
14419
+ direction: WORK_TIME_DIRECTION.FUTURE,
14420
+ unit: CALENDAR_UNIT.HOUR
14421
+ });
14422
+ const endDate = calendar.calculateEndDate(
14423
+ startDate,
14424
+ activity.durationHours
14425
+ );
14426
+ if (sameInstant(startDate, activity.startDate) && sameInstant(endDate, activity.endDate)) {
14427
+ continue;
14428
+ }
14429
+ const activityId = String(activity.id);
14430
+ beforeSnap.set(activityId, structuredCloneActivity(activity));
14431
+ touchedIds.add(activityId);
14432
+ deps.adapter.setActivityFields(activityId, { startDate, endDate });
14433
+ }
14434
+ const { scheduledIds } = await runPostMutation(
14435
+ {
14436
+ adapter: deps.adapter,
14437
+ scheduler: deps.scheduler,
14438
+ sector: deps.sector,
14439
+ defaultBaseCalendarId: deps.defaultBaseCalendarId
14440
+ },
14441
+ {
14442
+ action,
14443
+ autoscheduleFrom: "roots",
14444
+ recomputeParentsFrom: touchedIds,
14445
+ now: deps.now,
14446
+ options
14447
+ }
14448
+ );
14449
+ return {
14450
+ ok: true,
14451
+ changes: await assembleChangeSet(deps.adapter, {
14452
+ source: action,
14453
+ beforeSnap,
14454
+ touchedIds,
14455
+ scheduledIds,
14456
+ hoursPerDay: deps.sector.hoursPerDay
14457
+ })
14458
+ };
14459
+ }
14460
+ function shouldReconcile(activity, deps) {
14461
+ return activity.progress === 0 && !isSummary(activity.type, deps.adapter.hasChildren(activity.id));
14462
+ }
14463
+ function sameInstant(first, second) {
14464
+ return first.getTime() === second.getTime();
14465
+ }
14466
+
14393
14467
  // src/activity-copy-paste/policy.ts
14394
14468
  var ACTIVITY_COPY_FIELDS = [
14395
14469
  "name",
@@ -14599,6 +14673,9 @@ async function performDispatch(action, options, deps) {
14599
14673
  clipboard: deps.activityClipboard
14600
14674
  });
14601
14675
  }
14676
+ if (action.kind === "calendar-reconcile") {
14677
+ return dispatchCalendarReconcile(action, options, deps);
14678
+ }
14602
14679
  if (action.kind === "activity-clipboard-clear") {
14603
14680
  return dispatchActivityClipboardClear(action, deps.activityClipboard);
14604
14681
  }
@@ -18557,7 +18634,7 @@ function getDispatchHistoryPolicy(action) {
18557
18634
  if (action.kind === "persistence-acknowledge") {
18558
18635
  return "checkpoint-on-success";
18559
18636
  }
18560
- if (action.kind === "sir-sync" || action.kind === "activity-lookahead-sync" || action.kind === "baseline-apply" || action.kind === "ponderator-criterion-set" || action.kind === "status-criteria-set" || action.kind === "activity-clipboard-clear" || action.kind === "activity-copy" || action.kind === "selection-toggle" || action.kind === "selection-replace" || action.kind === "visibility-set" || action.kind === "filter-set" || action.kind === "sort-set") {
18637
+ if (action.kind === "sir-sync" || action.kind === "calendar-reconcile" || action.kind === "activity-lookahead-sync" || action.kind === "baseline-apply" || action.kind === "ponderator-criterion-set" || action.kind === "status-criteria-set" || action.kind === "activity-clipboard-clear" || action.kind === "activity-copy" || action.kind === "selection-toggle" || action.kind === "selection-replace" || action.kind === "visibility-set" || action.kind === "filter-set" || action.kind === "sort-set") {
18561
18638
  return "skip";
18562
18639
  }
18563
18640
  return "record";
@@ -21346,11 +21423,7 @@ var ScheduleCore = class _ScheduleCore {
21346
21423
  );
21347
21424
  });
21348
21425
  this._criticalPathReady = this._initPromise.then(
21349
- () => this._enqueue(async () => {
21350
- const result = await this._runCriticalPathAndCapture();
21351
- this._criticalPathRevision = this._scheduleRevision;
21352
- return result;
21353
- })
21426
+ () => this._startCriticalPathForCurrentRevision()
21354
21427
  );
21355
21428
  const waitForCriticalPathOnLoad = input.criticalPathOnLoad === true;
21356
21429
  this._ready = waitForCriticalPathOnLoad ? this._criticalPathReady.then(() => void 0) : this._initPromise;
@@ -21988,39 +22061,6 @@ var ScheduleCore = class _ScheduleCore {
21988
22061
  void promise.then(clearIfActive, clearIfActive);
21989
22062
  return promise;
21990
22063
  }
21991
- async _runCriticalPathAndCapture() {
21992
- if (this._status === SCHEDULE_CORE_STATUS.DESTROYED) {
21993
- return {
21994
- changes: {
21995
- source: { kind: "init" },
21996
- activities: [],
21997
- links: [],
21998
- calendars: [],
21999
- trackingEvents: []
22000
- }
22001
- };
22002
- }
22003
- this.coreRuntime.state.beginWriteCapture();
22004
- this.coreRuntime.customIdTracker.beginCustomIdTransaction();
22005
- let changes;
22006
- try {
22007
- await applyCriticalPath(
22008
- this.coreRuntime.state,
22009
- this.coreRuntime.sector.hoursPerDay
22010
- );
22011
- changes = await assembleChangeSet(this.coreRuntime.state, {
22012
- source: { kind: "init" },
22013
- beforeSnap: /* @__PURE__ */ new Map(),
22014
- touchedIds: [],
22015
- scheduledIds: [],
22016
- hoursPerDay: this.coreRuntime.sector.hoursPerDay
22017
- });
22018
- } finally {
22019
- this.coreRuntime.state.endWriteCapture();
22020
- this.coreRuntime.customIdTracker.commitCustomIdTransaction();
22021
- }
22022
- return { changes };
22023
- }
22024
22064
  undo(options = {}) {
22025
22065
  const admitted = this._admitScheduleMutation();
22026
22066
  let changedState = false;
@@ -22218,6 +22258,7 @@ var DEFAULT_HOURS_PER_DAY = 8;
22218
22258
  var DISPATCH_ACTION_KIND = {
22219
22259
  ACTIVITY_CLIPBOARD_CLEAR: "activity-clipboard-clear",
22220
22260
  ACTIVITY_COPY: "activity-copy",
22261
+ CALENDAR_RECONCILE: "calendar-reconcile",
22221
22262
  ACTIVITY_PASTE_COPIED: "activity-paste-copied",
22222
22263
  PERSISTENCE_ACKNOWLEDGE: "persistence-acknowledge",
22223
22264
  BASELINE_APPLY: "baseline-apply",
@@ -22247,6 +22288,7 @@ var DISPATCH_ACTION_KIND = {
22247
22288
  var KIND_CATALOG_COVERS_UNION = {
22248
22289
  [DISPATCH_ACTION_KIND.ACTIVITY_CLIPBOARD_CLEAR]: true,
22249
22290
  [DISPATCH_ACTION_KIND.ACTIVITY_COPY]: true,
22291
+ [DISPATCH_ACTION_KIND.CALENDAR_RECONCILE]: true,
22250
22292
  [DISPATCH_ACTION_KIND.ACTIVITY_PASTE_COPIED]: true,
22251
22293
  [DISPATCH_ACTION_KIND.PERSISTENCE_ACKNOWLEDGE]: true,
22252
22294
  [DISPATCH_ACTION_KIND.BASELINE_APPLY]: true,