@outbuild-company/schedule-core 1.10.2 → 1.10.4

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.d.cts CHANGED
@@ -885,7 +885,6 @@ declare class ScheduleCore {
885
885
  private _reapplyActiveFilter;
886
886
  private _recordScheduleMutation;
887
887
  private _startCriticalPathForCurrentRevision;
888
- private _runCriticalPathAndCapture;
889
888
  undo(options?: UndoOptions): Promise<ChangeSet | null>;
890
889
  private _runUndo;
891
890
  redo(options?: {
package/dist/index.d.ts CHANGED
@@ -885,7 +885,6 @@ declare class ScheduleCore {
885
885
  private _reapplyActiveFilter;
886
886
  private _recordScheduleMutation;
887
887
  private _startCriticalPathForCurrentRevision;
888
- private _runCriticalPathAndCapture;
889
888
  undo(options?: UndoOptions): Promise<ChangeSet | null>;
890
889
  private _runUndo;
891
890
  redo(options?: {
package/dist/index.js CHANGED
@@ -4282,15 +4282,28 @@ var setDuration = (value) => ({
4282
4282
  });
4283
4283
 
4284
4284
  // src/columns/start-date/start-date-pipeline.ts
4285
+ var SIR_APPLY_EVENT_SOURCE = "sir-apply";
4285
4286
  var startDatePipeline = {
4286
4287
  targetField: "startDate",
4287
- canEdit(activity, hierarchy) {
4288
+ canEdit(activity, hierarchy, edit) {
4288
4289
  if (isSummaryActivity2(activity, hierarchy)) {
4289
4290
  return cannotEdit("summary", "summary_column_value");
4290
4291
  }
4291
- if (hasProgress(activity)) {
4292
+ if (!hasProgress(activity)) return canEdit();
4293
+ if (edit?.eventSource !== SIR_APPLY_EVENT_SOURCE) {
4292
4294
  return cannotEdit("has_progress", "cant_edit_activity_with_progress");
4293
4295
  }
4296
+ if (isCompletedActivity(activity)) {
4297
+ return cannotEdit("completed", "cant_edit_completed_activity");
4298
+ }
4299
+ if (!isValidDate(edit.newValue)) return canEdit();
4300
+ if (isSameDay(activity.startDate, edit.newValue)) return canEdit();
4301
+ if (edit.newValue.getTime() > activity.startDate.getTime()) {
4302
+ return cannotEdit(
4303
+ "sir_start_after_progress",
4304
+ "sir_cant_move_start_after_progress"
4305
+ );
4306
+ }
4294
4307
  return canEdit();
4295
4308
  },
4296
4309
  parseInput(rawValue, _activity, _ctx) {
@@ -9701,13 +9714,41 @@ async function createGanttAdapter(state, hoursPerDay) {
9701
9714
 
9702
9715
  // src/critical-path/run-critical-path.ts
9703
9716
  var CP_WRITE_YIELD_EVERY = 1e3;
9704
- function fieldsForLink(rawResidual, sourceIsCritical, targetIsCritical, targetProgress) {
9705
- const freeSlackHours = typeof rawResidual === "number" && Number.isFinite(rawResidual) ? Object.is(rawResidual, -0) ? 0 : rawResidual : null;
9717
+ var finiteHoursOrNull = (value) => {
9718
+ if (typeof value !== "number" || !Number.isFinite(value)) return null;
9719
+ return Object.is(value, -0) ? 0 : value;
9720
+ };
9721
+ var linkFreeFloatDaysToHours = (valueDays, hoursPerDay) => {
9722
+ if (typeof valueDays !== "number" || valueDays < 0) return null;
9723
+ return slackDaysToHours(valueDays, hoursPerDay);
9724
+ };
9725
+ function fieldsForLink(input) {
9726
+ const freeSlackHours = linkFreeFloatDaysToHours(
9727
+ input.freeFloatDays,
9728
+ input.hoursPerDay
9729
+ );
9730
+ const residualHours = finiteHoursOrNull(input.residualHours);
9706
9731
  return {
9707
9732
  freeSlackHours,
9708
- isCritical: freeSlackHours !== null && freeSlackHours <= 0 && sourceIsCritical && targetIsCritical && targetProgress === 0
9733
+ isCritical: residualHours !== null && residualHours <= 0 && input.sourceIsCritical && input.targetIsCritical && input.targetProgress === 0
9709
9734
  };
9710
9735
  }
9736
+ async function collectLinkFreeFloatDays(freeFloat, isCurrent) {
9737
+ const values = /* @__PURE__ */ new Map();
9738
+ let sinceYield = 0;
9739
+ for (const calculation of freeFloat.values()) {
9740
+ for (const linkId in calculation.linksFreeFloat) {
9741
+ if (!Object.hasOwn(calculation.linksFreeFloat, linkId)) continue;
9742
+ if (++sinceYield >= CP_WRITE_YIELD_EVERY) {
9743
+ sinceYield = 0;
9744
+ await yieldToBrowser();
9745
+ if (!isCurrent()) return null;
9746
+ }
9747
+ values.set(String(linkId), calculation.linksFreeFloat[linkId]);
9748
+ }
9749
+ }
9750
+ return isCurrent() ? values : null;
9751
+ }
9711
9752
  async function collectActivityFields(state, maps, hoursPerDay, toCanonicalActivityId, isCurrent) {
9712
9753
  const fields = /* @__PURE__ */ new Map();
9713
9754
  let sinceYield = 0;
@@ -9733,7 +9774,7 @@ async function collectActivityFields(state, maps, hoursPerDay, toCanonicalActivi
9733
9774
  }
9734
9775
  return isCurrent() ? fields : null;
9735
9776
  }
9736
- async function collectLinkFields(state, linkResidualHours, activityFields, isCurrent) {
9777
+ async function collectLinkFields(state, linkFreeFloatDays, linkResidualHours, activityFields, hoursPerDay, isCurrent) {
9737
9778
  const fields = /* @__PURE__ */ new Map();
9738
9779
  let sinceYield = 0;
9739
9780
  for (const link of state.getAllLinks()) {
@@ -9744,12 +9785,14 @@ async function collectLinkFields(state, linkResidualHours, activityFields, isCur
9744
9785
  }
9745
9786
  fields.set(
9746
9787
  String(link.id),
9747
- fieldsForLink(
9748
- linkResidualHours.get(String(link.id)),
9749
- activityFields.get(link.source)?.isCritical === true,
9750
- activityFields.get(link.target)?.isCritical === true,
9751
- state.getActivity(link.target)?.progress
9752
- )
9788
+ fieldsForLink({
9789
+ freeFloatDays: linkFreeFloatDays.get(String(link.id)),
9790
+ residualHours: linkResidualHours.get(String(link.id)),
9791
+ hoursPerDay,
9792
+ sourceIsCritical: activityFields.get(link.source)?.isCritical === true,
9793
+ targetIsCritical: activityFields.get(link.target)?.isCritical === true,
9794
+ targetProgress: state.getActivity(link.target)?.progress
9795
+ })
9753
9796
  );
9754
9797
  }
9755
9798
  return isCurrent() ? fields : null;
@@ -9832,10 +9875,17 @@ async function computeCriticalPathFields(state, hoursPerDay, isCurrent = () => t
9832
9875
  isCurrent
9833
9876
  );
9834
9877
  if (!activities) return null;
9878
+ const linkFreeFloatDays = await collectLinkFreeFloatDays(
9879
+ maps.freeFloat,
9880
+ isCurrent
9881
+ );
9882
+ if (!linkFreeFloatDays) return null;
9835
9883
  const links = await collectLinkFields(
9836
9884
  state,
9885
+ linkFreeFloatDays,
9837
9886
  criticalPath.linkResidualHours,
9838
9887
  activities,
9888
+ hoursPerDay,
9839
9889
  isCurrent
9840
9890
  );
9841
9891
  return links ? { activities, links } : null;
@@ -13823,7 +13873,7 @@ async function dispatchBulkEdit(action, options, deps) {
13823
13873
  const warnings = [];
13824
13874
  let needsAutoSchedule = false;
13825
13875
  for (const edit of action.edits) {
13826
- const outcome = applyOneEdit2(edit, deps);
13876
+ const outcome = applyOneEdit2(edit, deps, action.eventSource);
13827
13877
  verdicts.push(outcome.verdict);
13828
13878
  if (!outcome.verdict.ok || !outcome.changes) continue;
13829
13879
  const constraintWarning = toConstraintWarning(
@@ -13919,7 +13969,7 @@ async function dispatchBulkEdit(action, options, deps) {
13919
13969
  })
13920
13970
  };
13921
13971
  }
13922
- function applyOneEdit2(edit, deps) {
13972
+ function applyOneEdit2(edit, deps, eventSource) {
13923
13973
  const { ctx } = deps;
13924
13974
  const activityId = edit.activityId;
13925
13975
  const pipeline = findPipelineForColumn(edit.column);
@@ -13944,7 +13994,10 @@ function applyOneEdit2(edit, deps) {
13944
13994
  changes: null
13945
13995
  };
13946
13996
  }
13947
- const editGate = pipeline.canEdit(activitySnap, ctx.hierarchy);
13997
+ const editGate = pipeline.canEdit(activitySnap, ctx.hierarchy, {
13998
+ eventSource,
13999
+ newValue: edit.newValue
14000
+ });
13948
14001
  if (!editGate.allowed) {
13949
14002
  return {
13950
14003
  verdict: {
@@ -21307,11 +21360,7 @@ var ScheduleCore = class _ScheduleCore {
21307
21360
  );
21308
21361
  });
21309
21362
  this._criticalPathReady = this._initPromise.then(
21310
- () => this._enqueue(async () => {
21311
- const result = await this._runCriticalPathAndCapture();
21312
- this._criticalPathRevision = this._scheduleRevision;
21313
- return result;
21314
- })
21363
+ () => this._startCriticalPathForCurrentRevision()
21315
21364
  );
21316
21365
  const waitForCriticalPathOnLoad = input.criticalPathOnLoad === true;
21317
21366
  this._ready = waitForCriticalPathOnLoad ? this._criticalPathReady.then(() => void 0) : this._initPromise;
@@ -21949,39 +21998,6 @@ var ScheduleCore = class _ScheduleCore {
21949
21998
  void promise.then(clearIfActive, clearIfActive);
21950
21999
  return promise;
21951
22000
  }
21952
- async _runCriticalPathAndCapture() {
21953
- if (this._status === SCHEDULE_CORE_STATUS.DESTROYED) {
21954
- return {
21955
- changes: {
21956
- source: { kind: "init" },
21957
- activities: [],
21958
- links: [],
21959
- calendars: [],
21960
- trackingEvents: []
21961
- }
21962
- };
21963
- }
21964
- this.coreRuntime.state.beginWriteCapture();
21965
- this.coreRuntime.customIdTracker.beginCustomIdTransaction();
21966
- let changes;
21967
- try {
21968
- await applyCriticalPath(
21969
- this.coreRuntime.state,
21970
- this.coreRuntime.sector.hoursPerDay
21971
- );
21972
- changes = await assembleChangeSet(this.coreRuntime.state, {
21973
- source: { kind: "init" },
21974
- beforeSnap: /* @__PURE__ */ new Map(),
21975
- touchedIds: [],
21976
- scheduledIds: [],
21977
- hoursPerDay: this.coreRuntime.sector.hoursPerDay
21978
- });
21979
- } finally {
21980
- this.coreRuntime.state.endWriteCapture();
21981
- this.coreRuntime.customIdTracker.commitCustomIdTransaction();
21982
- }
21983
- return { changes };
21984
- }
21985
22001
  undo(options = {}) {
21986
22002
  const admitted = this._admitScheduleMutation();
21987
22003
  let changedState = false;