@outbuild-company/schedule-core 1.2.0 → 1.4.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 +1105 -1388
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +119 -822
- package/dist/index.d.ts +119 -822
- package/dist/index.js +1105 -1388
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
package/dist/index.js
CHANGED
|
@@ -5,14 +5,12 @@ var Queue = class {
|
|
|
5
5
|
enqueue(item) {
|
|
6
6
|
this.items.push(item);
|
|
7
7
|
}
|
|
8
|
-
/** Removes and returns the oldest item, or `undefined` when empty. */
|
|
9
8
|
dequeue() {
|
|
10
9
|
if (this.head >= this.items.length) return void 0;
|
|
11
10
|
const item = this.items[this.head];
|
|
12
11
|
this.head += 1;
|
|
13
12
|
return item;
|
|
14
13
|
}
|
|
15
|
-
/** The oldest item without removing it, or `undefined` when empty. */
|
|
16
14
|
peek() {
|
|
17
15
|
if (this.head >= this.items.length) return void 0;
|
|
18
16
|
return this.items[this.head];
|
|
@@ -123,33 +121,24 @@ function isFrozen(activity) {
|
|
|
123
121
|
|
|
124
122
|
// src/dispatch/reasons.ts
|
|
125
123
|
var REJECTION_REASON = {
|
|
126
|
-
// Pipeline-gate fallbacks (used when a gate rejects without a reason).
|
|
127
124
|
CANNOT_EDIT: "cannot_edit",
|
|
128
125
|
PARSE_ERROR: "parse_error",
|
|
129
126
|
INVALID: "invalid",
|
|
130
|
-
// Inline-edit / link validation.
|
|
131
127
|
CUSTOM_ID_DUPLICATE: "custom_id_duplicate",
|
|
132
128
|
INVALID_LINK_TYPE: "invalid_link_type",
|
|
133
129
|
INVALID_LINK_LAG: "invalid_link_lag",
|
|
134
130
|
INVALID_VALUE: "invalid_value",
|
|
135
|
-
// Bulk-edit: the column has no registered pipeline (unknown column, or a
|
|
136
|
-
// link column like custom_predecessors that dispatches as link intents).
|
|
137
131
|
NO_PIPELINE_FOR_COLUMN: "no_pipeline_for_column",
|
|
138
|
-
// Entity lookups.
|
|
139
132
|
ACTIVITY_NOT_FOUND: "activity_not_found",
|
|
140
133
|
PARENT_NOT_FOUND: "parent_not_found",
|
|
141
134
|
ACTIVITY_IDS_EMPTY: "activity_ids_empty",
|
|
142
|
-
// Anchored positioning (create / move).
|
|
143
135
|
ANCHOR_SIBLING_CONFLICT: "anchor_sibling_conflict",
|
|
144
136
|
ANCHOR_SIBLING_NOT_FOUND: "anchor_sibling_not_found",
|
|
145
137
|
ANCHOR_SIBLING_WRONG_PARENT: "anchor_sibling_wrong_parent",
|
|
146
|
-
// SIR freeze: cannot add a child under an activity with a pending SIR.
|
|
147
138
|
PARENT_FROZEN_BY_SIR: "parent_frozen_by_sir",
|
|
148
|
-
// Hierarchy rules.
|
|
149
139
|
CANNOT_MOVE_INTO_OWN_DESCENDANT: "cannot_move_into_own_descendant",
|
|
150
140
|
INDENT_NO_ELIGIBLE_SIBLING: "indent_no_eligible_sibling",
|
|
151
141
|
OUTDENT_ROOT_LEVEL_NOT_EDITABLE: "outdent_root_level_not_editable",
|
|
152
|
-
// Progress button.
|
|
153
142
|
INVALID_PROGRESS_VALUE: "invalid_progress_value_must_be_0_or_100"
|
|
154
143
|
};
|
|
155
144
|
|
|
@@ -220,14 +209,12 @@ function dispatchSelectionReplace(action, deps) {
|
|
|
220
209
|
};
|
|
221
210
|
}
|
|
222
211
|
|
|
223
|
-
// src/dispatch/
|
|
224
|
-
function
|
|
225
|
-
const { adapter } = deps;
|
|
226
|
-
const targetVisible = new Set(action.visibleIds.map(String));
|
|
212
|
+
// src/dispatch/shared/apply-visible-set.ts
|
|
213
|
+
function applyVisibleSet(adapter, visibleIds) {
|
|
227
214
|
const viewState = [];
|
|
228
215
|
adapter.forEachActivity((_snapshot, activityId) => {
|
|
229
216
|
const id = String(activityId);
|
|
230
|
-
const willBeVisible =
|
|
217
|
+
const willBeVisible = visibleIds.has(id);
|
|
231
218
|
const before = adapter.isVisible(id);
|
|
232
219
|
if (before === willBeVisible) return;
|
|
233
220
|
adapter.setVisible(id, willBeVisible);
|
|
@@ -236,6 +223,390 @@ function dispatchVisibilitySet(action, deps) {
|
|
|
236
223
|
visible: { before, after: willBeVisible }
|
|
237
224
|
});
|
|
238
225
|
});
|
|
226
|
+
return viewState;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// src/dispatch/visibility.ts
|
|
230
|
+
function dispatchVisibilitySet(action, deps) {
|
|
231
|
+
const { adapter } = deps;
|
|
232
|
+
const targetVisible = new Set(action.visibleIds.map(String));
|
|
233
|
+
const viewState = applyVisibleSet(adapter, targetVisible);
|
|
234
|
+
const changes = {
|
|
235
|
+
source: action,
|
|
236
|
+
activities: [],
|
|
237
|
+
links: [],
|
|
238
|
+
calendars: [],
|
|
239
|
+
trackingEvents: [],
|
|
240
|
+
viewState
|
|
241
|
+
};
|
|
242
|
+
return { ok: true, changes };
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// src/internal/filter/field-registry.ts
|
|
246
|
+
var STATUS_ORDER = [
|
|
247
|
+
"Waiting",
|
|
248
|
+
"Done",
|
|
249
|
+
"Doing",
|
|
250
|
+
"Overdue",
|
|
251
|
+
"Advancement"
|
|
252
|
+
];
|
|
253
|
+
var CONSTRAINT_TYPE_ORDER = [
|
|
254
|
+
"mfo",
|
|
255
|
+
"mso",
|
|
256
|
+
"snlt",
|
|
257
|
+
"snet",
|
|
258
|
+
"alap",
|
|
259
|
+
"asap",
|
|
260
|
+
"fnet",
|
|
261
|
+
"fnlt"
|
|
262
|
+
];
|
|
263
|
+
var MILLISECONDS_PER_DAY = 1e3 * 60 * 60 * 24;
|
|
264
|
+
function toDays(hours, hoursPerDay) {
|
|
265
|
+
if (hours === null) return null;
|
|
266
|
+
if (hoursPerDay <= 0) return null;
|
|
267
|
+
return hours / hoursPerDay;
|
|
268
|
+
}
|
|
269
|
+
function calendarDaySpan(startDate, endDate) {
|
|
270
|
+
const elapsed = endDate.getTime() - startDate.getTime();
|
|
271
|
+
return Math.floor(elapsed / MILLISECONDS_PER_DAY) + 1;
|
|
272
|
+
}
|
|
273
|
+
var FIELD_REGISTRY = {
|
|
274
|
+
name: { valueKind: "string", extract: (activity) => activity.name },
|
|
275
|
+
description: {
|
|
276
|
+
valueKind: "string",
|
|
277
|
+
extract: (activity) => activity.description
|
|
278
|
+
},
|
|
279
|
+
customId: { valueKind: "string", extract: (activity) => activity.customId },
|
|
280
|
+
correlativeId: {
|
|
281
|
+
valueKind: "number",
|
|
282
|
+
extract: (activity) => activity.correlativeId
|
|
283
|
+
},
|
|
284
|
+
uniqueCorrelativeId: {
|
|
285
|
+
valueKind: "number",
|
|
286
|
+
extract: (activity) => Number(activity.uniqueCorrelativeId)
|
|
287
|
+
},
|
|
288
|
+
progress: { valueKind: "number", extract: (activity) => activity.progress },
|
|
289
|
+
durationDays: {
|
|
290
|
+
valueKind: "number",
|
|
291
|
+
extract: (activity, context) => toDays(activity.durationHours, context.hoursPerDay)
|
|
292
|
+
},
|
|
293
|
+
calendarDuration: {
|
|
294
|
+
valueKind: "number",
|
|
295
|
+
extract: (activity) => calendarDaySpan(activity.startDate, activity.endDate)
|
|
296
|
+
},
|
|
297
|
+
cost: { valueKind: "number", extract: (activity) => activity.cost },
|
|
298
|
+
usedCost: { valueKind: "number", extract: (activity) => activity.usedCost },
|
|
299
|
+
realCost: { valueKind: "number", extract: (activity) => activity.realCost },
|
|
300
|
+
workHours: { valueKind: "number", extract: (activity) => activity.workHours },
|
|
301
|
+
realWorkHours: {
|
|
302
|
+
valueKind: "number",
|
|
303
|
+
extract: (activity) => activity.realWorkHours
|
|
304
|
+
},
|
|
305
|
+
ponderator: {
|
|
306
|
+
valueKind: "number",
|
|
307
|
+
extract: (activity) => activity.ponderator
|
|
308
|
+
},
|
|
309
|
+
freeSlackDays: {
|
|
310
|
+
valueKind: "number",
|
|
311
|
+
extract: (activity, context) => toDays(activity.freeSlackHours, context.hoursPerDay)
|
|
312
|
+
},
|
|
313
|
+
totalSlackDays: {
|
|
314
|
+
valueKind: "number",
|
|
315
|
+
extract: (activity, context) => toDays(
|
|
316
|
+
activity.criticalPath?.totalSlackHours ?? null,
|
|
317
|
+
context.hoursPerDay
|
|
318
|
+
)
|
|
319
|
+
},
|
|
320
|
+
expectedProgressBaseline: {
|
|
321
|
+
valueKind: "number",
|
|
322
|
+
extract: (activity) => activity.expectedProgressBaseline
|
|
323
|
+
},
|
|
324
|
+
baselineDurationDays: {
|
|
325
|
+
valueKind: "number",
|
|
326
|
+
extract: (activity) => activity.baselineSnapshot?.durationDays ?? null
|
|
327
|
+
},
|
|
328
|
+
baselineCost: {
|
|
329
|
+
valueKind: "number",
|
|
330
|
+
extract: (activity) => activity.baselineSnapshot?.cost ?? null
|
|
331
|
+
},
|
|
332
|
+
baselineWorkHours: {
|
|
333
|
+
valueKind: "number",
|
|
334
|
+
extract: (activity) => activity.baselineSnapshot?.workHours ?? null
|
|
335
|
+
},
|
|
336
|
+
startDate: { valueKind: "date", extract: (activity) => activity.startDate },
|
|
337
|
+
endDate: { valueKind: "date", extract: (activity) => activity.endDate },
|
|
338
|
+
constraintDate: {
|
|
339
|
+
valueKind: "date",
|
|
340
|
+
extract: (activity) => activity.constraintDate
|
|
341
|
+
},
|
|
342
|
+
baselineStartDate: {
|
|
343
|
+
valueKind: "date",
|
|
344
|
+
extract: (activity) => activity.baselineSnapshot?.startDate ?? null
|
|
345
|
+
},
|
|
346
|
+
baselineEndDate: {
|
|
347
|
+
valueKind: "date",
|
|
348
|
+
extract: (activity) => activity.baselineSnapshot?.endDate ?? null
|
|
349
|
+
},
|
|
350
|
+
earlyStart: {
|
|
351
|
+
valueKind: "date",
|
|
352
|
+
extract: (activity) => activity.criticalPath?.earlyStart ?? null
|
|
353
|
+
},
|
|
354
|
+
earlyFinish: {
|
|
355
|
+
valueKind: "date",
|
|
356
|
+
extract: (activity) => activity.criticalPath?.earlyFinish ?? null
|
|
357
|
+
},
|
|
358
|
+
lateStart: {
|
|
359
|
+
valueKind: "date",
|
|
360
|
+
extract: (activity) => activity.criticalPath?.lateStart ?? null
|
|
361
|
+
},
|
|
362
|
+
lateFinish: {
|
|
363
|
+
valueKind: "date",
|
|
364
|
+
extract: (activity) => activity.criticalPath?.lateFinish ?? null
|
|
365
|
+
},
|
|
366
|
+
responsableIds: {
|
|
367
|
+
valueKind: "id-array",
|
|
368
|
+
extract: (activity) => activity.responsableIds
|
|
369
|
+
},
|
|
370
|
+
tagIds: { valueKind: "id-array", extract: (activity) => activity.tagIds },
|
|
371
|
+
status: {
|
|
372
|
+
valueKind: "enum",
|
|
373
|
+
order: STATUS_ORDER,
|
|
374
|
+
extract: (activity) => activity.status
|
|
375
|
+
},
|
|
376
|
+
constraintType: {
|
|
377
|
+
valueKind: "enum",
|
|
378
|
+
order: CONSTRAINT_TYPE_ORDER,
|
|
379
|
+
extract: (activity) => activity.constraintType
|
|
380
|
+
},
|
|
381
|
+
calendarId: {
|
|
382
|
+
valueKind: "reference",
|
|
383
|
+
extract: (activity) => activity.calendarId === null ? null : String(activity.calendarId)
|
|
384
|
+
},
|
|
385
|
+
// Normalized to string like calendarId. It is stored as a number, so it used
|
|
386
|
+
// to reach compareValues through the numeric branch while its sibling
|
|
387
|
+
// reference went through the string one — the same field kind comparing two
|
|
388
|
+
// different ways. localeCompare with numeric:true keeps the digit ordering.
|
|
389
|
+
subcontractId: {
|
|
390
|
+
valueKind: "reference",
|
|
391
|
+
extract: (activity) => activity.subcontractId === null ? null : String(activity.subcontractId)
|
|
392
|
+
},
|
|
393
|
+
// Declared boolean, not enum: it is one, and saying so is what lets the enum
|
|
394
|
+
// branch demand an order without inventing one for true/false.
|
|
395
|
+
isCritical: {
|
|
396
|
+
valueKind: "boolean",
|
|
397
|
+
extract: (activity) => activity.isCritical
|
|
398
|
+
}
|
|
399
|
+
};
|
|
400
|
+
function getFieldDescriptor(field) {
|
|
401
|
+
return FIELD_REGISTRY[field] ?? null;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// src/internal/filter/evaluate-filter.ts
|
|
405
|
+
function toTargetDate(value) {
|
|
406
|
+
if (value instanceof Date) return value;
|
|
407
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
408
|
+
return new Date(value);
|
|
409
|
+
}
|
|
410
|
+
return new Date(Number.NaN);
|
|
411
|
+
}
|
|
412
|
+
function matchString(value, target, operator) {
|
|
413
|
+
const isAbsent = value === null;
|
|
414
|
+
if (operator === "includes") {
|
|
415
|
+
return !isAbsent && String(value).toLowerCase().includes(target.toLowerCase());
|
|
416
|
+
}
|
|
417
|
+
if (operator === "notIncludes") {
|
|
418
|
+
return isAbsent || !String(value).toLowerCase().includes(target.toLowerCase());
|
|
419
|
+
}
|
|
420
|
+
if (operator === "is") return !isAbsent && String(value) === target;
|
|
421
|
+
if (operator === "isNot") return isAbsent || String(value) !== target;
|
|
422
|
+
return false;
|
|
423
|
+
}
|
|
424
|
+
function matchNumber(value, target, operator) {
|
|
425
|
+
if (value === null || typeof value !== "number") {
|
|
426
|
+
return operator === "notEquals";
|
|
427
|
+
}
|
|
428
|
+
if (operator === "equals") return value === target;
|
|
429
|
+
if (operator === "notEquals") return value !== target;
|
|
430
|
+
if (operator === "greaterThan") return value > target;
|
|
431
|
+
if (operator === "lessThan") return value < target;
|
|
432
|
+
if (operator === "greaterOrEqual") return value >= target;
|
|
433
|
+
if (operator === "lessOrEqual") return value <= target;
|
|
434
|
+
return false;
|
|
435
|
+
}
|
|
436
|
+
function matchDate(value, target, operator) {
|
|
437
|
+
if (!(value instanceof Date)) return false;
|
|
438
|
+
if (operator === "after") return value.getTime() > target.getTime();
|
|
439
|
+
if (operator === "before") return value.getTime() < target.getTime();
|
|
440
|
+
return false;
|
|
441
|
+
}
|
|
442
|
+
function matchIdArray(value, allowed, operator) {
|
|
443
|
+
const ids = Array.isArray(value) ? value : [];
|
|
444
|
+
const intersects = ids.some((id) => allowed.has(String(id)));
|
|
445
|
+
if (operator === "someOf") return intersects;
|
|
446
|
+
if (operator === "notSomeOf") return !intersects;
|
|
447
|
+
return false;
|
|
448
|
+
}
|
|
449
|
+
function matchEnum(value, allowed, operator) {
|
|
450
|
+
const isMember = value !== null && allowed.has(String(value));
|
|
451
|
+
if (operator === "someOf") return isMember;
|
|
452
|
+
if (operator === "notSomeOf") return !isMember;
|
|
453
|
+
return false;
|
|
454
|
+
}
|
|
455
|
+
function toAllowedSet(value) {
|
|
456
|
+
const items = Array.isArray(value) ? value : [value];
|
|
457
|
+
return new Set(items.map((item) => String(item)));
|
|
458
|
+
}
|
|
459
|
+
function matchCriterion(activity, criterion, context) {
|
|
460
|
+
const descriptor = getFieldDescriptor(criterion.field);
|
|
461
|
+
if (descriptor === null) return false;
|
|
462
|
+
const value = descriptor.extract(activity, context);
|
|
463
|
+
const { operator } = criterion;
|
|
464
|
+
if (descriptor.valueKind === "string") {
|
|
465
|
+
return matchString(value, String(criterion.value), operator);
|
|
466
|
+
}
|
|
467
|
+
if (descriptor.valueKind === "number") {
|
|
468
|
+
return matchNumber(value, Number(criterion.value), operator);
|
|
469
|
+
}
|
|
470
|
+
if (descriptor.valueKind === "date") {
|
|
471
|
+
return matchDate(value, toTargetDate(criterion.value), operator);
|
|
472
|
+
}
|
|
473
|
+
if (descriptor.valueKind === "id-array") {
|
|
474
|
+
return matchIdArray(value, toAllowedSet(criterion.value), operator);
|
|
475
|
+
}
|
|
476
|
+
return matchEnum(value, toAllowedSet(criterion.value), operator);
|
|
477
|
+
}
|
|
478
|
+
function matchesCriteria(activity, filter, context) {
|
|
479
|
+
if (filter.criteria.length === 0) return true;
|
|
480
|
+
if (filter.logic === "or") {
|
|
481
|
+
return filter.criteria.some(
|
|
482
|
+
(criterion) => matchCriterion(activity, criterion, context)
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
return filter.criteria.every(
|
|
486
|
+
(criterion) => matchCriterion(activity, criterion, context)
|
|
487
|
+
);
|
|
488
|
+
}
|
|
489
|
+
function overlapsRange(activity, range) {
|
|
490
|
+
const taskStart = activity.startDate.getTime();
|
|
491
|
+
const taskEnd = activity.endDate.getTime();
|
|
492
|
+
const windowStart = range.start.getTime();
|
|
493
|
+
const windowEnd = range.end.getTime();
|
|
494
|
+
const fullyInside = taskStart >= windowStart && taskEnd <= windowEnd;
|
|
495
|
+
const startsInside = taskStart >= windowStart && taskStart <= windowEnd;
|
|
496
|
+
const windowStartsInside = windowStart >= taskStart && windowStart <= taskEnd;
|
|
497
|
+
return fullyInside || startsInside || windowStartsInside;
|
|
498
|
+
}
|
|
499
|
+
function addAncestors(matchedId, parentOf, visibleIds) {
|
|
500
|
+
let ancestorId = parentOf(matchedId);
|
|
501
|
+
while (ancestorId !== null && !visibleIds.has(String(ancestorId))) {
|
|
502
|
+
visibleIds.add(String(ancestorId));
|
|
503
|
+
ancestorId = parentOf(ancestorId);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
function evaluateVisibleIds(input) {
|
|
507
|
+
const { activities, parentOf, filter, context } = input;
|
|
508
|
+
const range = filter.dateRange;
|
|
509
|
+
const visibleIds = /* @__PURE__ */ new Set();
|
|
510
|
+
const matchedIds = [];
|
|
511
|
+
for (const activity of activities) {
|
|
512
|
+
const passesCriteria = matchesCriteria(activity, filter, context);
|
|
513
|
+
const passesRange = range === void 0 || overlapsRange(activity, range);
|
|
514
|
+
if (passesCriteria && passesRange) {
|
|
515
|
+
visibleIds.add(String(activity.id));
|
|
516
|
+
matchedIds.push(activity.id);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
for (const matchedId of matchedIds) {
|
|
520
|
+
addAncestors(matchedId, parentOf, visibleIds);
|
|
521
|
+
}
|
|
522
|
+
return visibleIds;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// src/internal/filter/context.ts
|
|
526
|
+
var COLLATION_LOCALE = "en";
|
|
527
|
+
function buildFilterContext(hoursPerDay) {
|
|
528
|
+
return { hoursPerDay, locale: COLLATION_LOCALE };
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// src/internal/filter/validate.ts
|
|
532
|
+
var OPERATORS_BY_KIND = {
|
|
533
|
+
string: /* @__PURE__ */ new Set(["includes", "notIncludes", "is", "isNot"]),
|
|
534
|
+
number: /* @__PURE__ */ new Set([
|
|
535
|
+
"equals",
|
|
536
|
+
"notEquals",
|
|
537
|
+
"greaterThan",
|
|
538
|
+
"lessThan",
|
|
539
|
+
"greaterOrEqual",
|
|
540
|
+
"lessOrEqual"
|
|
541
|
+
]),
|
|
542
|
+
date: /* @__PURE__ */ new Set(["after", "before"]),
|
|
543
|
+
"id-array": /* @__PURE__ */ new Set(["someOf", "notSomeOf"]),
|
|
544
|
+
enum: /* @__PURE__ */ new Set(["someOf", "notSomeOf"]),
|
|
545
|
+
// Same membership operators as enum: splitting the kinds was about ordering,
|
|
546
|
+
// not about filtering, and these two filter exactly like an enum.
|
|
547
|
+
boolean: /* @__PURE__ */ new Set(["someOf", "notSomeOf"]),
|
|
548
|
+
reference: /* @__PURE__ */ new Set(["someOf", "notSomeOf"])
|
|
549
|
+
};
|
|
550
|
+
function validateCriterion(criterion) {
|
|
551
|
+
const descriptor = getFieldDescriptor(criterion.field);
|
|
552
|
+
if (descriptor === null) return "unknown_field";
|
|
553
|
+
if (!OPERATORS_BY_KIND[descriptor.valueKind].has(criterion.operator)) {
|
|
554
|
+
return "unknown_operator";
|
|
555
|
+
}
|
|
556
|
+
return validateValueForKind(criterion, descriptor.valueKind);
|
|
557
|
+
}
|
|
558
|
+
function validateValueForKind(criterion, valueKind) {
|
|
559
|
+
const { value } = criterion;
|
|
560
|
+
if (valueKind === "id-array" || valueKind === "enum") {
|
|
561
|
+
return Array.isArray(value) ? null : "invalid_value";
|
|
562
|
+
}
|
|
563
|
+
if (Array.isArray(value)) return "invalid_value";
|
|
564
|
+
if (valueKind === "number") {
|
|
565
|
+
return Number.isFinite(Number(value)) ? null : "invalid_value";
|
|
566
|
+
}
|
|
567
|
+
if (valueKind === "date") {
|
|
568
|
+
return isValidDateValue(value) ? null : "invalid_value";
|
|
569
|
+
}
|
|
570
|
+
return null;
|
|
571
|
+
}
|
|
572
|
+
function isValidDateValue(value) {
|
|
573
|
+
if (value instanceof Date) return true;
|
|
574
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
575
|
+
return !Number.isNaN(new Date(value).getTime());
|
|
576
|
+
}
|
|
577
|
+
return false;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// src/dispatch/filter.ts
|
|
581
|
+
function isEmptyFilter(filter) {
|
|
582
|
+
return filter.criteria.length === 0 && filter.dateRange === void 0;
|
|
583
|
+
}
|
|
584
|
+
function resolveVisibleIds(adapter, filter, hoursPerDay) {
|
|
585
|
+
const activities = adapter.getAllActivities();
|
|
586
|
+
if (isEmptyFilter(filter)) {
|
|
587
|
+
return new Set(activities.map((activity) => String(activity.id)));
|
|
588
|
+
}
|
|
589
|
+
return evaluateVisibleIds({
|
|
590
|
+
activities,
|
|
591
|
+
parentOf: (activityId) => adapter.getParentId(activityId),
|
|
592
|
+
filter,
|
|
593
|
+
context: buildFilterContext(hoursPerDay)
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
function dispatchFilterSet(action, deps) {
|
|
597
|
+
const { adapter, hoursPerDay } = deps;
|
|
598
|
+
for (const criterion of action.criteria) {
|
|
599
|
+
const rejection = validateCriterion(criterion);
|
|
600
|
+
if (rejection !== null) return { ok: false, reason: rejection };
|
|
601
|
+
}
|
|
602
|
+
const filter = action.dateRange === void 0 ? { criteria: action.criteria, logic: action.logic } : {
|
|
603
|
+
criteria: action.criteria,
|
|
604
|
+
logic: action.logic,
|
|
605
|
+
dateRange: action.dateRange
|
|
606
|
+
};
|
|
607
|
+
adapter.setActiveFilter(isEmptyFilter(filter) ? null : filter);
|
|
608
|
+
const visibleIds = resolveVisibleIds(adapter, filter, hoursPerDay);
|
|
609
|
+
const viewState = applyVisibleSet(adapter, visibleIds);
|
|
239
610
|
const changes = {
|
|
240
611
|
source: action,
|
|
241
612
|
activities: [],
|
|
@@ -247,6 +618,140 @@ function dispatchVisibilitySet(action, deps) {
|
|
|
247
618
|
return { ok: true, changes };
|
|
248
619
|
}
|
|
249
620
|
|
|
621
|
+
// src/internal/hierarchy/root-parent.ts
|
|
622
|
+
var ROOT_PARENT_ID = "0";
|
|
623
|
+
function isRootParent(parent) {
|
|
624
|
+
return parent == null || parent === 0 || parent === ROOT_PARENT_ID;
|
|
625
|
+
}
|
|
626
|
+
function normalizeParentKey(parent) {
|
|
627
|
+
return isRootParent(parent) ? ROOT_PARENT_ID : String(parent);
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
// src/internal/hierarchy/visual-order.ts
|
|
631
|
+
var NOT_SET_SORT_VALUE = Number.MAX_SAFE_INTEGER;
|
|
632
|
+
function getChildrenInVisualOrder(parentId, adapter) {
|
|
633
|
+
const children = collectChildrenSnapshots(parentId, adapter);
|
|
634
|
+
const userOrder = adapter.getOrderComparator?.() ?? null;
|
|
635
|
+
children.sort(
|
|
636
|
+
userOrder === null ? compareActivitiesInVisualOrder : (a, b) => userOrder(a, b) || compareActivitiesInVisualOrder(a, b)
|
|
637
|
+
);
|
|
638
|
+
return children.map((a) => String(a.id));
|
|
639
|
+
}
|
|
640
|
+
function iterateInVisualOrder(adapter) {
|
|
641
|
+
const result = [];
|
|
642
|
+
const visit = (activity) => {
|
|
643
|
+
result.push(activity);
|
|
644
|
+
const childIds = getChildrenInVisualOrder(String(activity.id), adapter);
|
|
645
|
+
for (const childId of childIds) {
|
|
646
|
+
const child = adapter.getActivity(childId);
|
|
647
|
+
if (child) visit(child);
|
|
648
|
+
}
|
|
649
|
+
};
|
|
650
|
+
const rootIds = getChildrenInVisualOrder(ROOT_PARENT_ID, adapter);
|
|
651
|
+
for (const rootId of rootIds) {
|
|
652
|
+
const root = adapter.getActivity(rootId);
|
|
653
|
+
if (root) visit(root);
|
|
654
|
+
}
|
|
655
|
+
return result;
|
|
656
|
+
}
|
|
657
|
+
function findPreviousNonSelectedSibling(taskId, selected, adapter) {
|
|
658
|
+
const activity = adapter.getActivity(taskId);
|
|
659
|
+
if (!activity) return null;
|
|
660
|
+
const parentKey = parentKeyOf(activity);
|
|
661
|
+
const siblings = getChildrenInVisualOrder(parentKey, adapter);
|
|
662
|
+
const idx = siblings.findIndex((id) => String(id) === String(taskId));
|
|
663
|
+
if (idx <= 0) return null;
|
|
664
|
+
for (let i = idx - 1; i >= 0; i--) {
|
|
665
|
+
const candidateId = siblings[i];
|
|
666
|
+
if (candidateId === void 0) continue;
|
|
667
|
+
if (!setHas(selected, candidateId)) return candidateId;
|
|
668
|
+
}
|
|
669
|
+
return null;
|
|
670
|
+
}
|
|
671
|
+
function visualIndexInParent(taskId, adapter) {
|
|
672
|
+
const activity = adapter.getActivity(taskId);
|
|
673
|
+
if (!activity) return -1;
|
|
674
|
+
const parentKey = parentKeyOf(activity);
|
|
675
|
+
const siblings = getChildrenInVisualOrder(parentKey, adapter);
|
|
676
|
+
return siblings.findIndex((id) => String(id) === String(taskId));
|
|
677
|
+
}
|
|
678
|
+
function collectChildrenSnapshots(parentId, adapter) {
|
|
679
|
+
const key = String(parentId);
|
|
680
|
+
if (key === "0") {
|
|
681
|
+
return adapter.getAllActivities().filter((a) => a.parentId === null);
|
|
682
|
+
}
|
|
683
|
+
const childIds = adapter.getChildren(parentId);
|
|
684
|
+
const out = [];
|
|
685
|
+
for (const id of childIds) {
|
|
686
|
+
const snap = adapter.getActivity(id);
|
|
687
|
+
if (snap) out.push(snap);
|
|
688
|
+
}
|
|
689
|
+
return out;
|
|
690
|
+
}
|
|
691
|
+
function compareActivitiesInVisualOrder(a, b) {
|
|
692
|
+
const ac = correlativeIdOf(a);
|
|
693
|
+
const bc = correlativeIdOf(b);
|
|
694
|
+
if (ac !== bc) return ac - bc;
|
|
695
|
+
return String(a.id).localeCompare(String(b.id));
|
|
696
|
+
}
|
|
697
|
+
function correlativeIdOf(activity) {
|
|
698
|
+
const raw = activity.correlativeId;
|
|
699
|
+
const n = typeof raw === "number" ? raw : Number(raw);
|
|
700
|
+
return Number.isFinite(n) ? n : NOT_SET_SORT_VALUE;
|
|
701
|
+
}
|
|
702
|
+
function parentKeyOf(activity) {
|
|
703
|
+
const parentId = activity.parentId;
|
|
704
|
+
if (parentId === null) return "0";
|
|
705
|
+
return parentId;
|
|
706
|
+
}
|
|
707
|
+
function setHas(set, id) {
|
|
708
|
+
if (set.has(id)) return true;
|
|
709
|
+
return set.has(String(id));
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
// src/dispatch/shared/collect-branch-order.ts
|
|
713
|
+
function collectBranchOrder(adapter) {
|
|
714
|
+
const branches = [];
|
|
715
|
+
const visit = (parentId) => {
|
|
716
|
+
const childIds = getChildrenInVisualOrder(parentId, adapter);
|
|
717
|
+
if (childIds.length > 1) {
|
|
718
|
+
branches.push({ parentId, childIds });
|
|
719
|
+
}
|
|
720
|
+
for (const childId of childIds) {
|
|
721
|
+
visit(childId);
|
|
722
|
+
}
|
|
723
|
+
};
|
|
724
|
+
visit(ROOT_PARENT_ID);
|
|
725
|
+
return branches;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
// src/dispatch/order.ts
|
|
729
|
+
function validateRule(rule) {
|
|
730
|
+
if (getFieldDescriptor(rule.field) === null) return "unknown_field";
|
|
731
|
+
if (rule.direction !== "asc" && rule.direction !== "desc") {
|
|
732
|
+
return "unknown_operator";
|
|
733
|
+
}
|
|
734
|
+
return null;
|
|
735
|
+
}
|
|
736
|
+
function dispatchSortSet(action, deps) {
|
|
737
|
+
const { adapter } = deps;
|
|
738
|
+
for (const rule of action.rules) {
|
|
739
|
+
const rejection = validateRule(rule);
|
|
740
|
+
if (rejection !== null) return { ok: false, reason: rejection };
|
|
741
|
+
}
|
|
742
|
+
const order = action.rules.length === 0 ? null : { rules: action.rules };
|
|
743
|
+
adapter.setActiveOrder(order);
|
|
744
|
+
const changes = {
|
|
745
|
+
source: action,
|
|
746
|
+
activities: [],
|
|
747
|
+
links: [],
|
|
748
|
+
calendars: [],
|
|
749
|
+
trackingEvents: [],
|
|
750
|
+
order: collectBranchOrder(adapter)
|
|
751
|
+
};
|
|
752
|
+
return { ok: true, changes };
|
|
753
|
+
}
|
|
754
|
+
|
|
250
755
|
// src/columns/text/constants.ts
|
|
251
756
|
var TEXT = "text";
|
|
252
757
|
|
|
@@ -628,19 +1133,22 @@ var ACTIVITY_TYPE = {
|
|
|
628
1133
|
MILESTONE: "milestone"
|
|
629
1134
|
};
|
|
630
1135
|
var TIMING = {
|
|
631
|
-
// 16ms = full frame budget; 8ms = yield twice per frame so the
|
|
632
|
-
// browser still has half a frame to paint and handle input.
|
|
633
1136
|
YIELD_SLICE_MS: 8
|
|
634
1137
|
};
|
|
635
1138
|
|
|
636
1139
|
// src/shared/timing.ts
|
|
637
1140
|
var isNode = typeof window === "undefined";
|
|
638
|
-
var
|
|
1141
|
+
var hasMessageChannel = !isNode && typeof MessageChannel !== "undefined";
|
|
639
1142
|
function yieldToBrowser() {
|
|
640
|
-
if (
|
|
1143
|
+
if (!hasMessageChannel) return Promise.resolve();
|
|
641
1144
|
return new Promise((resolve) => {
|
|
642
|
-
|
|
643
|
-
|
|
1145
|
+
const oneShotChannel = new MessageChannel();
|
|
1146
|
+
oneShotChannel.port1.onmessage = () => {
|
|
1147
|
+
oneShotChannel.port1.close();
|
|
1148
|
+
oneShotChannel.port2.close();
|
|
1149
|
+
resolve();
|
|
1150
|
+
};
|
|
1151
|
+
oneShotChannel.port2.postMessage(null);
|
|
644
1152
|
});
|
|
645
1153
|
}
|
|
646
1154
|
|
|
@@ -1248,7 +1756,6 @@ function calculateSuccessorStartFromLink(predecessor, successor, link, adapter)
|
|
|
1248
1756
|
startDate: date2,
|
|
1249
1757
|
durationHours: sourceLag,
|
|
1250
1758
|
task: predecessor
|
|
1251
|
-
// sourceLag always on predecessor calendar
|
|
1252
1759
|
});
|
|
1253
1760
|
}
|
|
1254
1761
|
if (targetLag !== 0) {
|
|
@@ -1256,7 +1763,6 @@ function calculateSuccessorStartFromLink(predecessor, successor, link, adapter)
|
|
|
1256
1763
|
startDate: date2,
|
|
1257
1764
|
durationHours: targetLag,
|
|
1258
1765
|
task: successor
|
|
1259
|
-
// targetLag always on successor calendar
|
|
1260
1766
|
});
|
|
1261
1767
|
}
|
|
1262
1768
|
if (trueLag !== 0) {
|
|
@@ -1264,7 +1770,6 @@ function calculateSuccessorStartFromLink(predecessor, successor, link, adapter)
|
|
|
1264
1770
|
startDate: date2,
|
|
1265
1771
|
durationHours: trueLag,
|
|
1266
1772
|
task: successor
|
|
1267
|
-
// trueLag always on successor calendar
|
|
1268
1773
|
});
|
|
1269
1774
|
}
|
|
1270
1775
|
if (successor.durationHours === 0) {
|
|
@@ -1553,15 +2058,6 @@ function isSummaryActivity(activity, adapter) {
|
|
|
1553
2058
|
return isSummary(activity.type, adapter.getChildren(activity.id).length > 0);
|
|
1554
2059
|
}
|
|
1555
2060
|
|
|
1556
|
-
// src/internal/hierarchy/root-parent.ts
|
|
1557
|
-
var ROOT_PARENT_ID = "0";
|
|
1558
|
-
function isRootParent(parent) {
|
|
1559
|
-
return parent == null || parent === 0 || parent === ROOT_PARENT_ID;
|
|
1560
|
-
}
|
|
1561
|
-
function normalizeParentKey(parent) {
|
|
1562
|
-
return isRootParent(parent) ? ROOT_PARENT_ID : String(parent);
|
|
1563
|
-
}
|
|
1564
|
-
|
|
1565
2061
|
// src/autoscheduler/engine/alap-pass.ts
|
|
1566
2062
|
async function alapPass(reversedIds, links, asapPlans, adapter, _options, isCurrent) {
|
|
1567
2063
|
const plans = new Map(asapPlans);
|
|
@@ -1914,8 +2410,6 @@ function parseEntry(entry) {
|
|
|
1914
2410
|
lag = sign === "-" ? -value : value;
|
|
1915
2411
|
}
|
|
1916
2412
|
return {
|
|
1917
|
-
// frozen logic: invariant guaranteed by ENTRY_RE — capture group 1 `(\d+)`
|
|
1918
|
-
// is non-optional, so a successful match always defines correlativeId
|
|
1919
2413
|
correlativeId,
|
|
1920
2414
|
type,
|
|
1921
2415
|
lag
|
|
@@ -2022,36 +2516,6 @@ function lagDaysToHours(lagDays, hoursPerDay) {
|
|
|
2022
2516
|
|
|
2023
2517
|
// src/autoscheduler/date-math/impl-current.ts
|
|
2024
2518
|
var currentImpl = {
|
|
2025
|
-
/**
|
|
2026
|
-
* Legacy rule observed empirically from 4 fixtures:
|
|
2027
|
-
*
|
|
2028
|
-
* midnight = setHours(0, 0, 0, 0) on a copy of rawDate (local TZ)
|
|
2029
|
-
* if (midnight.getTime() === rawDate.getTime())
|
|
2030
|
-
* return calendar.getClosestWorkTime(raw, 'future') // snap forward
|
|
2031
|
-
* else
|
|
2032
|
-
* return midnight // preserve day
|
|
2033
|
-
*
|
|
2034
|
-
* Rationale (inferred): when the user types/picks a date AT local
|
|
2035
|
-
* midnight (e.g., Saturday 00:00 local = "just Saturday"), legacy
|
|
2036
|
-
* interprets it as "start of the week/day" and snaps to the next
|
|
2037
|
-
* working hour. When they pick a time WITHIN a day (e.g., Sunday
|
|
2038
|
-
* 08:00 local), legacy treats it as "this specific day" and preserves
|
|
2039
|
-
* the day at local midnight, even if the day is non-working.
|
|
2040
|
-
*
|
|
2041
|
-
* Fixture evidence:
|
|
2042
|
-
* - test3: raw=Apr 26 06:00Z (Sun 08:00 CEST) → Apr 25 22:00Z (Sun 00:00 CEST)
|
|
2043
|
-
* - create-rename-drag: raw=Apr 23 22:00Z (Fri 00:00 CEST) → Apr 24 06:00Z (snap)
|
|
2044
|
-
* - create-rename-drag: raw=Apr 25 22:00Z (Sun 00:00 CEST) → Apr 27 06:00Z (snap)
|
|
2045
|
-
*
|
|
2046
|
-
* UTC contract: `setUTCHours(0)` makes the normalization deterministic
|
|
2047
|
-
* regardless of the runtime's local TZ. The work-calendar package (and
|
|
2048
|
-
* any future strict-UTC calendar engine) requires UTC-keyed inputs, so
|
|
2049
|
-
* the day boundary must be computed in UTC too. Legacy fixtures
|
|
2050
|
-
* recorded under local-TZ midnight may need their `metadata.tz` honored
|
|
2051
|
-
* upstream — `pipeline-context.ts` plumbs that field but this function
|
|
2052
|
-
* does not yet consume it (its caller supplies a raw Date with the
|
|
2053
|
-
* recorded instant intact).
|
|
2054
|
-
*/
|
|
2055
2519
|
rawInputToConstraintDate(rawDate, calendar) {
|
|
2056
2520
|
const midnight = new Date(rawDate);
|
|
2057
2521
|
midnight.setUTCHours(0, 0, 0, 0);
|
|
@@ -2067,16 +2531,6 @@ var currentImpl = {
|
|
|
2067
2531
|
}
|
|
2068
2532
|
return midnight;
|
|
2069
2533
|
},
|
|
2070
|
-
/**
|
|
2071
|
-
* Legacy behavior replicated (from `modifyLagCustom.js:29-35`):
|
|
2072
|
-
* `calendar.calculateDuration(sourceDate, targetDate)`
|
|
2073
|
-
*
|
|
2074
|
-
* Returns working hours between the two dates according to the task's
|
|
2075
|
-
* calendar (working days + working hours range). Positive when
|
|
2076
|
-
* targetDate > sourceDate, zero when aligned. Negative branch
|
|
2077
|
-
* exists in calendar.calculateDuration (reverse walk) but our
|
|
2078
|
-
* current usage always has target after source post-move.
|
|
2079
|
-
*/
|
|
2080
2534
|
computeLagBetweenTasks(sourceDate, targetDate, calendar) {
|
|
2081
2535
|
return calendar.calculateDuration(sourceDate, targetDate);
|
|
2082
2536
|
}
|
|
@@ -2113,36 +2567,16 @@ var AutoScheduler = class {
|
|
|
2113
2567
|
getCurrentCalculationId() {
|
|
2114
2568
|
return this.currentCalculationId;
|
|
2115
2569
|
}
|
|
2116
|
-
/**
|
|
2117
|
-
* Invalidates the cached full-graph topological order. Call after any
|
|
2118
|
-
* structural mutation: link create/delete, activity create/delete,
|
|
2119
|
-
* activity reparent (indent/outdent/move).
|
|
2120
|
-
*/
|
|
2121
2570
|
invalidateTopoCache() {
|
|
2122
2571
|
this.topoCache.invalidate();
|
|
2123
2572
|
}
|
|
2124
|
-
/**
|
|
2125
|
-
* Invalidates the cached expanded parent-link set. Call on link create /
|
|
2126
|
-
* delete, activity reparent, activity create / delete, and on the rare
|
|
2127
|
-
* field edits that affect chain-pruning (`duration`, `auto_scheduling`).
|
|
2128
|
-
*/
|
|
2129
2573
|
invalidateExpandedLinksCache() {
|
|
2130
2574
|
this.expandedLinksCache.invalidate();
|
|
2131
2575
|
}
|
|
2132
|
-
/**
|
|
2133
|
-
* Convenience: invalidate every cache held by the scheduler.
|
|
2134
|
-
*/
|
|
2135
2576
|
invalidateAllCaches() {
|
|
2136
2577
|
this.topoCache.invalidate();
|
|
2137
2578
|
this.expandedLinksCache.invalidate();
|
|
2138
2579
|
}
|
|
2139
|
-
/**
|
|
2140
|
-
* Main entry point. Runs the full scheduling algorithm.
|
|
2141
|
-
*
|
|
2142
|
-
* Returns a ScheduleResult with the plans, updated IDs, and status.
|
|
2143
|
-
* The caller (integration layer) is responsible for applying the results
|
|
2144
|
-
* back to gantt.
|
|
2145
|
-
*/
|
|
2146
2580
|
async schedule(options = {}) {
|
|
2147
2581
|
const calculationId = ++this.currentCalculationId;
|
|
2148
2582
|
const isCurrent = createIsCurrent(
|
|
@@ -2511,16 +2945,6 @@ function sortDeepestFirst(ids, depths) {
|
|
|
2511
2945
|
// src/internal/post-processors/runner.ts
|
|
2512
2946
|
var POST_PROCESSORS = {
|
|
2513
2947
|
updateActivityDuration: runUpdateActivityDuration,
|
|
2514
|
-
// `updateMilestoneData` eliminado del registro (2026-06-10, MIL-B2):
|
|
2515
|
-
// post-processor fantasma — ninguna pipeline lo emitía. Su garantía
|
|
2516
|
-
// (duration=0, end_date=start_date al convertir a milestone) vive en
|
|
2517
|
-
// durationPipeline (fix MIL-B1) + calculateEndDate(start, 0) === start
|
|
2518
|
-
// (test en calendar/adapter.test.ts). Ver BUGS_milestones_2026-06-10.md
|
|
2519
|
-
// (vault).
|
|
2520
|
-
// `executeFixForConstraints` (legacy) se reimplementa fuera de este registro
|
|
2521
|
-
// como `revertNoOpConstraintEdit` (post-pass del dispatch de constraint, tras
|
|
2522
|
-
// la cascada) — NO como post-processor por-pipeline. `recordLastStartDate`
|
|
2523
|
-
// guarda el baseline del gesto (start al editar duración) que ese revert lee.
|
|
2524
2948
|
updateTaskTiming: runNoOp("updateTaskTiming"),
|
|
2525
2949
|
adjustLinkLagOnTaskMove,
|
|
2526
2950
|
recordLastStartDate: runRecordLastStartDate
|
|
@@ -2943,7 +3367,6 @@ function buildDescendantCascade(activity, newValue, autoScheduling, hierarchy, r
|
|
|
2943
3367
|
const descendants = hierarchy.getDescendantIds(activity.id);
|
|
2944
3368
|
return descendants.map((id) => ({
|
|
2945
3369
|
activityId: id,
|
|
2946
|
-
// Descendants of a recursive progress change inherit the primary value.
|
|
2947
3370
|
fields: descendantFields(
|
|
2948
3371
|
newValue,
|
|
2949
3372
|
autoScheduling,
|
|
@@ -3256,7 +3679,6 @@ var startDatePipeline = {
|
|
|
3256
3679
|
{
|
|
3257
3680
|
startDate: finalStart,
|
|
3258
3681
|
...setEndDate(finalEnd),
|
|
3259
|
-
// Sanea la duration de un milestone corrupto en el mismo move.
|
|
3260
3682
|
...milestoneActivity ? setDuration(0) : {},
|
|
3261
3683
|
...setConstraintTypeImplied(),
|
|
3262
3684
|
...setConstraintDate(constraintDate)
|
|
@@ -3535,9 +3957,11 @@ var calendarIdPipeline = {
|
|
|
3535
3957
|
if (isEmpty(value)) return parseError("empty_calendar");
|
|
3536
3958
|
return parsed(value);
|
|
3537
3959
|
},
|
|
3538
|
-
validate(activity, _oldValue, newValue) {
|
|
3960
|
+
validate(activity, _oldValue, newValue, ctx) {
|
|
3539
3961
|
if (isUnchangedCalendar(activity.calendarId, newValue))
|
|
3540
3962
|
return invalid("unchanged");
|
|
3963
|
+
if (!ctx.calendars.getCalendar(newValue))
|
|
3964
|
+
return invalid("unknown_calendar");
|
|
3541
3965
|
return valid();
|
|
3542
3966
|
},
|
|
3543
3967
|
transform(activity, newValue, ctx) {
|
|
@@ -3752,9 +4176,6 @@ var COLUMN_PIPELINES = /* @__PURE__ */ new Map([
|
|
|
3752
4176
|
[COLUMN.CONSTRAINT_DATE, constraintDatePipeline],
|
|
3753
4177
|
[COLUMN.CALENDAR_ID, calendarIdPipeline],
|
|
3754
4178
|
[COLUMN.CUSTOM_ID, customIdPipeline],
|
|
3755
|
-
// Naming exception: `subcontractId` stays camelCase for parity with
|
|
3756
|
-
// production (backend BD + legacy column + `BackendActivityInput.subcontractId`).
|
|
3757
|
-
// Snake-case unification deferred to a global pass.
|
|
3758
4179
|
[COLUMN.SUBCONTRACT_ID, subcontractIdPipeline],
|
|
3759
4180
|
[COLUMN.RESPONSABLES, responsablesPipeline],
|
|
3760
4181
|
[COLUMN.TAGS, tagsPipeline]
|
|
@@ -3879,7 +4300,13 @@ function cloneCriticalPath(value) {
|
|
|
3879
4300
|
};
|
|
3880
4301
|
}
|
|
3881
4302
|
|
|
4303
|
+
// src/shared/clone-domain-value.ts
|
|
4304
|
+
function cloneDomainValue(value) {
|
|
4305
|
+
return structuredClone(value);
|
|
4306
|
+
}
|
|
4307
|
+
|
|
3882
4308
|
// src/dispatch/shared/snapshots.ts
|
|
4309
|
+
var YIELD_EVERY_N_ENTRIES = 200;
|
|
3883
4310
|
function collectTouchedIds(primary, changes) {
|
|
3884
4311
|
const ids = /* @__PURE__ */ new Set([String(primary)]);
|
|
3885
4312
|
for (const mutation of changes.cascadeMutations ?? []) {
|
|
@@ -3887,9 +4314,12 @@ function collectTouchedIds(primary, changes) {
|
|
|
3887
4314
|
}
|
|
3888
4315
|
return ids;
|
|
3889
4316
|
}
|
|
3890
|
-
function snapshotActivities(adapter, ids) {
|
|
4317
|
+
async function snapshotActivities(adapter, ids) {
|
|
3891
4318
|
const out = /* @__PURE__ */ new Map();
|
|
4319
|
+
let processed = 0;
|
|
3892
4320
|
for (const id of ids) {
|
|
4321
|
+
processed += 1;
|
|
4322
|
+
if (processed % YIELD_EVERY_N_ENTRIES === 0) await yieldToBrowser();
|
|
3893
4323
|
const a = adapter.getActivity(id);
|
|
3894
4324
|
if (a) out.set(id, structuredCloneActivity(a));
|
|
3895
4325
|
}
|
|
@@ -3898,6 +4328,10 @@ function snapshotActivities(adapter, ids) {
|
|
|
3898
4328
|
function structuredCloneActivity(activity) {
|
|
3899
4329
|
return cloneCoreActivity(activity);
|
|
3900
4330
|
}
|
|
4331
|
+
function snapshotSingleActivity(adapter, activityId) {
|
|
4332
|
+
const liveActivity = adapter.getActivity(activityId);
|
|
4333
|
+
return liveActivity ? cloneCoreActivity(liveActivity) : null;
|
|
4334
|
+
}
|
|
3901
4335
|
function applyFieldChanges(adapter, activityId, changes) {
|
|
3902
4336
|
applyCanonicalPatch(adapter, activityId, changes.patch);
|
|
3903
4337
|
for (const mutation of changes.cascadeMutations ?? []) {
|
|
@@ -3914,35 +4348,69 @@ function applyCanonicalPatch(adapter, activityId, patch) {
|
|
|
3914
4348
|
setActivityFieldDynamic(adapter, activityId, key, value);
|
|
3915
4349
|
}
|
|
3916
4350
|
}
|
|
3917
|
-
function buildActivityChanges(adapter, before, touched) {
|
|
4351
|
+
async function buildActivityChanges(adapter, before, touched, correlativeBefore) {
|
|
3918
4352
|
const out = [];
|
|
4353
|
+
let processed = 0;
|
|
3919
4354
|
for (const id of touched) {
|
|
3920
|
-
|
|
3921
|
-
if (
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
if (
|
|
3929
|
-
out.push({
|
|
3930
|
-
id,
|
|
3931
|
-
kind: "created",
|
|
3932
|
-
fields: diff,
|
|
3933
|
-
after: structuredCloneActivity(afterSnap)
|
|
3934
|
-
});
|
|
3935
|
-
} else {
|
|
3936
|
-
out.push({
|
|
3937
|
-
id,
|
|
3938
|
-
kind: "updated",
|
|
3939
|
-
fields: diff,
|
|
3940
|
-
after: structuredCloneActivity(afterSnap)
|
|
3941
|
-
});
|
|
3942
|
-
}
|
|
4355
|
+
processed += 1;
|
|
4356
|
+
if (processed % YIELD_EVERY_N_ENTRIES === 0) await yieldToBrowser();
|
|
4357
|
+
const entry = buildEntryForTouchedId(
|
|
4358
|
+
adapter,
|
|
4359
|
+
before,
|
|
4360
|
+
id,
|
|
4361
|
+
correlativeBefore
|
|
4362
|
+
);
|
|
4363
|
+
if (entry) out.push(entry);
|
|
3943
4364
|
}
|
|
3944
4365
|
return out;
|
|
3945
4366
|
}
|
|
4367
|
+
function buildEntryForTouchedId(adapter, before, activityId, correlativeBefore) {
|
|
4368
|
+
const afterSnap = adapter.getActivity(activityId);
|
|
4369
|
+
if (!afterSnap) {
|
|
4370
|
+
return { id: activityId, kind: "deleted", after: null };
|
|
4371
|
+
}
|
|
4372
|
+
const beforeSnap = before.get(activityId);
|
|
4373
|
+
if (!beforeSnap && correlativeBefore?.has(activityId)) {
|
|
4374
|
+
return buildCorrelativeOnlyEntry(
|
|
4375
|
+
activityId,
|
|
4376
|
+
correlativeBefore.get(activityId),
|
|
4377
|
+
afterSnap
|
|
4378
|
+
);
|
|
4379
|
+
}
|
|
4380
|
+
const diff = diffActivity(beforeSnap, afterSnap);
|
|
4381
|
+
mergeCorrelativeShiftIntoDiff(diff, correlativeBefore, activityId, afterSnap);
|
|
4382
|
+
if (beforeSnap && Object.keys(diff).length === 0) return null;
|
|
4383
|
+
return {
|
|
4384
|
+
id: activityId,
|
|
4385
|
+
kind: beforeSnap ? "updated" : "created",
|
|
4386
|
+
fields: diff,
|
|
4387
|
+
after: structuredCloneActivity(afterSnap)
|
|
4388
|
+
};
|
|
4389
|
+
}
|
|
4390
|
+
function buildCorrelativeOnlyEntry(activityId, correlativeIdBefore, liveActivity) {
|
|
4391
|
+
if (correlativeIdBefore === liveActivity.correlativeId) return null;
|
|
4392
|
+
return {
|
|
4393
|
+
id: activityId,
|
|
4394
|
+
kind: "updated",
|
|
4395
|
+
fields: {
|
|
4396
|
+
correlativeId: {
|
|
4397
|
+
before: correlativeIdBefore,
|
|
4398
|
+
after: liveActivity.correlativeId
|
|
4399
|
+
}
|
|
4400
|
+
},
|
|
4401
|
+
after: structuredCloneActivity(liveActivity)
|
|
4402
|
+
};
|
|
4403
|
+
}
|
|
4404
|
+
function mergeCorrelativeShiftIntoDiff(diff, correlativeBefore, activityId, liveActivity) {
|
|
4405
|
+
if (!correlativeBefore?.has(activityId)) return;
|
|
4406
|
+
if (Object.hasOwn(diff, "correlativeId")) return;
|
|
4407
|
+
const shiftedFrom = correlativeBefore.get(activityId);
|
|
4408
|
+
if (shiftedFrom === liveActivity.correlativeId) return;
|
|
4409
|
+
diff.correlativeId = {
|
|
4410
|
+
before: shiftedFrom,
|
|
4411
|
+
after: liveActivity.correlativeId
|
|
4412
|
+
};
|
|
4413
|
+
}
|
|
3946
4414
|
function diffActivity(before, after) {
|
|
3947
4415
|
const fields = {};
|
|
3948
4416
|
const beforeRec = before ?? {};
|
|
@@ -3950,11 +4418,19 @@ function diffActivity(before, after) {
|
|
|
3950
4418
|
const keys = /* @__PURE__ */ new Set([...Object.keys(beforeRec), ...Object.keys(afterRec)]);
|
|
3951
4419
|
for (const k of keys) {
|
|
3952
4420
|
if (Object.hasOwn(beforeRec, k) !== Object.hasOwn(afterRec, k) || !fieldValueEqual(beforeRec[k], afterRec[k])) {
|
|
3953
|
-
fields[k] = {
|
|
4421
|
+
fields[k] = {
|
|
4422
|
+
before: cloneFieldValue(beforeRec[k]),
|
|
4423
|
+
after: cloneFieldValue(afterRec[k])
|
|
4424
|
+
};
|
|
3954
4425
|
}
|
|
3955
4426
|
}
|
|
3956
4427
|
return fields;
|
|
3957
4428
|
}
|
|
4429
|
+
function cloneFieldValue(value) {
|
|
4430
|
+
const isPrimitive = value === null || typeof value !== "object";
|
|
4431
|
+
if (isPrimitive) return value;
|
|
4432
|
+
return cloneDomainValue(value);
|
|
4433
|
+
}
|
|
3958
4434
|
function fieldValueEqual(left, right) {
|
|
3959
4435
|
if (Object.is(left, right)) return true;
|
|
3960
4436
|
if (left instanceof Date && right instanceof Date) {
|
|
@@ -4631,12 +5107,6 @@ function mutateTheDateToFutureOrPastInBaseRestriction(dateBaseToCalculate, restr
|
|
|
4631
5107
|
|
|
4632
5108
|
// src/critical-path/legacy/base/parents-calculations/forward.js
|
|
4633
5109
|
var CalculateForwardParentsWithLinks = class {
|
|
4634
|
-
/**
|
|
4635
|
-
* Initializes the calculator with linked activities, the current activity, and the gantt instance.
|
|
4636
|
-
* @param {Array<Object>} linkedActivitiesData - Array of linked activities data.
|
|
4637
|
-
* @param {Object} activity - The current activity object.
|
|
4638
|
-
* @param {Object} gantt - The gantt instance.
|
|
4639
|
-
*/
|
|
4640
5110
|
constructor(linkedActivitiesData, activity, gantt) {
|
|
4641
5111
|
this.linkedActivitiesData = linkedActivitiesData;
|
|
4642
5112
|
this.activity = activity;
|
|
@@ -4648,10 +5118,6 @@ var CalculateForwardParentsWithLinks = class {
|
|
|
4648
5118
|
);
|
|
4649
5119
|
}
|
|
4650
5120
|
}
|
|
4651
|
-
/**
|
|
4652
|
-
* Main method to perform the calculation.
|
|
4653
|
-
* @returns {Object} The calculation result.
|
|
4654
|
-
*/
|
|
4655
5121
|
calculate() {
|
|
4656
5122
|
const calculationsFromLinks = this.calculateLinks();
|
|
4657
5123
|
const maxEfFromLinks = getMaxEarlyStartSet(calculationsFromLinks);
|
|
@@ -4664,10 +5130,6 @@ var CalculateForwardParentsWithLinks = class {
|
|
|
4664
5130
|
}
|
|
4665
5131
|
return maxEfFromLinks;
|
|
4666
5132
|
}
|
|
4667
|
-
/**
|
|
4668
|
-
* Calculates the dates based on the linked activities.
|
|
4669
|
-
* @returns {Array<Object>} Array of calculation results from links.
|
|
4670
|
-
*/
|
|
4671
5133
|
calculateLinks() {
|
|
4672
5134
|
const calculations = [];
|
|
4673
5135
|
for (const linkedActivity of this.linkedActivitiesData) {
|
|
@@ -4698,11 +5160,6 @@ var CalculateForwardParentsWithLinks = class {
|
|
|
4698
5160
|
}
|
|
4699
5161
|
return calculations;
|
|
4700
5162
|
}
|
|
4701
|
-
/**
|
|
4702
|
-
* Handles the 'Start No Earlier Than' (SNET) constraint.
|
|
4703
|
-
* @param {Object|null} maxEfFromLinks - The maximum early finish from links.
|
|
4704
|
-
* @returns {Object} The calculation result considering the constraint.
|
|
4705
|
-
*/
|
|
4706
5163
|
handleSNETConstraint(maxEfFromLinks) {
|
|
4707
5164
|
const restriction = calculateRestrictionSnet({
|
|
4708
5165
|
duration: this.activity.duration,
|
|
@@ -4715,11 +5172,6 @@ var CalculateForwardParentsWithLinks = class {
|
|
|
4715
5172
|
}
|
|
4716
5173
|
return maxEfFromLinks.ef > restriction.ef ? maxEfFromLinks : restriction;
|
|
4717
5174
|
}
|
|
4718
|
-
/**
|
|
4719
|
-
* Handles the 'Finish No Later Than' (FNLT) constraint.
|
|
4720
|
-
* @param {Object|null} maxEfFromLinks - The maximum early finish from links.
|
|
4721
|
-
* @returns {Object} The calculation result considering the constraint.
|
|
4722
|
-
*/
|
|
4723
5175
|
handleFNLTConstraint(maxEfFromLinks) {
|
|
4724
5176
|
const restriction = calculateRestriction({
|
|
4725
5177
|
duration: -this.activity.duration,
|
|
@@ -4732,11 +5184,6 @@ var CalculateForwardParentsWithLinks = class {
|
|
|
4732
5184
|
}
|
|
4733
5185
|
return maxEfFromLinks.ef > restriction.ef ? restriction : maxEfFromLinks;
|
|
4734
5186
|
}
|
|
4735
|
-
/**
|
|
4736
|
-
* Calculates dates for 'Start to Start' (SS) link type.
|
|
4737
|
-
* @param {Object} params - Parameters containing lag and predecessor early start.
|
|
4738
|
-
* @returns {Object} The calculation result.
|
|
4739
|
-
*/
|
|
4740
5187
|
calculateSSLink({ lag, predecessorEs }) {
|
|
4741
5188
|
const esLinked = mutateDate({
|
|
4742
5189
|
linkType: "ss",
|
|
@@ -4767,11 +5214,6 @@ var CalculateForwardParentsWithLinks = class {
|
|
|
4767
5214
|
);
|
|
4768
5215
|
return { es, ef };
|
|
4769
5216
|
}
|
|
4770
|
-
/**
|
|
4771
|
-
* Calculates dates for 'Finish to Finish' (FF) link type.
|
|
4772
|
-
* @param {Object} params - Parameters containing lag and predecessor early finish.
|
|
4773
|
-
* @returns {Object} The calculation result.
|
|
4774
|
-
*/
|
|
4775
5217
|
calculateFFLink({ lag, predecessorEf }) {
|
|
4776
5218
|
const efLinked = mutateDate({
|
|
4777
5219
|
linkType: "ff",
|
|
@@ -4802,11 +5244,6 @@ var CalculateForwardParentsWithLinks = class {
|
|
|
4802
5244
|
}
|
|
4803
5245
|
return { es, ef };
|
|
4804
5246
|
}
|
|
4805
|
-
/**
|
|
4806
|
-
* Calculates dates for 'Finish to Start' (FS) link type.
|
|
4807
|
-
* @param {Object} params - Parameters containing lag and predecessor early finish.
|
|
4808
|
-
* @returns {Object} The calculation result.
|
|
4809
|
-
*/
|
|
4810
5247
|
calculateFSLink({ lag, predecessorEf }) {
|
|
4811
5248
|
let efLinked = predecessorEf;
|
|
4812
5249
|
if (lag === 0) {
|
|
@@ -4831,11 +5268,6 @@ var CalculateForwardParentsWithLinks = class {
|
|
|
4831
5268
|
);
|
|
4832
5269
|
return { es, ef };
|
|
4833
5270
|
}
|
|
4834
|
-
/**
|
|
4835
|
-
* Calculates dates for 'Start to Finish' (SF) link type.
|
|
4836
|
-
* @param {Object} params - Parameters containing lag, predecessor early start, and finish.
|
|
4837
|
-
* @returns {Object} The calculation result.
|
|
4838
|
-
*/
|
|
4839
5271
|
calculateSFLink({ lag, predecessorEs }) {
|
|
4840
5272
|
const ef = addDurationToDate(
|
|
4841
5273
|
this.activityCalendar,
|
|
@@ -5141,14 +5573,6 @@ var CalculateBackwardParentsLinks = class {
|
|
|
5141
5573
|
});
|
|
5142
5574
|
return newDate;
|
|
5143
5575
|
}
|
|
5144
|
-
/**
|
|
5145
|
-
* Determines if a given date corresponds to the initial work hour of an activity as defined in the activity calendar.
|
|
5146
|
-
* This function retrieves the first work interval from the activity calendar and compares the hour portion
|
|
5147
|
-
* of the input date to the start hour of the work interval.
|
|
5148
|
-
* @param {object} activityCalendar - The calendar object containing work hours and scheduling information for the activity.
|
|
5149
|
-
* @param {Date} date - The date to check against the activity's start hour.
|
|
5150
|
-
* @returns {boolean} True if the hour of the input date matches the initial work hour of the activity; otherwise, false.
|
|
5151
|
-
*/
|
|
5152
5576
|
isActivityInInitHour(activityCalendar, date2) {
|
|
5153
5577
|
const normalizedDate = date2 instanceof Date ? date2 : new Date(date2);
|
|
5154
5578
|
const shifts = activityCalendar.getWorkHours(normalizedDate);
|
|
@@ -5489,22 +5913,12 @@ var calculation_of_parent_default = CalculationOfParent;
|
|
|
5489
5913
|
|
|
5490
5914
|
// src/critical-path/legacy/base/third-level-activities/index.js
|
|
5491
5915
|
var ThirdLevelActivityIdentifier = class {
|
|
5492
|
-
/**
|
|
5493
|
-
* Constructs the ThirdLevelActivityIdentifier class.
|
|
5494
|
-
* @param {Object} params - The parameters object.
|
|
5495
|
-
* @param {Object} params.gantt - The Gantt chart instance.
|
|
5496
|
-
* @param {Object} params.filters - Filters for tasks.
|
|
5497
|
-
* @param {string} params.linkProperty - The property name for links.
|
|
5498
|
-
*/
|
|
5499
5916
|
constructor({ gantt, linkProperty }) {
|
|
5500
5917
|
this.gantt = gantt;
|
|
5501
5918
|
this.linkProperty = linkProperty;
|
|
5502
5919
|
this.structureOfParents = /* @__PURE__ */ new Map();
|
|
5503
5920
|
this.singleParents = /* @__PURE__ */ new Map();
|
|
5504
5921
|
}
|
|
5505
|
-
/**
|
|
5506
|
-
* Identifies third-level activities and populates the structureOfParents map.
|
|
5507
|
-
*/
|
|
5508
5922
|
identifyThirdLevelActivities() {
|
|
5509
5923
|
try {
|
|
5510
5924
|
const parents = this.getFirstLevelParents();
|
|
@@ -5529,18 +5943,9 @@ var ThirdLevelActivityIdentifier = class {
|
|
|
5529
5943
|
throw e;
|
|
5530
5944
|
}
|
|
5531
5945
|
}
|
|
5532
|
-
/**
|
|
5533
|
-
* Retrieves the first-level parent tasks.
|
|
5534
|
-
* @returns {Array<Object>} Array of parent tasks.
|
|
5535
|
-
*/
|
|
5536
5946
|
getFirstLevelParents() {
|
|
5537
5947
|
return this.gantt.getTaskByTime().filter(filters_default.byFirstLevel).filter(filters_default.filterByParentType);
|
|
5538
5948
|
}
|
|
5539
|
-
/**
|
|
5540
|
-
* Processes each activity under a parent task.
|
|
5541
|
-
* @param {Object} parentActivity - The parent activity to process.
|
|
5542
|
-
* @returns {Object} Processed data including parentsIds, allTasks, activitiesByLevel.
|
|
5543
|
-
*/
|
|
5544
5949
|
processEachActivity(parentActivity) {
|
|
5545
5950
|
const parentsIds = /* @__PURE__ */ new Set();
|
|
5546
5951
|
const allTasks = /* @__PURE__ */ new Set();
|
|
@@ -5555,10 +5960,6 @@ var ThirdLevelActivityIdentifier = class {
|
|
|
5555
5960
|
activitiesByLevel
|
|
5556
5961
|
};
|
|
5557
5962
|
}
|
|
5558
|
-
/**
|
|
5559
|
-
* Initializes the parent activity in singleParents map.
|
|
5560
|
-
* @param {Object} parentActivity - The parent activity.
|
|
5561
|
-
*/
|
|
5562
5963
|
initializeParent(parentActivity) {
|
|
5563
5964
|
const parentId = Number(parentActivity.id);
|
|
5564
5965
|
const hasLink = Boolean(parentActivity[this.linkProperty]?.length);
|
|
@@ -5569,13 +5970,6 @@ var ThirdLevelActivityIdentifier = class {
|
|
|
5569
5970
|
childrens: []
|
|
5570
5971
|
});
|
|
5571
5972
|
}
|
|
5572
|
-
/**
|
|
5573
|
-
* Processes a single activity.
|
|
5574
|
-
* @param {Object} activity - The activity to process.
|
|
5575
|
-
* @param {Set<number>} parentsIds - Set of parent IDs.
|
|
5576
|
-
* @param {Set<number>} allTasks - Set of all task IDs.
|
|
5577
|
-
* @param {Map<number, Map<number, Array<Object>>>} activitiesByLevel - Activities grouped by level.
|
|
5578
|
-
*/
|
|
5579
5973
|
processActivity(activity, parentsIds, allTasks, activitiesByLevel) {
|
|
5580
5974
|
const activityId = Number(activity.id);
|
|
5581
5975
|
const parentId = Number(activity.parent);
|
|
@@ -5590,27 +5984,12 @@ var ThirdLevelActivityIdentifier = class {
|
|
|
5590
5984
|
}
|
|
5591
5985
|
this.addActivityToLevel(activity, activitiesByLevel);
|
|
5592
5986
|
}
|
|
5593
|
-
/**
|
|
5594
|
-
* Checks if an activity is a project (parent activity).
|
|
5595
|
-
* @param {Object} activity - The activity to check.
|
|
5596
|
-
* @returns {boolean} True if the activity is a project.
|
|
5597
|
-
*/
|
|
5598
5987
|
isProjectActivity(activity) {
|
|
5599
5988
|
return activity.type === "project";
|
|
5600
5989
|
}
|
|
5601
|
-
/**
|
|
5602
|
-
* Checks if an activity has a link.
|
|
5603
|
-
* @param {Object} activity - The activity to check.
|
|
5604
|
-
* @returns {boolean} True if the activity has a link.
|
|
5605
|
-
*/
|
|
5606
5990
|
hasLink(activity) {
|
|
5607
5991
|
return Boolean(activity[this.linkProperty]?.length);
|
|
5608
5992
|
}
|
|
5609
|
-
/**
|
|
5610
|
-
* Adds parent information to singleParents map.
|
|
5611
|
-
* @param {Object} activity - The parent activity.
|
|
5612
|
-
* @param {Set<number>} parentsIds - Set of parent IDs.
|
|
5613
|
-
*/
|
|
5614
5993
|
addParentInfo(activity, parentsIds) {
|
|
5615
5994
|
const parentId = Number(activity.id);
|
|
5616
5995
|
const level = activity["$level"];
|
|
@@ -5623,27 +6002,12 @@ var ThirdLevelActivityIdentifier = class {
|
|
|
5623
6002
|
parentsIds.add(parentId);
|
|
5624
6003
|
this.singleParents.set(parentId, parentInfo);
|
|
5625
6004
|
}
|
|
5626
|
-
/**
|
|
5627
|
-
* Checks if a parent exists in singleParents map.
|
|
5628
|
-
* @param {number} parentId - The parent ID to check.
|
|
5629
|
-
* @returns {boolean} True if the parent exists.
|
|
5630
|
-
*/
|
|
5631
6005
|
doesParentExist(parentId) {
|
|
5632
6006
|
return this.singleParents.has(parentId);
|
|
5633
6007
|
}
|
|
5634
|
-
/**
|
|
5635
|
-
* Adds a child activity to its parent in singleParents map.
|
|
5636
|
-
* @param {number} parentId - The parent ID.
|
|
5637
|
-
* @param {number} activityId - The child activity ID.
|
|
5638
|
-
*/
|
|
5639
6008
|
addChildToParent(parentId, activityId) {
|
|
5640
6009
|
this.singleParents.get(parentId).childrens.push(activityId);
|
|
5641
6010
|
}
|
|
5642
|
-
/**
|
|
5643
|
-
* Adds an activity to the activitiesByLevel map.
|
|
5644
|
-
* @param {Object} activity - The activity to add.
|
|
5645
|
-
* @param {Map<number, Map<number, Array<Object>>>} activitiesByLevel - Activities grouped by level.
|
|
5646
|
-
*/
|
|
5647
6011
|
addActivityToLevel(activity, activitiesByLevel) {
|
|
5648
6012
|
const levelKey = activity["$level"];
|
|
5649
6013
|
const parentKey = Number(activity.parent);
|
|
@@ -5660,33 +6024,15 @@ var ThirdLevelActivityIdentifier = class {
|
|
|
5660
6024
|
calculated: false
|
|
5661
6025
|
});
|
|
5662
6026
|
}
|
|
5663
|
-
/**
|
|
5664
|
-
* Retrieves all levels from activitiesByLevel map.
|
|
5665
|
-
* @param {Map<number, Map<number, Array<Object>>>} activitiesByLevel - Activities grouped by level.
|
|
5666
|
-
* @returns {Set<number>} Set of all levels.
|
|
5667
|
-
*/
|
|
5668
6027
|
getAllLevels(activitiesByLevel) {
|
|
5669
6028
|
return new Set(activitiesByLevel.keys());
|
|
5670
6029
|
}
|
|
5671
|
-
/**
|
|
5672
|
-
* Determines the deepest level from a set of levels.
|
|
5673
|
-
* @param {Set<number>} allLevels - Set of all levels.
|
|
5674
|
-
* @returns {number} The deepest level.
|
|
5675
|
-
*/
|
|
5676
6030
|
getDeepestLevel(allLevels) {
|
|
5677
6031
|
if (allLevels.size === 0) {
|
|
5678
6032
|
return 0;
|
|
5679
6033
|
}
|
|
5680
6034
|
return Math.max(...allLevels);
|
|
5681
6035
|
}
|
|
5682
|
-
/**
|
|
5683
|
-
* Creates the result object for a parent activity.
|
|
5684
|
-
* @param {Object} parent - The parent activity.
|
|
5685
|
-
* @param {Object} processPayload - The processed data.
|
|
5686
|
-
* @param {number} deepestLevel - The deepest level found.
|
|
5687
|
-
* @param {Set<number>} allLevels - Set of all levels.
|
|
5688
|
-
* @returns {Object} The result object.
|
|
5689
|
-
*/
|
|
5690
6036
|
createResult(parent, processPayload, deepestLevel, allLevels) {
|
|
5691
6037
|
const { activitiesByLevel, parentsIds, allTasks } = processPayload;
|
|
5692
6038
|
return {
|
|
@@ -5852,22 +6198,6 @@ var CriticalPathHelpers = class {
|
|
|
5852
6198
|
throw e;
|
|
5853
6199
|
}
|
|
5854
6200
|
}
|
|
5855
|
-
/**
|
|
5856
|
-
* Identifies and sets the initial activities for the chain based on the specified direction.
|
|
5857
|
-
*
|
|
5858
|
-
* This function determines the starting activities of a chain by filtering activities from
|
|
5859
|
-
* the Gantt chart. The filtering is based on the specified direction (`forward` or `backward`).
|
|
5860
|
-
* - For `forward` direction, activities with an empty `$target` property are selected.
|
|
5861
|
-
* - For `backward` direction, activities with an empty `$source` property are selected.
|
|
5862
|
-
*
|
|
5863
|
-
* The function excludes activities of type `project` from the results.
|
|
5864
|
-
* The resulting activity IDs are stored in the `chainStartActivities` property.
|
|
5865
|
-
*
|
|
5866
|
-
* If an error occurs during the process, `chainStartActivities` is set to an empty array,
|
|
5867
|
-
* and the error is rethrown.
|
|
5868
|
-
*
|
|
5869
|
-
* @throws {Error} If an error occurs during the identification process.
|
|
5870
|
-
*/
|
|
5871
6201
|
identifyInitialActivities() {
|
|
5872
6202
|
try {
|
|
5873
6203
|
const {
|
|
@@ -5978,27 +6308,6 @@ var CriticalPathHelpers = class {
|
|
|
5978
6308
|
}
|
|
5979
6309
|
return sorted.reverse();
|
|
5980
6310
|
}
|
|
5981
|
-
/**
|
|
5982
|
-
* Calculates the start and finish dates for the origin of a chain activity.
|
|
5983
|
-
*
|
|
5984
|
-
* This function calculates the start and finish dates for an activity based on the provided direction
|
|
5985
|
-
* (`forward` or `backward`). For forward direction, it calculates the earliest start (ES) and earliest
|
|
5986
|
-
* finish (EF). For backward direction, it calculates the latest start (LS) and latest finish (LF),
|
|
5987
|
-
* handling different progress states (0%, 100%, and between 0% and 100%).
|
|
5988
|
-
*
|
|
5989
|
-
* @param {Object} [activityFromLink=null] - The activity object to calculate dates for.
|
|
5990
|
-
* @param {string} [customDirection=null] - The direction for the calculation (`forward` or `backward`).
|
|
5991
|
-
* @returns {Object} An object containing the calculated dates (ES, EF, LS, LF) based on the direction and progress.
|
|
5992
|
-
*
|
|
5993
|
-
* @example
|
|
5994
|
-
* // Assuming activity is an object with start_date, end_date, progress, and calendar_id properties
|
|
5995
|
-
* // and direction is 'forward'
|
|
5996
|
-
* const dates = calculateStartAndFinishOfChainOrigin(activity, 'forward');
|
|
5997
|
-
* console.log()
|
|
5998
|
-
// { es: activity.start_date, ef: activity.end_date }
|
|
5999
|
-
*
|
|
6000
|
-
* @throws {Error} If the activity's calendar cannot be retrieved or other errors occur during calculation.
|
|
6001
|
-
*/
|
|
6002
6311
|
calculateStartAndFinishOfChainOrigin(activityFromLink = null, customDirection = null) {
|
|
6003
6312
|
try {
|
|
6004
6313
|
let activity = activityFromLink;
|
|
@@ -6044,25 +6353,6 @@ var CriticalPathHelpers = class {
|
|
|
6044
6353
|
throw e;
|
|
6045
6354
|
}
|
|
6046
6355
|
}
|
|
6047
|
-
/**
|
|
6048
|
-
* Calculates the latest start (LS) and latest finish (LF) dates for an activity with zero progress.
|
|
6049
|
-
*
|
|
6050
|
-
* This function determines the LS and LF dates based on the activity's constraint type and duration,
|
|
6051
|
-
* using the provided calendar. It handles different types of constraints, adjusting the start and finish
|
|
6052
|
-
* dates accordingly.
|
|
6053
|
-
*
|
|
6054
|
-
* @param {Object} activity - The activity object to calculate dates for, which should include start_date, end_date, duration, and constraint_type.
|
|
6055
|
-
* @param {Object} calendar - The calendar object used to adjust dates based on working days and hours.
|
|
6056
|
-
* @returns {Object} An object containing the calculated latest start (LS) and latest finish (LF) dates.
|
|
6057
|
-
*
|
|
6058
|
-
* @example
|
|
6059
|
-
* // Assuming activity is an object with the required properties and a calendar object is provided
|
|
6060
|
-
* const dates = calculateBackwardWhenZeroProgress(activity, calendar);
|
|
6061
|
-
* console.log()
|
|
6062
|
-
// { ls: moment(...), lf: moment(...) }
|
|
6063
|
-
*
|
|
6064
|
-
* @throws {Error} If an error occurs during the calculation.
|
|
6065
|
-
*/
|
|
6066
6356
|
calculateBackwardWhenZeroProgress(activity, calendar) {
|
|
6067
6357
|
let lateStart = moment_default(activity.start_date).clone();
|
|
6068
6358
|
let lateFinish = moment_default(activity.end_date).clone();
|
|
@@ -6099,23 +6389,6 @@ var CriticalPathHelpers = class {
|
|
|
6099
6389
|
lf: lateFinish
|
|
6100
6390
|
};
|
|
6101
6391
|
}
|
|
6102
|
-
/**
|
|
6103
|
-
* Calculates the latest start (LS) and latest finish (LF) dates for an activity with progress between 0% and 100%.
|
|
6104
|
-
*
|
|
6105
|
-
* This function determines the LS and LF dates based on the activity's constraint type and progress,
|
|
6106
|
-
* considering the end date of the project and various constraints.
|
|
6107
|
-
*
|
|
6108
|
-
* @param {Object} activity - The activity object to calculate dates for, which should include start_date, end_date, and constraint_type.
|
|
6109
|
-
* @returns {Object} An object containing the calculated latest start (LS) and latest finish (LF) dates.
|
|
6110
|
-
*
|
|
6111
|
-
* @example
|
|
6112
|
-
* // Assuming activity is an object with the required properties
|
|
6113
|
-
* const dates = calculateWhenProgressIsBetweenZeroAndOneHundred(activity);
|
|
6114
|
-
* console.log()
|
|
6115
|
-
// { ls: activity.start_date, lf: calculatedLateFinish }
|
|
6116
|
-
*
|
|
6117
|
-
* @throws {Error} If an error occurs during the calculation.
|
|
6118
|
-
*/
|
|
6119
6392
|
calculateWhenProgressIsBetweenZeroAndOneHundred(activity) {
|
|
6120
6393
|
let lateStart = activity.start_date;
|
|
6121
6394
|
let lateFinish = null;
|
|
@@ -6176,7 +6449,6 @@ var CriticalPathHelpers = class {
|
|
|
6176
6449
|
throw e;
|
|
6177
6450
|
}
|
|
6178
6451
|
}
|
|
6179
|
-
// Main function
|
|
6180
6452
|
doCalculationForParentType(activity) {
|
|
6181
6453
|
const calculationOfParent = new calculation_of_parent_default({
|
|
6182
6454
|
activity,
|
|
@@ -6254,22 +6526,6 @@ var LinksRulesCalculationsMethods = class {
|
|
|
6254
6526
|
this.parentsCalculations = calculationObject.parentsCalculations;
|
|
6255
6527
|
this.gantt = calculationObject.ganttInstance;
|
|
6256
6528
|
}
|
|
6257
|
-
/**
|
|
6258
|
-
* Retrieves the earliest start (ES) and earliest finish (EF) dates for a given activity from previously calculated activities.
|
|
6259
|
-
*
|
|
6260
|
-
* This function checks if the activity exists in the `alapMap`. If it does, it returns the data from `alapMap`.
|
|
6261
|
-
* If the activity is not found in `alapMap`, it retrieves and returns the data from `calculatedActivities`.
|
|
6262
|
-
*
|
|
6263
|
-
* @param {string|number} activity - The ID of the activity for which to retrieve ES and EF dates.
|
|
6264
|
-
* @returns {Object|null} The ES and EF dates for the activity, or null if not found.
|
|
6265
|
-
*
|
|
6266
|
-
* @example
|
|
6267
|
-
* // Assuming alapMap and calculatedActivities are Maps with activity data
|
|
6268
|
-
* const esEf = getEsAndEfFromPreviousCalculatedActivities(1);
|
|
6269
|
-
// { es: ..., ef: ..., text: ... } or null
|
|
6270
|
-
*
|
|
6271
|
-
* @throws {Error} If an error occurs during the retrieval process.
|
|
6272
|
-
*/
|
|
6273
6529
|
getEsAndEfFromPreviousCalculatedActivities(activity) {
|
|
6274
6530
|
const isAlap = this.alapMap.has(activity);
|
|
6275
6531
|
if (isAlap) {
|
|
@@ -6277,29 +6533,6 @@ var LinksRulesCalculationsMethods = class {
|
|
|
6277
6533
|
}
|
|
6278
6534
|
return this.calculatedActivities.get(Number(activity));
|
|
6279
6535
|
}
|
|
6280
|
-
/**
|
|
6281
|
-
* Calculates the earliest start (ES) and earliest finish (EF) times for a successor activity.
|
|
6282
|
-
*
|
|
6283
|
-
* This function calculates the ES and EF times for a successor activity based on the provided predecessor time,
|
|
6284
|
-
* data calculations for ES and EF, lag time, and the type of link restriction. It adjusts the dates according
|
|
6285
|
-
* to the activity's calendar and the specified restrictions.
|
|
6286
|
-
*
|
|
6287
|
-
* @param {Date} predecessorTime - The time of the predecessor activity.
|
|
6288
|
-
* @param {number} esDataCalculation - The amount of time to add to the predecessor time to calculate the earliest start.
|
|
6289
|
-
* @param {number} [efDataCalculation=0] - The amount of time to add to calculate the earliest finish.
|
|
6290
|
-
* @param {number} lag - The lag time between the predecessor and successor activities.
|
|
6291
|
-
* @param {string} [restrictionOfLink='fs'] - The type of link restriction between the activities.
|
|
6292
|
-
* @returns {Object} An object containing the calculated earliest start (ES) and earliest finish (EF) times.
|
|
6293
|
-
* @property {Date} es - The earliest start time.
|
|
6294
|
-
* @property {Date} ef - The earliest finish time.
|
|
6295
|
-
*
|
|
6296
|
-
* @example
|
|
6297
|
-
* // Assuming predecessorTime is a Date object, esDataCalculation is 5, efDataCalculation is 10, lag is 2, and restrictionOfLink is 'fs'
|
|
6298
|
-
* const result = calculateSucessorTimes(new Date(), 5, 10, 2, 'fs');
|
|
6299
|
-
// { es: Date, ef: Date }
|
|
6300
|
-
*
|
|
6301
|
-
* @throws {Error} If an error occurs during the calculation process.
|
|
6302
|
-
*/
|
|
6303
6536
|
calculateSucessorTimes(predecessorTime, esDataCalculation, efDataCalculation = 0, lag, restrictionOfLink = LINK_TYPES.FS) {
|
|
6304
6537
|
const activityCalendar = this.gantt.getCalendar(
|
|
6305
6538
|
this.referenceActivity.calendar_id
|
|
@@ -6372,27 +6605,6 @@ var LinksRulesCalculationsMethods = class {
|
|
|
6372
6605
|
}
|
|
6373
6606
|
return { es, ef };
|
|
6374
6607
|
}
|
|
6375
|
-
/**
|
|
6376
|
-
* Calculates the earliest start (ES) and earliest finish (EF) times for a Start-to-Start (SS) relationship.
|
|
6377
|
-
*
|
|
6378
|
-
* This function calculates the ES and EF times for a successor activity based on a Start-to-Start (SS) relationship
|
|
6379
|
-
* with the predecessor activity. It uses the predecessor's ES time and adjusts it based on the link's lag and the
|
|
6380
|
-
* activity's duration.
|
|
6381
|
-
*
|
|
6382
|
-
* @param {Object} link - The link object representing the relationship between the predecessor and successor activities.
|
|
6383
|
-
* @param {number} link.source - The ID of the predecessor activity.
|
|
6384
|
-
* @param {number} [link.lag=0] - The lag time between the predecessor and successor activities.
|
|
6385
|
-
* @returns {Object} An object containing the calculated earliest start (ES) and earliest finish (EF) times.
|
|
6386
|
-
* @property {Date} es - The earliest start time.
|
|
6387
|
-
* @property {Date} ef - The earliest finish time.
|
|
6388
|
-
*
|
|
6389
|
-
* @example
|
|
6390
|
-
* // Assuming link is an object with a source property (predecessor ID) and an optional lag property
|
|
6391
|
-
* const result = calculateSS({ source: 1, lag: 2 });
|
|
6392
|
-
// { es: Date, ef: Date }
|
|
6393
|
-
*
|
|
6394
|
-
* @throws {Error} If an error occurs during the calculation process.
|
|
6395
|
-
*/
|
|
6396
6608
|
calculateSS(link) {
|
|
6397
6609
|
const predecessorCalculatedEsAndEf = this.getEsAndEfFromPreviousCalculatedActivities(Number(link.source));
|
|
6398
6610
|
const esDataCalculation = link.lag || 0;
|
|
@@ -6407,27 +6619,6 @@ var LinksRulesCalculationsMethods = class {
|
|
|
6407
6619
|
LINK_TYPES.SS
|
|
6408
6620
|
);
|
|
6409
6621
|
}
|
|
6410
|
-
/**
|
|
6411
|
-
* Calculates the earliest start (ES) and earliest finish (EF) times for a Finish-to-Finish (FF) relationship.
|
|
6412
|
-
*
|
|
6413
|
-
* This function calculates the ES and EF times for a successor activity based on a Finish-to-Finish (FF) relationship
|
|
6414
|
-
* with the predecessor activity. It uses the predecessor's EF time and adjusts it based on the link's lag and the
|
|
6415
|
-
* activity's duration.
|
|
6416
|
-
*
|
|
6417
|
-
* @param {Object} link - The link object representing the relationship between the predecessor and successor activities.
|
|
6418
|
-
* @param {number} link.source - The ID of the predecessor activity.
|
|
6419
|
-
* @param {number} [link.lag=0] - The lag time between the predecessor and successor activities.
|
|
6420
|
-
* @returns {Object} An object containing the calculated earliest start (ES) and earliest finish (EF) times.
|
|
6421
|
-
* @property {Date} es - The earliest start time.
|
|
6422
|
-
* @property {Date} ef - The earliest finish time.
|
|
6423
|
-
*
|
|
6424
|
-
* @example
|
|
6425
|
-
* // Assuming link is an object with a source property (predecessor ID) and an optional lag property
|
|
6426
|
-
* const result = calculateFF({ source: 1, lag: 2 });
|
|
6427
|
-
// { es: Date, ef: Date }
|
|
6428
|
-
*
|
|
6429
|
-
* @throws {Error} If an error occurs during the calculation process.
|
|
6430
|
-
*/
|
|
6431
6622
|
calculateFF(link) {
|
|
6432
6623
|
const predecessorCalculatedEsAndEf = this.getEsAndEfFromPreviousCalculatedActivities(Number(link.source));
|
|
6433
6624
|
const duration = this.referenceActivity.duration;
|
|
@@ -6442,27 +6633,6 @@ var LinksRulesCalculationsMethods = class {
|
|
|
6442
6633
|
LINK_TYPES.FF
|
|
6443
6634
|
);
|
|
6444
6635
|
}
|
|
6445
|
-
/**
|
|
6446
|
-
* Calculates the earliest start (ES) and earliest finish (EF) times for a Finish-to-Start (FS) relationship.
|
|
6447
|
-
*
|
|
6448
|
-
* This function calculates the ES and EF times for a successor activity based on a Finish-to-Start (FS) relationship
|
|
6449
|
-
* with the predecessor activity. It uses the predecessor's EF time and adjusts it based on the link's lag and the
|
|
6450
|
-
* activity's duration.
|
|
6451
|
-
*
|
|
6452
|
-
* @param {Object} link - The link object representing the relationship between the predecessor and successor activities.
|
|
6453
|
-
* @param {number} link.source - The ID of the predecessor activity.
|
|
6454
|
-
* @param {number} [link.lag=0] - The lag time between the predecessor and successor activities.
|
|
6455
|
-
* @returns {Object} An object containing the calculated earliest start (ES) and earliest finish (EF) times.
|
|
6456
|
-
* @property {Date} es - The earliest start time.
|
|
6457
|
-
* @property {Date} ef - The earliest finish time.
|
|
6458
|
-
*
|
|
6459
|
-
* @example
|
|
6460
|
-
* // Assuming link is an object with a source property (predecessor ID) and an optional lag property
|
|
6461
|
-
* const result = calculateFS({ source: 1, lag: 2 });
|
|
6462
|
-
// { es: Date, ef: Date }
|
|
6463
|
-
*
|
|
6464
|
-
* @throws {Error} If an error occurs during the calculation process.
|
|
6465
|
-
*/
|
|
6466
6636
|
calculateFS(link) {
|
|
6467
6637
|
const predecessorCalculatedEsAndEf = this.getEsAndEfFromPreviousCalculatedActivities(Number(link.source));
|
|
6468
6638
|
const esDataCalculation = link.lag || 0;
|
|
@@ -6477,27 +6647,6 @@ var LinksRulesCalculationsMethods = class {
|
|
|
6477
6647
|
LINK_TYPES.FS
|
|
6478
6648
|
);
|
|
6479
6649
|
}
|
|
6480
|
-
/**
|
|
6481
|
-
* Calculates the earliest start (ES) and earliest finish (EF) times for a Start-to-Finish (SF) relationship.
|
|
6482
|
-
*
|
|
6483
|
-
* This function calculates the ES and EF times for a successor activity based on a Start-to-Finish (SF) relationship
|
|
6484
|
-
* with the predecessor activity. It uses the predecessor's EF time and adjusts it based on the link's lag and the
|
|
6485
|
-
* activity's duration.
|
|
6486
|
-
*
|
|
6487
|
-
* @param {Object} link - The link object representing the relationship between the predecessor and successor activities.
|
|
6488
|
-
* @param {number} link.source - The ID of the predecessor activity.
|
|
6489
|
-
* @param {number} [link.lag=0] - The lag time between the predecessor and successor activities.
|
|
6490
|
-
* @returns {Object} An object containing the calculated earliest start (ES) and earliest finish (EF) times.
|
|
6491
|
-
* @property {Date} es - The earliest start time.
|
|
6492
|
-
* @property {Date} ef - The earliest finish time.
|
|
6493
|
-
*
|
|
6494
|
-
* @example
|
|
6495
|
-
* // Assuming link is an object with a source property (predecessor ID) and an optional lag property
|
|
6496
|
-
* const result = calculateSF({ source: 1, lag: 2 });
|
|
6497
|
-
// { es: Date, ef: Date }
|
|
6498
|
-
*
|
|
6499
|
-
* @throws {Error} If an error occurs during the calculation process.
|
|
6500
|
-
*/
|
|
6501
6650
|
calculateSF(link) {
|
|
6502
6651
|
const predecessorCalculatedEsAndEf = this.getEsAndEfFromPreviousCalculatedActivities(Number(link.source));
|
|
6503
6652
|
const duration = this.referenceActivity.duration;
|
|
@@ -6512,24 +6661,6 @@ var LinksRulesCalculationsMethods = class {
|
|
|
6512
6661
|
LINK_TYPES.SF
|
|
6513
6662
|
);
|
|
6514
6663
|
}
|
|
6515
|
-
/**
|
|
6516
|
-
* Adjusts a date to the next working hour based on the type of link restriction and the activity's calendar.
|
|
6517
|
-
*
|
|
6518
|
-
* This function adjusts the provided date either to a future or past working hour based on the specified link restriction.
|
|
6519
|
-
* It uses the activity's calendar to determine the working hours and calculates the appropriate date.
|
|
6520
|
-
*
|
|
6521
|
-
* @param {Date} dateBaseToCalculate - The initial date that needs to be adjusted.
|
|
6522
|
-
* @param {string} restrictionOfLink - The type of link restriction (e.g., 'fs', 'ss', 'ff').
|
|
6523
|
-
* @param {Object} activityCalendar - The calendar associated with the activity, used to determine working hours.
|
|
6524
|
-
* @returns {Date} The adjusted date based on the link restriction and activity calendar.
|
|
6525
|
-
*
|
|
6526
|
-
* @example
|
|
6527
|
-
* // Assuming dateBaseToCalculate is a Date object, restrictionOfLink is 'fs', and activityCalendar is a valid calendar object
|
|
6528
|
-
* const adjustedDate = mutateTheDateToFutureOrPastInBaseRestriction(new Date(), 'fs', activityCalendar);
|
|
6529
|
-
// The date adjusted to the next working hour in the future
|
|
6530
|
-
*
|
|
6531
|
-
* @throws {Error} If an error occurs during the date adjustment process.
|
|
6532
|
-
*/
|
|
6533
6664
|
mutateTheDateToFutureOrPastInBaseRestriction(dateBaseToCalculate, restrictionOfLink, activityCalendar) {
|
|
6534
6665
|
if (![LINK_TYPES.FS, LINK_TYPES.SS, LINK_TYPES.FF].includes(restrictionOfLink)) {
|
|
6535
6666
|
return dateBaseToCalculate;
|
|
@@ -6553,22 +6684,6 @@ var LinksConstraintCalculator = class extends LinksRulesCalculationsMethods_defa
|
|
|
6553
6684
|
constructor(calculationObject) {
|
|
6554
6685
|
super(calculationObject);
|
|
6555
6686
|
}
|
|
6556
|
-
/**
|
|
6557
|
-
* Calculates the earliest start dates for all links and returns the maximum early start set.
|
|
6558
|
-
*
|
|
6559
|
-
* This function processes each link in the `links` array, retrieves the necessary link data, and calculates
|
|
6560
|
-
* the earliest start dates using the `calculateLink` method. It then returns the maximum early start set
|
|
6561
|
-
* by calling `getMaxEarlyStartSet`.
|
|
6562
|
-
*
|
|
6563
|
-
* @returns {Object} The maximum early start set calculated from all links.
|
|
6564
|
-
*
|
|
6565
|
-
* @example
|
|
6566
|
-
* // Assuming links is an array of link IDs [1, 2, 3]
|
|
6567
|
-
* // and gantt.getLink(id) returns link data for each ID
|
|
6568
|
-
* const result = calculate();
|
|
6569
|
-
*
|
|
6570
|
-
* @throws {Error} If an error occurs during the calculation process.
|
|
6571
|
-
*/
|
|
6572
6687
|
calculate() {
|
|
6573
6688
|
if (this.links.length === 0) {
|
|
6574
6689
|
return new generic_calculations_default(
|
|
@@ -6599,23 +6714,6 @@ var LinksConstraintCalculator = class extends LinksRulesCalculationsMethods_defa
|
|
|
6599
6714
|
}
|
|
6600
6715
|
return getMaxEarlyStartSet(allLinksCalculations);
|
|
6601
6716
|
}
|
|
6602
|
-
/**
|
|
6603
|
-
* Calculates the link based on its type.
|
|
6604
|
-
*
|
|
6605
|
-
* This function determines the appropriate calculation method for the link based on its type and executes it.
|
|
6606
|
-
* The link type is mapped to specific calculation methods: Finish-to-Start (FS), Start-to-Start (SS),
|
|
6607
|
-
* Finish-to-Finish (FF), and Start-to-Finish (SF).
|
|
6608
|
-
*
|
|
6609
|
-
* @param {Object} linkData - The data of the link to be calculated. It should include a `type` property that indicates the type of link.
|
|
6610
|
-
* @returns {*} The result of the calculation based on the link type.
|
|
6611
|
-
*
|
|
6612
|
-
* @example
|
|
6613
|
-
* // Assuming linkData is an object with a type property
|
|
6614
|
-
* const result = calculateLink({ type: 0, ...otherLinkProperties });
|
|
6615
|
-
* // This will call the calculateFS method with the linkData and return the result
|
|
6616
|
-
*
|
|
6617
|
-
* @throws {Error} If the link type is not recognized.
|
|
6618
|
-
*/
|
|
6619
6717
|
calculateLink(linkData) {
|
|
6620
6718
|
const calculationMapping = {
|
|
6621
6719
|
0: () => this.calculateFS(linkData),
|
|
@@ -6641,11 +6739,6 @@ var ActivityCalculator = class {
|
|
|
6641
6739
|
this.linkProperty = options.linkProperty;
|
|
6642
6740
|
this.linkDirection = options.linkDirection;
|
|
6643
6741
|
}
|
|
6644
|
-
/**
|
|
6645
|
-
* Checks which activities can now be calculated based on their dependencies.
|
|
6646
|
-
* @param {Set<number>} pendingToCalculate - Set of activity IDs pending calculation.
|
|
6647
|
-
* @returns {Object} An object containing activities that can be calculated and remaining pending activities.
|
|
6648
|
-
*/
|
|
6649
6742
|
checkActivitiesThatNowCanBeCalculated(pendingToCalculate) {
|
|
6650
6743
|
const activitiesThatCanBeCalculated = /* @__PURE__ */ new Set();
|
|
6651
6744
|
const pendingActivities = new Set(pendingToCalculate);
|
|
@@ -6672,9 +6765,6 @@ var ActivityCalculator = class {
|
|
|
6672
6765
|
pendingActivities
|
|
6673
6766
|
};
|
|
6674
6767
|
}
|
|
6675
|
-
/**
|
|
6676
|
-
* Handles logic for project-type activities.
|
|
6677
|
-
*/
|
|
6678
6768
|
handleProjectActivity(activityId, activityData, activitiesThatCanBeCalculated, pendingActivities) {
|
|
6679
6769
|
const isPendingParentWithNoLinks = this.pendingParentsWithNoLinks.has(activityId);
|
|
6680
6770
|
const isPendingParentWithLinks = this.pendingParentsWithLinks.has(activityId);
|
|
@@ -6715,9 +6805,6 @@ var ActivityCalculator = class {
|
|
|
6715
6805
|
}
|
|
6716
6806
|
}
|
|
6717
6807
|
}
|
|
6718
|
-
/**
|
|
6719
|
-
* Determines if a parent activity can be calculated.
|
|
6720
|
-
*/
|
|
6721
6808
|
canCalculateParentActivity(activityData) {
|
|
6722
6809
|
const hasNoLinks = (activityData[this.linkProperty] || []).length === 0;
|
|
6723
6810
|
const constraintType = activityData.constraint_type;
|
|
@@ -6732,9 +6819,6 @@ var ActivityCalculator = class {
|
|
|
6732
6819
|
(activityId) => this.calculations.has(activityId)
|
|
6733
6820
|
);
|
|
6734
6821
|
}
|
|
6735
|
-
/**
|
|
6736
|
-
* Handles logic for non-project activities.
|
|
6737
|
-
*/
|
|
6738
6822
|
handleNonProjectActivity(activityId, activityData, activitiesThatCanBeCalculated, pendingActivities) {
|
|
6739
6823
|
const parentId = Number(activityData.parent);
|
|
6740
6824
|
const isParentPendingWithLinks = this.pendingParentsWithLinks.has(parentId);
|
|
@@ -6772,9 +6856,6 @@ var ActivityCalculator = class {
|
|
|
6772
6856
|
pendingActivities.delete(activityId);
|
|
6773
6857
|
}
|
|
6774
6858
|
}
|
|
6775
|
-
/**
|
|
6776
|
-
* Retrieves linked activities based on link property.
|
|
6777
|
-
*/
|
|
6778
6859
|
getLinkedActivities(predecessors) {
|
|
6779
6860
|
if (!Array.isArray(predecessors)) {
|
|
6780
6861
|
return [];
|
|
@@ -6793,9 +6874,6 @@ var ActivityCalculator = class {
|
|
|
6793
6874
|
}
|
|
6794
6875
|
return linkedActivities;
|
|
6795
6876
|
}
|
|
6796
|
-
/**
|
|
6797
|
-
* Retrieves an array of linked activity IDs.
|
|
6798
|
-
*/
|
|
6799
6877
|
getArrayOfLinkedActivities(links) {
|
|
6800
6878
|
if (!Array.isArray(links)) {
|
|
6801
6879
|
return [];
|
|
@@ -6817,8 +6895,7 @@ var get_activities_to_calculate_default = ActivityCalculator;
|
|
|
6817
6895
|
var createIsCurrent2 = (calculationId, getCurrentId) => () => getCurrentId() === calculationId;
|
|
6818
6896
|
|
|
6819
6897
|
// src/critical-path/legacy/utils/validation.js
|
|
6820
|
-
var shouldAbortCalculation = (gantt) => !gantt?.fullyParsed ||
|
|
6821
|
-
typeof window !== "undefined" && window.to_use_react_gantt?.conversionMode?.isActive;
|
|
6898
|
+
var shouldAbortCalculation = (gantt) => !gantt?.fullyParsed || typeof window !== "undefined" && window.to_use_react_gantt?.conversionMode?.isActive;
|
|
6822
6899
|
|
|
6823
6900
|
// src/critical-path/legacy/utils/timing.js
|
|
6824
6901
|
var TIME_BUDGET_MS = 16;
|
|
@@ -6930,24 +7007,6 @@ var ForwardPath = class extends generic_calculations_default {
|
|
|
6930
7007
|
isCurrent
|
|
6931
7008
|
});
|
|
6932
7009
|
}
|
|
6933
|
-
/**
|
|
6934
|
-
* Calculates the earliest start (ES) and earliest finish (EF) dates for a list of activities.
|
|
6935
|
-
*
|
|
6936
|
-
* This function processes each activity in the `activitiesToCalculate` list, retrieves the necessary
|
|
6937
|
-
* information, and calculates the ES and EF dates based on the activity's progress and constraint type.
|
|
6938
|
-
* It handles various constraints and updates the calculations accordingly.
|
|
6939
|
-
* It also do calculation according to the activities links
|
|
6940
|
-
*
|
|
6941
|
-
* @param {Array<string|number>} activitiesToCalculate - A list of activity IDs for which to calculate ES and EF dates.
|
|
6942
|
-
* @returns {void} This function does not return a value.
|
|
6943
|
-
*
|
|
6944
|
-
* @example
|
|
6945
|
-
* // Assuming activitiesToCalculate is an array containing activity IDs [1, 2, 3]
|
|
6946
|
-
* calculateStartAndFinishTimes([1, 2, 3]);
|
|
6947
|
-
* // This will calculate the ES and EF dates for the activities and update the internal calculations map.
|
|
6948
|
-
*
|
|
6949
|
-
* @throws {Error} If an error occurs during the process.
|
|
6950
|
-
*/
|
|
6951
7010
|
calculateStartAndFinishTimes(activitiesToCalculate) {
|
|
6952
7011
|
activitiesToCalculate.forEach((activity) => {
|
|
6953
7012
|
const activityReference = this.gantt.getTask(activity);
|
|
@@ -7068,13 +7127,6 @@ var ForwardPath = class extends generic_calculations_default {
|
|
|
7068
7127
|
this.activitiesWaitingForCalculation.delete(activity);
|
|
7069
7128
|
});
|
|
7070
7129
|
}
|
|
7071
|
-
/**
|
|
7072
|
-
* Gets the greatest date between a restriction and a link calculation.
|
|
7073
|
-
* @param {Object} restriction - The restriction object.
|
|
7074
|
-
* @param {Object} linkCalculation - The link calculation object.
|
|
7075
|
-
* @param {string} [comparisonType='greater'] - The type of comparison ('greater' or 'less').
|
|
7076
|
-
* @returns {Object} - The object with the greatest date.
|
|
7077
|
-
*/
|
|
7078
7130
|
getTheGreatesDateBetweenRestrictionAndEsEf(restriction, linkCalculation, comparisonType = "greater") {
|
|
7079
7131
|
if (comparisonType === "greater") {
|
|
7080
7132
|
return linkCalculation.ef > restriction.ef ? linkCalculation : restriction;
|
|
@@ -7083,34 +7135,18 @@ var ForwardPath = class extends generic_calculations_default {
|
|
|
7083
7135
|
return linkCalculation.ef < restriction.ef ? linkCalculation : restriction;
|
|
7084
7136
|
}
|
|
7085
7137
|
}
|
|
7086
|
-
/**
|
|
7087
|
-
* Set ES and EF dates for an activity with full progress.
|
|
7088
|
-
* @param {Object} activity - The activity object.
|
|
7089
|
-
*/
|
|
7090
7138
|
setDatesForActivityWithFullProgress(activity) {
|
|
7091
7139
|
this.calculations.set(activity.id, {
|
|
7092
7140
|
es: activity.start_date,
|
|
7093
7141
|
ef: activity.end_date
|
|
7094
7142
|
});
|
|
7095
7143
|
}
|
|
7096
|
-
/**
|
|
7097
|
-
* Calculates ES and EF dates for an activity with progress greater than zero.
|
|
7098
|
-
* @param {Object} activity - The activity object.
|
|
7099
|
-
* @returns {Object} - The calculated ES and EF dates.
|
|
7100
|
-
*/
|
|
7101
7144
|
getDatesForActivityWithZeroProgress(activity) {
|
|
7102
7145
|
return {
|
|
7103
7146
|
es: activity.start_date,
|
|
7104
7147
|
ef: activity.end_date
|
|
7105
7148
|
};
|
|
7106
7149
|
}
|
|
7107
|
-
/**
|
|
7108
|
-
* Recalculates ES and EF dates based on a constraint.
|
|
7109
|
-
* @param {string} constraintType - The type of constraint.
|
|
7110
|
-
* @param {Object} calculatedRestriction - The calculated restriction object.
|
|
7111
|
-
* @param {Object} calculatedEsEf - The calculated ES and EF object.
|
|
7112
|
-
* @returns {Object} - The recalculated ES and EF dates.
|
|
7113
|
-
*/
|
|
7114
7150
|
recalculateInBaseConstraint(constraintType, calculatedRestriction, calculatedEsEf) {
|
|
7115
7151
|
const comparisontype = [
|
|
7116
7152
|
CONSTRAINT_TYPES.SNET,
|
|
@@ -7150,30 +7186,12 @@ var CalculationsGenericMethods = class {
|
|
|
7150
7186
|
this.forwardPathCalculations = calculationObject.calculatedForwardActivitiesMap;
|
|
7151
7187
|
this.gantt = calculationObject.ganttInstance;
|
|
7152
7188
|
}
|
|
7153
|
-
/**
|
|
7154
|
-
* Retrieves the late start (LS) and late finish (lf) dates for a given activity from previously calculated activities.
|
|
7155
|
-
*
|
|
7156
|
-
* @param {string|number} activity - The ID of the activity for which to retrieve LS and lf dates.
|
|
7157
|
-
* @param {string} [constraint=null] - The constraint type to use for the calculation (e.g., 'alap').
|
|
7158
|
-
* @returns {Object|null} The LS and lf dates for the activity, or null if not found.
|
|
7159
|
-
* @throws {Error} If an error occurs during the retrieval process.
|
|
7160
|
-
*/
|
|
7161
7189
|
getForwardOrBackwardCalculations(activity, constraint = null) {
|
|
7162
7190
|
if (constraint === CONSTRAINT_TYPES.ALAP) {
|
|
7163
7191
|
return this.forwardPathCalculations.get(activity);
|
|
7164
7192
|
}
|
|
7165
7193
|
return this.calculatedActivities.get(activity);
|
|
7166
7194
|
}
|
|
7167
|
-
/**
|
|
7168
|
-
* Calculates the LS (Latest Start) and LF (Latest Finish) times for the successor activity.
|
|
7169
|
-
* @param {Date} successorTime - The time of the successor activity.
|
|
7170
|
-
* @param {number} lsDataCalculation - The duration for LS calculation.
|
|
7171
|
-
* @param {number} [lfDataCalculation=0] - The duration for LF calculation, default is 0.
|
|
7172
|
-
* @param {number} lag - The lag time.
|
|
7173
|
-
* @param {string} [type='FS'] - The type of link ('FS', 'FF', 'SS', 'SF'), default is 'FS'.
|
|
7174
|
-
* @returns {Object} Returns an object containing the LS and LF times for the successor activity.
|
|
7175
|
-
* @throws Will throw an error if there's an issue with the calculation.
|
|
7176
|
-
*/
|
|
7177
7195
|
calculateSuccessorTimes(sucessorTime, lsDataCalculation, lfDataCalculation = 0, lag, type = LINK_TYPES.FS) {
|
|
7178
7196
|
let activityCalendar = this.gantt.getCalendar(this.activity.calendar_id);
|
|
7179
7197
|
if (!activityCalendar) {
|
|
@@ -7223,13 +7241,6 @@ var CalculationsGenericMethods = class {
|
|
|
7223
7241
|
return { ls, lf };
|
|
7224
7242
|
}
|
|
7225
7243
|
}
|
|
7226
|
-
/**
|
|
7227
|
-
* Calculates the LS (Latest Start) and LF (Latest Finish) times for the successor activity in a SS (Start-to-Start) link.
|
|
7228
|
-
* @param {Object} link - The link object containing information about the relationship.
|
|
7229
|
-
* @param {boolean} [alap=false] - Indicates whether to calculate based on ALAP (As Late As Possible) constraint, default is false.
|
|
7230
|
-
* @returns {Object} Returns an object containing the calculated LS and LF times for the successor activity.
|
|
7231
|
-
* @throws Will throw an error if there's an issue with the calculation.
|
|
7232
|
-
*/
|
|
7233
7244
|
calculateSS(link, alap = false) {
|
|
7234
7245
|
let lsSuc = this.getValueForSS(link, alap);
|
|
7235
7246
|
let lsDataForCalculation = -link.lag || 0;
|
|
@@ -7243,12 +7254,6 @@ var CalculationsGenericMethods = class {
|
|
|
7243
7254
|
LINK_TYPES.SS
|
|
7244
7255
|
);
|
|
7245
7256
|
}
|
|
7246
|
-
/**
|
|
7247
|
-
* Calculates the LS (Latest Start) and LF (Latest Finish) times for the successor activity in a FF (Finish-to-Finish) link.
|
|
7248
|
-
* @param {Object} link - The link object containing information about the relationship.
|
|
7249
|
-
* @returns {Object} Returns an object containing the calculated LS and LF times for the successor activity.
|
|
7250
|
-
* @throws Will throw an error if there's an issue with the calculation.
|
|
7251
|
-
*/
|
|
7252
7257
|
calculateFF(link, constraint) {
|
|
7253
7258
|
const succesorDate = this.getForwardOrBackwardCalculations(
|
|
7254
7259
|
Number(link.target)
|
|
@@ -7266,13 +7271,6 @@ var CalculationsGenericMethods = class {
|
|
|
7266
7271
|
LINK_TYPES.FF
|
|
7267
7272
|
);
|
|
7268
7273
|
}
|
|
7269
|
-
/**
|
|
7270
|
-
* Calculates the LS (Latest Start) and LF (Latest Finish) times for the successor activity in a FS (Finish-to-Start) link.
|
|
7271
|
-
* @param {Object} link - The link object containing information about the relationship.
|
|
7272
|
-
* @param {string} constraint - The constraint type.
|
|
7273
|
-
* @returns {Object} Returns an object containing the calculated LS and LF times for the successor activity.
|
|
7274
|
-
* @throws Will throw an error if there's an issue with the calculation.
|
|
7275
|
-
*/
|
|
7276
7274
|
calculateFS(link, constraint) {
|
|
7277
7275
|
let propertyToCalculate = "ls";
|
|
7278
7276
|
propertyToCalculate = constraint === CONSTRAINT_TYPES.ALAP ? "es" : "ls";
|
|
@@ -7291,13 +7289,6 @@ var CalculationsGenericMethods = class {
|
|
|
7291
7289
|
LINK_TYPES.FS
|
|
7292
7290
|
);
|
|
7293
7291
|
}
|
|
7294
|
-
/**
|
|
7295
|
-
* Calculates the LS (Latest Start) and LF (Latest Finish) times for the successor activity in a SF (Start-to-Finish) link.
|
|
7296
|
-
* @param {Object} link - The link object containing information about the relationship.
|
|
7297
|
-
* @param {boolean} getFromForward - Whether to calculate LS using the early start from the forward path.
|
|
7298
|
-
* @returns {Object} Returns an object containing the calculated LS and LF times for the successor activity.
|
|
7299
|
-
* @throws Will throw an error if there's an issue with the calculation.
|
|
7300
|
-
*/
|
|
7301
7292
|
calculateSF(link, getFromForward = false) {
|
|
7302
7293
|
let lateFinishSucessor = getFromForward ? this.getEarlyStartFromForwardPath(Number(link.target)).ef : this.getForwardOrBackwardCalculations(Number(link.target)).lf;
|
|
7303
7294
|
let lsDataForCalculation = -link.lag || 0;
|
|
@@ -7311,19 +7302,9 @@ var CalculationsGenericMethods = class {
|
|
|
7311
7302
|
LINK_TYPES.SF
|
|
7312
7303
|
);
|
|
7313
7304
|
}
|
|
7314
|
-
/**
|
|
7315
|
-
* Retrieves the early start time from the forward path calculations for the current activity.
|
|
7316
|
-
* @returns {number} The early start time for the activity.
|
|
7317
|
-
*/
|
|
7318
7305
|
getEarlyStartFromForwardPath(link) {
|
|
7319
7306
|
return this.forwardPathCalculations.get(link);
|
|
7320
7307
|
}
|
|
7321
|
-
/**
|
|
7322
|
-
* Retrieves the value for the specified scheduling state (SS).
|
|
7323
|
-
* @param {object} link - The link object representing the dependency.
|
|
7324
|
-
* @param {boolean} alap - Flag indicating if the scheduling state is As Late As Possible (ALAP).
|
|
7325
|
-
* @returns {number} The value representing the specified scheduling state.
|
|
7326
|
-
*/
|
|
7327
7308
|
getValueForSS(link, alap) {
|
|
7328
7309
|
if (alap) {
|
|
7329
7310
|
return this.getEarlyStartFromForwardPath(Number(link.target)).es;
|
|
@@ -7332,13 +7313,6 @@ var CalculationsGenericMethods = class {
|
|
|
7332
7313
|
let sucessor = this.getForwardOrBackwardCalculations(Number(link.target));
|
|
7333
7314
|
return sucessor[propertyToCalculate];
|
|
7334
7315
|
}
|
|
7335
|
-
/**
|
|
7336
|
-
* Calculates the end date based on the provided activity calendar, starting date, and duration.
|
|
7337
|
-
* @param {object} activityCalendar - The calendar object containing activity scheduling information.
|
|
7338
|
-
* @param {Date} date - The starting date for the activity.
|
|
7339
|
-
* @param {number} duration - The duration of the activity in days.
|
|
7340
|
-
* @returns {Date} The end date of the activity.
|
|
7341
|
-
*/
|
|
7342
7316
|
calculateDate(activityCalendar, date2, duration) {
|
|
7343
7317
|
let resetedDate = moment_default(date2).clone();
|
|
7344
7318
|
return addDurationToDate(
|
|
@@ -7348,14 +7322,6 @@ var CalculationsGenericMethods = class {
|
|
|
7348
7322
|
this.activity
|
|
7349
7323
|
);
|
|
7350
7324
|
}
|
|
7351
|
-
/**
|
|
7352
|
-
* Retrieves the last working hour based on the provided date and activity calendar.
|
|
7353
|
-
* @param {Date} date - The date for which to find the last working hour.
|
|
7354
|
-
* @param {object} activityCalendar - The calendar object containing activity scheduling information.
|
|
7355
|
-
* @param {string} [dir='past'] - The direction in which to search for the last working hour. Default is 'past'.
|
|
7356
|
-
* @throws {Error} Throws an error if the provided date is not valid.
|
|
7357
|
-
* @returns {Date} The last working hour relative to the provided date.
|
|
7358
|
-
*/
|
|
7359
7325
|
getLastWorkingHour(date2, activityCalendar, dir = "past") {
|
|
7360
7326
|
const normalizedDate = date2 instanceof Date ? date2 : new Date(date2);
|
|
7361
7327
|
let resetedDate = moment_default(normalizedDate).clone();
|
|
@@ -7370,14 +7336,6 @@ var CalculationsGenericMethods = class {
|
|
|
7370
7336
|
});
|
|
7371
7337
|
return newDate;
|
|
7372
7338
|
}
|
|
7373
|
-
/**
|
|
7374
|
-
* Determines if a given date corresponds to the initial work hour of an activity as defined in the activity calendar.
|
|
7375
|
-
* This function retrieves the first work interval from the activity calendar and compares the hour portion
|
|
7376
|
-
* of the input date to the start hour of the work interval.
|
|
7377
|
-
* @param {object} activityCalendar - The calendar object containing work hours and scheduling information for the activity.
|
|
7378
|
-
* @param {Date} date - The date to check against the activity's start hour.
|
|
7379
|
-
* @returns {boolean} True if the hour of the input date matches the initial work hour of the activity; otherwise, false.
|
|
7380
|
-
*/
|
|
7381
7339
|
isActivityInInitHour(activityCalendar, date2) {
|
|
7382
7340
|
const normalizedDate = date2 instanceof Date ? date2 : new Date(date2);
|
|
7383
7341
|
const shifts = activityCalendar.getWorkHours(normalizedDate);
|
|
@@ -7396,17 +7354,6 @@ var CalculationsGenericMethods = class {
|
|
|
7396
7354
|
}
|
|
7397
7355
|
return normalizedDate.getUTCHours() === workStartHour;
|
|
7398
7356
|
}
|
|
7399
|
-
/**
|
|
7400
|
-
* Calculates the forward start (FS) and forward finish (FF) dates based on the provided parameters.
|
|
7401
|
-
* @param {object} options - An object containing the necessary parameters for the calculation.
|
|
7402
|
-
* @param {number} options.lag - The lag duration for the calculation.
|
|
7403
|
-
* @param {Date} options.workTime - The starting work time for the calculation.
|
|
7404
|
-
* @param {object} options.activityCalendar - The calendar object containing activity scheduling information.
|
|
7405
|
-
* @param {number} options.lsDataCalculation - The duration for calculating the forward start date.
|
|
7406
|
-
* @param {number} options.lfDataCalculation - The duration for calculating the forward finish date.
|
|
7407
|
-
* @param {boolean} [options.isMilestone=false] - Flag indicating if the activity is a milestone. Default is false.
|
|
7408
|
-
* @returns {object} An object containing the forward start (FS) and forward finish (FF) dates.
|
|
7409
|
-
*/
|
|
7410
7357
|
calculateFsLink({
|
|
7411
7358
|
lag,
|
|
7412
7359
|
workTime,
|
|
@@ -7459,16 +7406,6 @@ var CalculationsGenericMethods = class {
|
|
|
7459
7406
|
}
|
|
7460
7407
|
return { ls: lsPred, lf: lfPred };
|
|
7461
7408
|
}
|
|
7462
|
-
/**
|
|
7463
|
-
* Calculates the forward finish (FF) dates based on the provided parameters.
|
|
7464
|
-
* @param {object} options - An object containing the necessary parameters for the calculation.
|
|
7465
|
-
* @param {number} options.lag - The lag duration for the calculation.
|
|
7466
|
-
* @param {Date} options.workTime - The starting work time for the calculation.
|
|
7467
|
-
* @param {object} options.activityCalendar - The calendar object containing activity scheduling information.
|
|
7468
|
-
* @param {number} options.lsDataCalculation - The duration for calculating the forward start date.
|
|
7469
|
-
* @param {number} options.lfDataCalculation - The duration for calculating the forward finish date.
|
|
7470
|
-
* @returns {object} An object containing the forward start (FS) and forward finish (FF) dates.
|
|
7471
|
-
*/
|
|
7472
7409
|
calculateFFLink({
|
|
7473
7410
|
lag,
|
|
7474
7411
|
workTime,
|
|
@@ -7515,19 +7452,6 @@ var CalculationsGenericMethods = class {
|
|
|
7515
7452
|
);
|
|
7516
7453
|
return { ls: lsPred, lf: lfPred };
|
|
7517
7454
|
}
|
|
7518
|
-
/**
|
|
7519
|
-
* Calculates the start and finish times for an activity based on the specified lag and work time.
|
|
7520
|
-
* If the lag is zero, the function directly calculates the times using the provided work time.
|
|
7521
|
-
* If the lag is negative and the activity is not a milestone, it adjusts the work time based on future working hours.
|
|
7522
|
-
* @param {object} options - Configuration object containing parameters needed for the calculation.
|
|
7523
|
-
* @param {number} options.lay - The lag time affecting the start and finish calculations.
|
|
7524
|
-
* @param {Date} options.workTime - The reference time from which calculations begin.
|
|
7525
|
-
* @param {object} options.activityCalendar - The calendar used to check work hours and holidays.
|
|
7526
|
-
* @param {number} options.lsDataCalculation - Duration to calculate the start time from the reference point.
|
|
7527
|
-
* @param {number} options.lfDataCalculation - Duration to calculate the finish time from the calculated start time.
|
|
7528
|
-
* @param {boolean} [options.isMilestone=false] - Indicates whether the current activity is a milestone.
|
|
7529
|
-
* @returns {object} An object with properties `ls` (start time) and `lf` (finish time).
|
|
7530
|
-
*/
|
|
7531
7455
|
calculateSSlink({
|
|
7532
7456
|
lag,
|
|
7533
7457
|
workTime,
|
|
@@ -7575,17 +7499,6 @@ var CalculationsGenericMethods = class {
|
|
|
7575
7499
|
);
|
|
7576
7500
|
return { ls: lsPred, lf: lfPred };
|
|
7577
7501
|
}
|
|
7578
|
-
/**
|
|
7579
|
-
* Calculates the start (SF) and finish (LF) times for an activity based on the specified lag and work time.
|
|
7580
|
-
* This function handles both cases where lag is zero and when it's not, calculating times based on the given work time.
|
|
7581
|
-
* @param {object} options - Configuration object containing the necessary parameters for the calculation.
|
|
7582
|
-
* @param {number} options.lag - The lag time that influences the scheduling.
|
|
7583
|
-
* @param {Date} options.workBlock - The reference time from which scheduling starts.
|
|
7584
|
-
* @param {object} options.activityCalendar - The calendar object containing activity scheduling information.
|
|
7585
|
-
* @param {number} options.lsDataCalculation - The duration to calculate the start time.
|
|
7586
|
-
* @param {number} options.lfDataCalculation - The duration to calculate the finish time.
|
|
7587
|
-
* @returns {object} An object containing the start (ls) and finish (lf) times of the activity.
|
|
7588
|
-
*/
|
|
7589
7502
|
calculateSFLink({
|
|
7590
7503
|
lag,
|
|
7591
7504
|
workTime,
|
|
@@ -7632,23 +7545,6 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
|
|
|
7632
7545
|
this.parentsThatImpactChildrens = calculationObject.parentsThatImpactChildrens;
|
|
7633
7546
|
this.projectDates = this.gantt.getSubtaskDates();
|
|
7634
7547
|
}
|
|
7635
|
-
/**
|
|
7636
|
-
* Calculates the latest start (LS) and latest finish (LF) times for an activity.
|
|
7637
|
-
*
|
|
7638
|
-
* This function calculates the LS and LF times for an activity based on its progress and the links associated with it.
|
|
7639
|
-
* It takes into account various conditions and constraints to determine the final LS and LF times.
|
|
7640
|
-
*
|
|
7641
|
-
* @returns {Object} An object containing the calculated latest start (LS) and latest finish (LF) times.
|
|
7642
|
-
* @property {Date} ls - The calculated latest start time.
|
|
7643
|
-
* @property {Date} lf - The calculated latest finish time.
|
|
7644
|
-
*
|
|
7645
|
-
* @example
|
|
7646
|
-
* // Assuming this function is part of a class with access to the required properties and methods
|
|
7647
|
-
* const result = calculate();
|
|
7648
|
-
// { ls: Date, lf: Date }
|
|
7649
|
-
*
|
|
7650
|
-
* @throws {Error} If an error occurs during the calculation process.
|
|
7651
|
-
*/
|
|
7652
7548
|
calculate() {
|
|
7653
7549
|
if (this.links.length === 0) {
|
|
7654
7550
|
return new generic_calculations_default(
|
|
@@ -7725,11 +7621,6 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
|
|
|
7725
7621
|
minFromLinks: calculation
|
|
7726
7622
|
};
|
|
7727
7623
|
}
|
|
7728
|
-
/**
|
|
7729
|
-
* Calculates the Late Start (LS) and Late Finish (LF) for the current activity.
|
|
7730
|
-
* @returns {Object} An object containing the Late Start (LS) and Late Finish (LF) dates.
|
|
7731
|
-
* @throws {Error} If there's an issue with retrieving the calendar or calculating the dates.
|
|
7732
|
-
*/
|
|
7733
7624
|
calculateTheLsAndLfForTheActivity(parentDates = null) {
|
|
7734
7625
|
try {
|
|
7735
7626
|
const duration = this.activity.duration;
|
|
@@ -7756,12 +7647,6 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
|
|
|
7756
7647
|
throw Error(error.message);
|
|
7757
7648
|
}
|
|
7758
7649
|
}
|
|
7759
|
-
/**
|
|
7760
|
-
* Calculates the minimum between the minimum date from links and the end date of the project
|
|
7761
|
-
* or the end date of the activity, depending on the constraint type.
|
|
7762
|
-
* @param {Object} minCalculatedDateFromLinks - The minimum calculated date from links.
|
|
7763
|
-
* @returns {Date} The minimum date between the calculated date from links and the end date.
|
|
7764
|
-
*/
|
|
7765
7650
|
SnetSnltMsoMinDate(minCalculatedDateFromLinks) {
|
|
7766
7651
|
const minDateOfEndOfProjectAndLinks = Math.min(
|
|
7767
7652
|
minCalculatedDateFromLinks.lf,
|
|
@@ -7771,12 +7656,6 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
|
|
|
7771
7656
|
Math.max(minDateOfEndOfProjectAndLinks, this.activity.end_date)
|
|
7772
7657
|
);
|
|
7773
7658
|
}
|
|
7774
|
-
/**
|
|
7775
|
-
* Calculates the successor and/or predecessor times based on the link type and constraints.
|
|
7776
|
-
* @param {Object} linkData - The link data object containing information about the link.
|
|
7777
|
-
* @returns {void} Returns nothing if the calculation is avoided based on the progress of the target activity.
|
|
7778
|
-
* @throws {Error} Throws an error if activity data is not found or if an error occurs during calculation.
|
|
7779
|
-
*/
|
|
7780
7659
|
calculateLink(linkData) {
|
|
7781
7660
|
const activityFromLink = this.gantt.getTask(linkData.target);
|
|
7782
7661
|
if (!activityFromLink) {
|
|
@@ -7796,29 +7675,17 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
|
|
|
7796
7675
|
};
|
|
7797
7676
|
return calculationMapping[linkData.type]();
|
|
7798
7677
|
}
|
|
7799
|
-
/**
|
|
7800
|
-
* Determines the special calculation parameter based on the constraint type.
|
|
7801
|
-
* @returns {string|undefined} Returns a special parameter for specific constraint types, or undefined if no special parameter is needed.
|
|
7802
|
-
*/
|
|
7803
7678
|
getSpecialCalculationParamForConstraintLink() {
|
|
7804
7679
|
if (this.constraint === CONSTRAINT_TYPES.ALAP) return CONSTRAINT_TYPES.ALAP;
|
|
7805
7680
|
if (this.constraint === CONSTRAINT_TYPES.FNET || this.constraint === CONSTRAINT_TYPES.SNET)
|
|
7806
7681
|
return "snet-fnet";
|
|
7807
7682
|
if (this.constraint === CONSTRAINT_TYPES.FNLT) return CONSTRAINT_TYPES.FNLT;
|
|
7808
7683
|
}
|
|
7809
|
-
/**
|
|
7810
|
-
* Determines the special calculation parameter based on the constraint type.
|
|
7811
|
-
* @returns {string|undefined} Returns a special parameter for specific constraint types, or undefined if no special parameter is needed.
|
|
7812
|
-
*/
|
|
7813
7684
|
getSpecialParamForSf() {
|
|
7814
7685
|
const constriantThatNeedSpecialParam = [CONSTRAINT_TYPES.ALAP];
|
|
7815
7686
|
if (constriantThatNeedSpecialParam.includes(this.constraint)) return true;
|
|
7816
7687
|
return false;
|
|
7817
7688
|
}
|
|
7818
|
-
/**
|
|
7819
|
-
* Determines the special calculation parameter based on the constraint type.
|
|
7820
|
-
* @returns {string|undefined} Returns a special parameter for specific constraint types, or undefined if no special parameter is needed.
|
|
7821
|
-
*/
|
|
7822
7689
|
getSpecialParamForFF() {
|
|
7823
7690
|
const constraintsThatNeedSpecialFFParam = [
|
|
7824
7691
|
CONSTRAINT_TYPES.MFO,
|
|
@@ -7828,11 +7695,6 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
|
|
|
7828
7695
|
return true;
|
|
7829
7696
|
return false;
|
|
7830
7697
|
}
|
|
7831
|
-
/**
|
|
7832
|
-
* Determines the minimum calculation logic based on the constraint type.
|
|
7833
|
-
* @param {Object} minCalculateFromLinks - The minimum calculation data from links.
|
|
7834
|
-
* @returns {Date} Returns the minimum calculation date based on the constraint type.
|
|
7835
|
-
*/
|
|
7836
7698
|
getMinCalculationLogic(minCalculateFromLinks) {
|
|
7837
7699
|
if (this.constraint === CONSTRAINT_TYPES.ALAP) {
|
|
7838
7700
|
return this.getMinDateBasedOnConstraint(minCalculateFromLinks);
|
|
@@ -7853,11 +7715,6 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
|
|
|
7853
7715
|
return this.getMinDateBasedOnConstraint(minCalculateFromLinks);
|
|
7854
7716
|
}
|
|
7855
7717
|
}
|
|
7856
|
-
/**
|
|
7857
|
-
* Calculates the minimum date from the list of link calculations based on the constraint type.
|
|
7858
|
-
* @param {Array} allLinksCalculations - The list of all link calculations.
|
|
7859
|
-
* @returns {Object} Returns the minimum date from the link calculations.
|
|
7860
|
-
*/
|
|
7861
7718
|
getMinDateFromLinks(allLinksCalculations) {
|
|
7862
7719
|
try {
|
|
7863
7720
|
if (this.constraint === CONSTRAINT_TYPES.ALAP || this.constraint === CONSTRAINT_TYPES.ASAP) {
|
|
@@ -7880,16 +7737,6 @@ var LinksConstraintCalculator2 = class extends CalculationsGenericMethods_defaul
|
|
|
7880
7737
|
(min, activity) => activity.lf < min.lf ? activity : min
|
|
7881
7738
|
);
|
|
7882
7739
|
}
|
|
7883
|
-
/**
|
|
7884
|
-
* Gets the minimum date between the links' minimum date and the end of the project based on the constraint type.
|
|
7885
|
-
*
|
|
7886
|
-
* @param {Object} minCalculatedDateFromLinks - The minimum calculated date from links.
|
|
7887
|
-
* @param {Date} minCalculatedDateFromLinks.lf - The latest finish date from links.
|
|
7888
|
-
* @param {string} constraintType - The constraint type of the activity.
|
|
7889
|
-
* @returns {Date} The calculated minimum date based on the constraint type.
|
|
7890
|
-
*
|
|
7891
|
-
* @throws {Error} If an error occurs during the calculation process.
|
|
7892
|
-
*/
|
|
7893
7740
|
getMinDateBasedOnConstraint(minCalculatedDateFromLinks, constraintType = this.constraint) {
|
|
7894
7741
|
const minDateOfEndOfProjectAndLinks = Math.min(
|
|
7895
7742
|
minCalculatedDateFromLinks.lf,
|
|
@@ -8040,23 +7887,6 @@ var BackwardPath = class extends generic_calculations_default {
|
|
|
8040
7887
|
lf: maxLf
|
|
8041
7888
|
});
|
|
8042
7889
|
}
|
|
8043
|
-
/**
|
|
8044
|
-
* Calculates the latest start (LS) and latest finish (LF) times for a list of activities.
|
|
8045
|
-
*
|
|
8046
|
-
* This function processes each activity in the `activitiesToCalculate` list, retrieves the necessary
|
|
8047
|
-
* information, and calculates the LS and LF times based on the activity's progress and constraint type.
|
|
8048
|
-
* It handles various constraints and updates the calculations accordingly.
|
|
8049
|
-
*
|
|
8050
|
-
* @param {Array<string|number>} activitiesToCalculate - A list of activity IDs for which to calculate LS and LF times.
|
|
8051
|
-
* @returns {void} This function does not return a value.
|
|
8052
|
-
*
|
|
8053
|
-
* @example
|
|
8054
|
-
* // Assuming activitiesToCalculate is an array containing activity IDs [1, 2, 3]
|
|
8055
|
-
* calculateStartAndFinishTimes([1, 2, 3]);
|
|
8056
|
-
* // This will calculate the LS and LF times for the activities and update the internal calculations map.
|
|
8057
|
-
*
|
|
8058
|
-
* @throws {Error} If an error occurs during the process.
|
|
8059
|
-
*/
|
|
8060
7890
|
calculateStartAndFinishTimes(activitiesToCalculate) {
|
|
8061
7891
|
activitiesToCalculate.forEach((activityId) => {
|
|
8062
7892
|
let activityReference = this.gantt.getTask(activityId);
|
|
@@ -8134,29 +7964,6 @@ var BackwardPath = class extends generic_calculations_default {
|
|
|
8134
7964
|
});
|
|
8135
7965
|
});
|
|
8136
7966
|
}
|
|
8137
|
-
/**
|
|
8138
|
-
* Determines the least late time for an activity based on ES and EF constraints.
|
|
8139
|
-
*
|
|
8140
|
-
* This function compares the latest finish (LF) time from links with the earliest finish (EF) constraint
|
|
8141
|
-
* for the activity. If the LF from links is less than the EF constraint, it returns the LF from links.
|
|
8142
|
-
* Otherwise, it returns the ES and EF constraints.
|
|
8143
|
-
*
|
|
8144
|
-
* @param {string|number} activity - The ID of the activity.
|
|
8145
|
-
* @param {Object} lfFromLinks - An object containing LS (latest start) and LF (latest finish) times from links.
|
|
8146
|
-
* @param {Date} lfFromLinks.ls - The latest start time from links.
|
|
8147
|
-
* @param {Date} lfFromLinks.lf - The latest finish time from links.
|
|
8148
|
-
* @returns {Object} An object containing the least late LS and LF times.
|
|
8149
|
-
* @property {Date} ls - The least late latest start time.
|
|
8150
|
-
* @property {Date} lf - The least late latest finish time.
|
|
8151
|
-
*
|
|
8152
|
-
* @example
|
|
8153
|
-
* // Assuming forwardConstraintsMap contains the ES and EF constraints for the activity
|
|
8154
|
-
* const result = getTheLessLateInBasEsEfConstraint(1, { ls: new Date(), lf: new Date() });
|
|
8155
|
-
* console.log()
|
|
8156
|
-
// { ls: Date, lf: Date }
|
|
8157
|
-
*
|
|
8158
|
-
* @throws {Error} If an error occurs during the process.
|
|
8159
|
-
*/
|
|
8160
7967
|
getTheLessLateInBasEsEfConstraint(activity, lfFromLinks, constraintType) {
|
|
8161
7968
|
let esEfFromConstraint = this.forwardConstraintsMap.get(activity);
|
|
8162
7969
|
if (!esEfFromConstraint) {
|
|
@@ -8175,23 +7982,6 @@ var BackwardPath = class extends generic_calculations_default {
|
|
|
8175
7982
|
}
|
|
8176
7983
|
return { ls: esEfFromConstraint.es, lf: esEfFromConstraint.ef };
|
|
8177
7984
|
}
|
|
8178
|
-
/**
|
|
8179
|
-
* Checks whether all activities linked to the given set of activities have progress greater than 0.
|
|
8180
|
-
*
|
|
8181
|
-
* This function iterates over the linked activities, retrieves their data, and checks if all of them have progress greater than 0.
|
|
8182
|
-
* If any linked activity has 0 progress, the function returns false. If all linked activities have progress, it returns true.
|
|
8183
|
-
*
|
|
8184
|
-
* @param {Array<string|number>} linkedActivities - An array of linked activity IDs.
|
|
8185
|
-
* @returns {boolean} True if all linked activities have progress greater than 0, otherwise false.
|
|
8186
|
-
*
|
|
8187
|
-
* @example
|
|
8188
|
-
* // Assuming linkedActivities is an array containing linked activity IDs [1, 2, 3]
|
|
8189
|
-
* const allHaveProgress = allLinkedActivitiesHasProgress([1, 2, 3]);
|
|
8190
|
-
* console.log()
|
|
8191
|
-
// true or false based on the progress of the linked activities
|
|
8192
|
-
*
|
|
8193
|
-
* @throws {Error} If an error occurs during the process, such as missing link data or activity data.
|
|
8194
|
-
*/
|
|
8195
7985
|
allLinkedActivitiesHasProgress(linkedActivities) {
|
|
8196
7986
|
try {
|
|
8197
7987
|
let allLinkedHasProgress = true;
|
|
@@ -8216,46 +8006,9 @@ var BackwardPath = class extends generic_calculations_default {
|
|
|
8216
8006
|
throw new Error(error.message);
|
|
8217
8007
|
}
|
|
8218
8008
|
}
|
|
8219
|
-
/**
|
|
8220
|
-
* Sets the calculations for an activity that has 100% progress.
|
|
8221
|
-
*
|
|
8222
|
-
* This function uses the activity's start and end dates to set the calculations for the activity.
|
|
8223
|
-
* It is assumed that the activity has 100% progress.
|
|
8224
|
-
*
|
|
8225
|
-
* @param {Object} activity - The activity object containing the details of the activity.
|
|
8226
|
-
* @param {Date} activity.start_date - The start date of the activity.
|
|
8227
|
-
* @param {Date} activity.end_date - The end date of the activity.
|
|
8228
|
-
* @returns {void} This function does not return a value.
|
|
8229
|
-
*
|
|
8230
|
-
* @example
|
|
8231
|
-
* // Assuming activity is an object with start_date and end_date properties
|
|
8232
|
-
* setDatesForActivityWithFullProgress({
|
|
8233
|
-
* start_date: new Date('2023-01-01'),
|
|
8234
|
-
* end_date: new Date('2023-01-10')
|
|
8235
|
-
* });
|
|
8236
|
-
* // This will set the calculations for the activity using its start and end dates.
|
|
8237
|
-
*
|
|
8238
|
-
* @throws {Error} If an error occurs during the calculation process.
|
|
8239
|
-
*/
|
|
8240
8009
|
setDatesForActivityWithFullProgress(activity) {
|
|
8241
8010
|
this.setCalculations(activity, activity.start_date, activity.end_date);
|
|
8242
8011
|
}
|
|
8243
|
-
/**
|
|
8244
|
-
* Sets the calculations for an activity when all its linked activities have progress.
|
|
8245
|
-
*
|
|
8246
|
-
* This function calculates the latest start (LS) and latest finish (LF) times for the activity using a backward direction,
|
|
8247
|
-
* and sets these values in the internal calculations.
|
|
8248
|
-
*
|
|
8249
|
-
* @param {Object} activity - The activity object containing the details of the activity.
|
|
8250
|
-
* @returns {void} This function does not return a value.
|
|
8251
|
-
*
|
|
8252
|
-
* @example
|
|
8253
|
-
* // Assuming activity is an object with necessary properties for calculation
|
|
8254
|
-
* setWhenAllLinkedActivitiesHasProgress(activity);
|
|
8255
|
-
* // This will calculate LS and LF for the activity and set these values in the internal calculations.
|
|
8256
|
-
*
|
|
8257
|
-
* @throws {Error} If an error occurs during the calculation process.
|
|
8258
|
-
*/
|
|
8259
8012
|
setWhenAllLinkedActivitiesHasProgress(activity) {
|
|
8260
8013
|
const parent = Number(activity.parent);
|
|
8261
8014
|
let { ls, lf } = this.calculateStartAndFinishOfChainOrigin(
|
|
@@ -8272,23 +8025,6 @@ var BackwardPath = class extends generic_calculations_default {
|
|
|
8272
8025
|
this.setCalculations(activity, ls, lf);
|
|
8273
8026
|
return;
|
|
8274
8027
|
}
|
|
8275
|
-
/**
|
|
8276
|
-
* Sets the calculations for an activity with progress greater than 0% but less than 100%.
|
|
8277
|
-
*
|
|
8278
|
-
* This function handles activities based on their constraint type when the progress is between 0% and 100%.
|
|
8279
|
-
* It sets the calculations accordingly using the activity's start and end dates, or the constraint dates.
|
|
8280
|
-
*
|
|
8281
|
-
* @param {Object} activity - The activity object containing the details of the activity.
|
|
8282
|
-
* @param {string} constraintType - The constraint type of the activity, such as 'mso' or 'mfo'.
|
|
8283
|
-
* @returns {void} This function does not return a value.
|
|
8284
|
-
*
|
|
8285
|
-
* @example
|
|
8286
|
-
* // Assuming activity is an object with start_date, end_date, and constraint_date properties, and constraintType is 'mso'
|
|
8287
|
-
* setWhenActivitiesHasProgressButLessThanOneHundred(activity, 'mso');
|
|
8288
|
-
* // This will set the calculations for the activity using its start and end dates.
|
|
8289
|
-
*
|
|
8290
|
-
* @throws {Error} If an error occurs during the calculation process.
|
|
8291
|
-
*/
|
|
8292
8028
|
setWhenActivitiesHasProgressButLessThanOneHundred(activity, constraintType) {
|
|
8293
8029
|
if (constraintType === CONSTRAINT_TYPES.MSO) {
|
|
8294
8030
|
this.setCalculations(activity, activity.start_date, activity.end_date);
|
|
@@ -8304,24 +8040,6 @@ var BackwardPath = class extends generic_calculations_default {
|
|
|
8304
8040
|
return;
|
|
8305
8041
|
}
|
|
8306
8042
|
}
|
|
8307
|
-
/**
|
|
8308
|
-
* Sets the latest start (LS) and latest finish (LF) times for a given activity in the internal calculations map.
|
|
8309
|
-
*
|
|
8310
|
-
* This function stores the LS and LF times, along with the activity's text, in the internal `calculations` map
|
|
8311
|
-
* using the activity's ID as the key.
|
|
8312
|
-
*
|
|
8313
|
-
* @param {Object} activity - The activity object containing the details of the activity.
|
|
8314
|
-
* @param {Date} ls - The latest start time for the activity.
|
|
8315
|
-
* @param {Date} lf - The latest finish time for the activity.
|
|
8316
|
-
* @returns {void} This function does not return a value.
|
|
8317
|
-
*
|
|
8318
|
-
* @example
|
|
8319
|
-
* // Assuming activity is an object with id and text properties, and ls and lf are Date objects
|
|
8320
|
-
* setCalculations(activity, new Date('2023-01-01'), new Date('2023-01-10'));
|
|
8321
|
-
* // This will store the LS and LF times in the calculations map for the given activity.
|
|
8322
|
-
*
|
|
8323
|
-
* @throws {Error} If an error occurs during the calculation process.
|
|
8324
|
-
*/
|
|
8325
8043
|
setCalculations(activity, ls, lf) {
|
|
8326
8044
|
this.calculations.set(activity.id, {
|
|
8327
8045
|
ls,
|
|
@@ -8329,28 +8047,6 @@ var BackwardPath = class extends generic_calculations_default {
|
|
|
8329
8047
|
text: activity.text
|
|
8330
8048
|
});
|
|
8331
8049
|
}
|
|
8332
|
-
/**
|
|
8333
|
-
* Calculates the latest start (LS) and latest finish (LF) times for an activity based on its links with successors and the given constraint type.
|
|
8334
|
-
*
|
|
8335
|
-
* This function creates a new instance of the `LinksConstraintCalculator` class with the provided parameters and calls its `calculate` method
|
|
8336
|
-
* to determine the LS and LF times for the activity.
|
|
8337
|
-
*
|
|
8338
|
-
* @param {Array<string|number>} linksWithSucessors - An array of links to successor activities.
|
|
8339
|
-
* @param {Object} activityReference - The activity object for which to calculate LS and LF times.
|
|
8340
|
-
* @param {string} constraintType - The constraint type of the activity.
|
|
8341
|
-
* @returns {Object} An object containing the calculated latest start (LS) and latest finish (LF) times.
|
|
8342
|
-
* @property {Date} ls - The calculated latest start time.
|
|
8343
|
-
* @property {Date} lf - The calculated latest finish time.
|
|
8344
|
-
*
|
|
8345
|
-
* @example
|
|
8346
|
-
* // Assuming linksWithSucessors is an array of link IDs, activityReference is an activity object,
|
|
8347
|
-
* // and constraintType is a string representing the constraint type
|
|
8348
|
-
* const result = calculateLfandLsFromLinks([1, 2, 3], activityReference, 'mso');
|
|
8349
|
-
* console.log()
|
|
8350
|
-
// { ls: Date, lf: Date }
|
|
8351
|
-
*
|
|
8352
|
-
* @throws {Error} If an error occurs during the calculation process.
|
|
8353
|
-
*/
|
|
8354
8050
|
calculateLfandLsFromLinks(linksWithSucessors, activityReference, constraintType, parentsWithFullProgress, parentsThatImpactChildrens) {
|
|
8355
8051
|
return new LinksConstraintCalculator_default({
|
|
8356
8052
|
links: linksWithSucessors,
|
|
@@ -8363,23 +8059,6 @@ var BackwardPath = class extends generic_calculations_default {
|
|
|
8363
8059
|
ganttInstance: this.gantt
|
|
8364
8060
|
}).calculate();
|
|
8365
8061
|
}
|
|
8366
|
-
/**
|
|
8367
|
-
* Recalculates the latest start (LS) and latest finish (LF) times for an activity based on its constraint type.
|
|
8368
|
-
*
|
|
8369
|
-
* This function fetches the activity's calendar, calculates the restriction based on the constraint type,
|
|
8370
|
-
* updates the constraint map, and sets the new calculations for the activity.
|
|
8371
|
-
*
|
|
8372
|
-
* @param {Object} activity - The activity object containing the details of the activity.
|
|
8373
|
-
* @param {string} constraintType - The constraint type of the activity.
|
|
8374
|
-
* @returns {void} This function does not return a value.
|
|
8375
|
-
*
|
|
8376
|
-
* @example
|
|
8377
|
-
* // Assuming activity is an object with calendar_id property, and constraintType is 'mso'
|
|
8378
|
-
* recalculateInBaseRestriction(activity, 'mso');
|
|
8379
|
-
* // This will recalculate the LS and LF times for the activity based on the constraint type and update the internal calculations.
|
|
8380
|
-
*
|
|
8381
|
-
* @throws {Error} If an error occurs during the calculation process, such as missing calendar data.
|
|
8382
|
-
*/
|
|
8383
8062
|
recalculateInBaseRestriction(activity, constraintType) {
|
|
8384
8063
|
try {
|
|
8385
8064
|
const activityCalendar = this.gantt.getCalendar(activity.calendar_id);
|
|
@@ -9427,6 +9106,8 @@ var NON_SCHEDULING_KINDS = /* @__PURE__ */ new Set([
|
|
|
9427
9106
|
"selection-toggle",
|
|
9428
9107
|
"selection-replace",
|
|
9429
9108
|
"visibility-set",
|
|
9109
|
+
"filter-set",
|
|
9110
|
+
"sort-set",
|
|
9430
9111
|
"sir-sync",
|
|
9431
9112
|
"activity-lookahead-sync",
|
|
9432
9113
|
"persistence-acknowledge",
|
|
@@ -9434,6 +9115,16 @@ var NON_SCHEDULING_KINDS = /* @__PURE__ */ new Set([
|
|
|
9434
9115
|
"ponderator-criterion-set",
|
|
9435
9116
|
"status-criteria-set"
|
|
9436
9117
|
]);
|
|
9118
|
+
var PURE_VIEW_STATE_KINDS = /* @__PURE__ */ new Set([
|
|
9119
|
+
"selection-toggle",
|
|
9120
|
+
"selection-replace",
|
|
9121
|
+
"visibility-set",
|
|
9122
|
+
"filter-set",
|
|
9123
|
+
"sort-set"
|
|
9124
|
+
]);
|
|
9125
|
+
function reappliesViewState(action) {
|
|
9126
|
+
return !PURE_VIEW_STATE_KINDS.has(action.kind);
|
|
9127
|
+
}
|
|
9437
9128
|
var NO_STRUCTURAL_EXEMPTIONS = /* @__PURE__ */ new Set();
|
|
9438
9129
|
function editsOnlyNonSchedulingColumns(action) {
|
|
9439
9130
|
if (action.kind === "inline-edit") {
|
|
@@ -9742,7 +9433,7 @@ function detectSirAutoReject(beforeSnap, adapter, touchedIds) {
|
|
|
9742
9433
|
}
|
|
9743
9434
|
|
|
9744
9435
|
// src/dispatch/shared/change-set.ts
|
|
9745
|
-
function assembleChangeSet(adapter, args) {
|
|
9436
|
+
async function assembleChangeSet(adapter, args) {
|
|
9746
9437
|
const allTouched = collectChangeSetIds(adapter, args);
|
|
9747
9438
|
const before = new Map(args.beforeSnap);
|
|
9748
9439
|
const captured = adapter.peekWriteCapture();
|
|
@@ -9751,7 +9442,16 @@ function assembleChangeSet(adapter, args) {
|
|
|
9751
9442
|
mergeDirtyBeforeImages(adapter, captured, insertedIds, before, allTouched);
|
|
9752
9443
|
}
|
|
9753
9444
|
const beforeDiffEffects = args.sirDetection === "before-diff" ? detectSirAutoReject(before, adapter, allTouched) : [];
|
|
9754
|
-
const
|
|
9445
|
+
const correlativeBefore = buildCorrelativeBeforeMap(
|
|
9446
|
+
args.correlativeShifts,
|
|
9447
|
+
allTouched
|
|
9448
|
+
);
|
|
9449
|
+
const activityChanges = await buildActivityChanges(
|
|
9450
|
+
adapter,
|
|
9451
|
+
before,
|
|
9452
|
+
allTouched,
|
|
9453
|
+
correlativeBefore
|
|
9454
|
+
);
|
|
9755
9455
|
const effects = args.sirDetection === "after-diff" ? detectSirAutoReject(before, adapter, allTouched) : beforeDiffEffects;
|
|
9756
9456
|
const warnings = args.warnings ?? [];
|
|
9757
9457
|
return {
|
|
@@ -9759,12 +9459,20 @@ function assembleChangeSet(adapter, args) {
|
|
|
9759
9459
|
activities: activityChanges,
|
|
9760
9460
|
links: args.links ?? [],
|
|
9761
9461
|
calendars: [],
|
|
9762
|
-
// dispatch never mutates calendars
|
|
9763
9462
|
trackingEvents: args.trackingEvents ?? [],
|
|
9764
9463
|
...effects.length > 0 ? { effects } : {},
|
|
9765
9464
|
...warnings.length > 0 ? { warnings } : {}
|
|
9766
9465
|
};
|
|
9767
9466
|
}
|
|
9467
|
+
function buildCorrelativeBeforeMap(shifts, touched) {
|
|
9468
|
+
if (!shifts || shifts.length === 0) return void 0;
|
|
9469
|
+
const correlativeBefore = /* @__PURE__ */ new Map();
|
|
9470
|
+
for (const shift of shifts) {
|
|
9471
|
+
correlativeBefore.set(shift.activityId, shift.before);
|
|
9472
|
+
touched.add(shift.activityId);
|
|
9473
|
+
}
|
|
9474
|
+
return correlativeBefore;
|
|
9475
|
+
}
|
|
9768
9476
|
function collectChangeSetIds(adapter, args) {
|
|
9769
9477
|
const ids = /* @__PURE__ */ new Set();
|
|
9770
9478
|
for (const id of args.touchedIds) ids.add(id);
|
|
@@ -9962,7 +9670,7 @@ async function dispatchInlineEdit(action, options, deps) {
|
|
|
9962
9670
|
parsed2.raw
|
|
9963
9671
|
);
|
|
9964
9672
|
const touchedIds = collectTouchedIds(action.activityId, changes);
|
|
9965
|
-
const beforeSnap = snapshotActivities(adapter, touchedIds);
|
|
9673
|
+
const beforeSnap = await snapshotActivities(adapter, touchedIds);
|
|
9966
9674
|
const beforeLinkLags = snapshotIncomingLinkLags(
|
|
9967
9675
|
adapter,
|
|
9968
9676
|
String(action.activityId)
|
|
@@ -10034,7 +9742,7 @@ async function dispatchInlineEdit(action, options, deps) {
|
|
|
10034
9742
|
);
|
|
10035
9743
|
return {
|
|
10036
9744
|
ok: true,
|
|
10037
|
-
changes: assembleChangeSet(adapter, {
|
|
9745
|
+
changes: await assembleChangeSet(adapter, {
|
|
10038
9746
|
source: action,
|
|
10039
9747
|
beforeSnap,
|
|
10040
9748
|
touchedIds,
|
|
@@ -10144,7 +9852,10 @@ async function dispatchLinkBatch(operations, source, options, deps, deterministi
|
|
|
10144
9852
|
const { adapter, scheduler, sector, linkIdGen } = deps;
|
|
10145
9853
|
scheduler.invalidateAllCaches();
|
|
10146
9854
|
const { activityIds: affectedActivityIds, links: beforeLinks } = collectBatchContext(operations, adapter);
|
|
10147
|
-
const beforeActivities = snapshotActivities(
|
|
9855
|
+
const beforeActivities = await snapshotActivities(
|
|
9856
|
+
adapter,
|
|
9857
|
+
affectedActivityIds
|
|
9858
|
+
);
|
|
10148
9859
|
const applied = applyBatchOperations(
|
|
10149
9860
|
operations,
|
|
10150
9861
|
adapter,
|
|
@@ -10187,7 +9898,7 @@ async function dispatchLinkBatch(operations, source, options, deps, deterministi
|
|
|
10187
9898
|
}
|
|
10188
9899
|
),
|
|
10189
9900
|
__beforeLinks: stringKeyedLinkSnapshots(beforeLinks),
|
|
10190
|
-
changes: assembleChangeSet(adapter, {
|
|
9901
|
+
changes: await assembleChangeSet(adapter, {
|
|
10191
9902
|
source,
|
|
10192
9903
|
beforeSnap: beforeActivities,
|
|
10193
9904
|
touchedIds: affectedActivityIds,
|
|
@@ -10283,85 +9994,6 @@ var DISPATCH_TRACK_EVENT = {
|
|
|
10283
9994
|
ACTIVITY_OUTDENT: "schedule_activity_outdent"
|
|
10284
9995
|
};
|
|
10285
9996
|
|
|
10286
|
-
// src/internal/hierarchy/visual-order.ts
|
|
10287
|
-
var NOT_SET_SORT_VALUE = Number.MAX_SAFE_INTEGER;
|
|
10288
|
-
function getChildrenInVisualOrder(parentId, adapter) {
|
|
10289
|
-
const children = collectChildrenSnapshots(parentId, adapter);
|
|
10290
|
-
children.sort(compareActivitiesInVisualOrder);
|
|
10291
|
-
return children.map((a) => String(a.id));
|
|
10292
|
-
}
|
|
10293
|
-
function iterateInVisualOrder(adapter) {
|
|
10294
|
-
const result = [];
|
|
10295
|
-
const visit = (activity) => {
|
|
10296
|
-
result.push(activity);
|
|
10297
|
-
const childIds = getChildrenInVisualOrder(String(activity.id), adapter);
|
|
10298
|
-
for (const childId of childIds) {
|
|
10299
|
-
const child = adapter.getActivity(childId);
|
|
10300
|
-
if (child) visit(child);
|
|
10301
|
-
}
|
|
10302
|
-
};
|
|
10303
|
-
const rootIds = getChildrenInVisualOrder(ROOT_PARENT_ID, adapter);
|
|
10304
|
-
for (const rootId of rootIds) {
|
|
10305
|
-
const root = adapter.getActivity(rootId);
|
|
10306
|
-
if (root) visit(root);
|
|
10307
|
-
}
|
|
10308
|
-
return result;
|
|
10309
|
-
}
|
|
10310
|
-
function findPreviousNonSelectedSibling(taskId, selected, adapter) {
|
|
10311
|
-
const activity = adapter.getActivity(taskId);
|
|
10312
|
-
if (!activity) return null;
|
|
10313
|
-
const parentKey = parentKeyOf(activity);
|
|
10314
|
-
const siblings = getChildrenInVisualOrder(parentKey, adapter);
|
|
10315
|
-
const idx = siblings.findIndex((id) => String(id) === String(taskId));
|
|
10316
|
-
if (idx <= 0) return null;
|
|
10317
|
-
for (let i = idx - 1; i >= 0; i--) {
|
|
10318
|
-
const candidateId = siblings[i];
|
|
10319
|
-
if (candidateId === void 0) continue;
|
|
10320
|
-
if (!setHas(selected, candidateId)) return candidateId;
|
|
10321
|
-
}
|
|
10322
|
-
return null;
|
|
10323
|
-
}
|
|
10324
|
-
function visualIndexInParent(taskId, adapter) {
|
|
10325
|
-
const activity = adapter.getActivity(taskId);
|
|
10326
|
-
if (!activity) return -1;
|
|
10327
|
-
const parentKey = parentKeyOf(activity);
|
|
10328
|
-
const siblings = getChildrenInVisualOrder(parentKey, adapter);
|
|
10329
|
-
return siblings.findIndex((id) => String(id) === String(taskId));
|
|
10330
|
-
}
|
|
10331
|
-
function collectChildrenSnapshots(parentId, adapter) {
|
|
10332
|
-
const key = String(parentId);
|
|
10333
|
-
if (key === "0") {
|
|
10334
|
-
return adapter.getAllActivities().filter((a) => a.parentId === null);
|
|
10335
|
-
}
|
|
10336
|
-
const childIds = adapter.getChildren(parentId);
|
|
10337
|
-
const out = [];
|
|
10338
|
-
for (const id of childIds) {
|
|
10339
|
-
const snap = adapter.getActivity(id);
|
|
10340
|
-
if (snap) out.push(snap);
|
|
10341
|
-
}
|
|
10342
|
-
return out;
|
|
10343
|
-
}
|
|
10344
|
-
function compareActivitiesInVisualOrder(a, b) {
|
|
10345
|
-
const ac = correlativeIdOf(a);
|
|
10346
|
-
const bc = correlativeIdOf(b);
|
|
10347
|
-
if (ac !== bc) return ac - bc;
|
|
10348
|
-
return String(a.id).localeCompare(String(b.id));
|
|
10349
|
-
}
|
|
10350
|
-
function correlativeIdOf(activity) {
|
|
10351
|
-
const raw = activity.correlativeId;
|
|
10352
|
-
const n = typeof raw === "number" ? raw : Number(raw);
|
|
10353
|
-
return Number.isFinite(n) ? n : NOT_SET_SORT_VALUE;
|
|
10354
|
-
}
|
|
10355
|
-
function parentKeyOf(activity) {
|
|
10356
|
-
const parentId = activity.parentId;
|
|
10357
|
-
if (parentId === null) return "0";
|
|
10358
|
-
return parentId;
|
|
10359
|
-
}
|
|
10360
|
-
function setHas(set, id) {
|
|
10361
|
-
if (set.has(id)) return true;
|
|
10362
|
-
return set.has(String(id));
|
|
10363
|
-
}
|
|
10364
|
-
|
|
10365
9997
|
// src/internal/hierarchy/recompute-correlative-ids.ts
|
|
10366
9998
|
function recomputeCorrelativeIds(adapter) {
|
|
10367
9999
|
adapter.invalidateVisualOrderIds?.();
|
|
@@ -10794,7 +10426,7 @@ function computeFractionalCidAtIndex(adapter, parentKey, targetIndex, excludeId)
|
|
|
10794
10426
|
}
|
|
10795
10427
|
|
|
10796
10428
|
// src/dispatch/handlers/activity-create.ts
|
|
10797
|
-
function createActivityCore(action, deps, opts = {}) {
|
|
10429
|
+
async function createActivityCore(action, deps, opts = {}) {
|
|
10798
10430
|
const { adapter, scheduler, sector, calendars, activityIdGen, uidGen } = deps;
|
|
10799
10431
|
scheduler.invalidateAllCaches();
|
|
10800
10432
|
const target = validateCreateTarget(action, adapter);
|
|
@@ -10835,7 +10467,7 @@ function createActivityCore(action, deps, opts = {}) {
|
|
|
10835
10467
|
const initialTouched = /* @__PURE__ */ new Set([newId]);
|
|
10836
10468
|
if (parent) initialTouched.add(parent.id);
|
|
10837
10469
|
const parentWasLeaf = parent !== null && adapter.getChildren(parent.id).length === 0;
|
|
10838
|
-
const beforeSnap = opts.skipBeforeSnap ? /* @__PURE__ */ new Map() : snapshotActivities(adapter, initialTouched);
|
|
10470
|
+
const beforeSnap = opts.skipBeforeSnap ? /* @__PURE__ */ new Map() : await snapshotActivities(adapter, initialTouched);
|
|
10839
10471
|
adapter.addActivity(newActivity);
|
|
10840
10472
|
applyParentMutations(
|
|
10841
10473
|
action,
|
|
@@ -10955,7 +10587,7 @@ function recomputeAndFoldCorrelatives(adapter, newId, beforeSnap, initialTouched
|
|
|
10955
10587
|
initialTouched
|
|
10956
10588
|
);
|
|
10957
10589
|
}
|
|
10958
|
-
function buildCreateChangeSet(adapter, action, coreResult, scheduledIds, hoursPerDay) {
|
|
10590
|
+
async function buildCreateChangeSet(adapter, action, coreResult, scheduledIds, hoursPerDay) {
|
|
10959
10591
|
const { newId, newActivity, beforeSnap, initialTouched } = coreResult;
|
|
10960
10592
|
const trackingEvent = {
|
|
10961
10593
|
name: DISPATCH_TRACK_EVENT.ACTIVITY_CREATION,
|
|
@@ -10977,7 +10609,7 @@ function buildCreateChangeSet(adapter, action, coreResult, scheduledIds, hoursPe
|
|
|
10977
10609
|
}
|
|
10978
10610
|
async function dispatchActivityCreate(action, options, deps) {
|
|
10979
10611
|
const { adapter, scheduler, sector } = deps;
|
|
10980
|
-
const core = createActivityCore(action, deps);
|
|
10612
|
+
const core = await createActivityCore(action, deps);
|
|
10981
10613
|
if (!core.ok) return core;
|
|
10982
10614
|
const { newId } = core;
|
|
10983
10615
|
const createdAutoScheduling = core.newActivity.autoScheduling;
|
|
@@ -11003,7 +10635,7 @@ async function dispatchActivityCreate(action, options, deps) {
|
|
|
11003
10635
|
adapter.setActivityField(newId, "autoScheduling", createdAutoScheduling);
|
|
11004
10636
|
}
|
|
11005
10637
|
const { scheduledIds } = scheduleOutcome;
|
|
11006
|
-
const changeset = buildCreateChangeSet(
|
|
10638
|
+
const changeset = await buildCreateChangeSet(
|
|
11007
10639
|
adapter,
|
|
11008
10640
|
action,
|
|
11009
10641
|
core,
|
|
@@ -11053,7 +10685,7 @@ async function dispatchActivityPaste(action, options, deps) {
|
|
|
11053
10685
|
const { adapter, scheduler, sector } = deps;
|
|
11054
10686
|
const rootDest = resolvePasteRootDestination(action.destination, adapter);
|
|
11055
10687
|
if (!rootDest.ok) return rootDest;
|
|
11056
|
-
const beforeSnap = snapshotActivities(adapter, /* @__PURE__ */ new Set());
|
|
10688
|
+
const beforeSnap = await snapshotActivities(adapter, /* @__PURE__ */ new Set());
|
|
11057
10689
|
const touched = /* @__PURE__ */ new Set();
|
|
11058
10690
|
const originalToNew = /* @__PURE__ */ new Map();
|
|
11059
10691
|
const createdIds = [];
|
|
@@ -11074,7 +10706,7 @@ async function dispatchActivityPaste(action, options, deps) {
|
|
|
11074
10706
|
afterSiblingId = prevRootId;
|
|
11075
10707
|
}
|
|
11076
10708
|
}
|
|
11077
|
-
const core = createActivityCore(
|
|
10709
|
+
const core = await createActivityCore(
|
|
11078
10710
|
{
|
|
11079
10711
|
parentId,
|
|
11080
10712
|
afterSiblingId,
|
|
@@ -11085,16 +10717,8 @@ async function dispatchActivityPaste(action, options, deps) {
|
|
|
11085
10717
|
},
|
|
11086
10718
|
deps,
|
|
11087
10719
|
{
|
|
11088
|
-
// Saltamos el recompute por-create: corre UNA vez tras el loop (abajo).
|
|
11089
10720
|
skipCorrelativeRecompute: true,
|
|
11090
|
-
// Saltamos el snapshot per-create: el paste ya capturó `beforeSnap` del
|
|
11091
|
-
// árbol completo antes del loop (O(N²) de clones puros si no).
|
|
11092
10721
|
skipBeforeSnap: true,
|
|
11093
|
-
// custom_id (paridad legacy): TODAS las pegadas derivan del ancla de
|
|
11094
|
-
// pegado. Los roots ya lo logran vía `afterSiblingId`; los HIJOS
|
|
11095
|
-
// (mappedParent) no tienen sibling anchor → les pasamos el ancla como
|
|
11096
|
-
// `customIdReferenceId`, y preservamos el custom_id de su parent pegado
|
|
11097
|
-
// (que si no, `buildParentMutations` limpiaría al adjuntar el hijo).
|
|
11098
10722
|
...mappedParent !== void 0 ? {
|
|
11099
10723
|
customIdReferenceId: action.referenceActivityId,
|
|
11100
10724
|
preserveParentCustomId: true
|
|
@@ -11138,9 +10762,6 @@ async function dispatchActivityPaste(action, options, deps) {
|
|
|
11138
10762
|
source: newSource,
|
|
11139
10763
|
target: newTarget,
|
|
11140
10764
|
type: link.type,
|
|
11141
|
-
// El clipboard trae `lag` en DÍAS (getLink/getAllLinks → lagHoursToDays);
|
|
11142
|
-
// el motor lo almacena en HORAS LABORALES. Convertir acá, igual que
|
|
11143
|
-
// `duration` arriba y que `link-create`/`link-update` — el borde de entrada.
|
|
11144
10765
|
lag: lagDaysToHours(link.lag, sector.hoursPerDay)
|
|
11145
10766
|
};
|
|
11146
10767
|
const res = applyLinkOperation(op, {
|
|
@@ -11175,7 +10796,7 @@ async function dispatchActivityPaste(action, options, deps) {
|
|
|
11175
10796
|
);
|
|
11176
10797
|
return {
|
|
11177
10798
|
ok: true,
|
|
11178
|
-
changes: assembleChangeSet(adapter, {
|
|
10799
|
+
changes: await assembleChangeSet(adapter, {
|
|
11179
10800
|
source: action,
|
|
11180
10801
|
beforeSnap,
|
|
11181
10802
|
touchedIds: touched,
|
|
@@ -11387,6 +11008,7 @@ function buildParentNewActivitiesCleanup(input) {
|
|
|
11387
11008
|
}
|
|
11388
11009
|
|
|
11389
11010
|
// src/dispatch/handlers/activity-delete.ts
|
|
11011
|
+
var DELETE_YIELD_EVERY_N = 200;
|
|
11390
11012
|
async function dispatchActivityDelete(action, options, deps) {
|
|
11391
11013
|
const { adapter, scheduler, customIdTracker, sector } = deps;
|
|
11392
11014
|
scheduler.invalidateAllCaches();
|
|
@@ -11410,14 +11032,17 @@ async function dispatchActivityDelete(action, options, deps) {
|
|
|
11410
11032
|
if (!toDelete.has(parentKey)) parentsToCheck.add(parentKey);
|
|
11411
11033
|
}
|
|
11412
11034
|
const touchedIds = /* @__PURE__ */ new Set([...toDelete, ...parentsToCheck]);
|
|
11413
|
-
const beforeSnap = snapshotActivities(adapter, touchedIds);
|
|
11035
|
+
const beforeSnap = await snapshotActivities(adapter, touchedIds);
|
|
11414
11036
|
const beforeLinks = /* @__PURE__ */ new Map();
|
|
11415
11037
|
for (const linkId of incidentLinkIds) {
|
|
11416
11038
|
const l = adapter.getLink(linkId);
|
|
11417
11039
|
if (l) beforeLinks.set(linkId, { ...l });
|
|
11418
11040
|
}
|
|
11419
11041
|
const newActivitiesToDelete = /* @__PURE__ */ new Set();
|
|
11042
|
+
let inspected = 0;
|
|
11420
11043
|
for (const id of toDelete) {
|
|
11044
|
+
inspected += 1;
|
|
11045
|
+
if (inspected % DELETE_YIELD_EVERY_N === 0) await yieldToBrowser();
|
|
11421
11046
|
const a = adapter.getActivity(id);
|
|
11422
11047
|
if (!a) continue;
|
|
11423
11048
|
const parent = isRootParent(a.parentId) ? null : adapter.getActivity(String(a.parentId));
|
|
@@ -11434,7 +11059,10 @@ async function dispatchActivityDelete(action, options, deps) {
|
|
|
11434
11059
|
adapter.removeLink(linkId);
|
|
11435
11060
|
}
|
|
11436
11061
|
const viewStateChanges = captureDeletedViewState(adapter, toDelete);
|
|
11062
|
+
let removed = 0;
|
|
11437
11063
|
for (const id of toDelete) {
|
|
11064
|
+
removed += 1;
|
|
11065
|
+
if (removed % DELETE_YIELD_EVERY_N === 0) await yieldToBrowser();
|
|
11438
11066
|
adapter.removeActivity(id);
|
|
11439
11067
|
}
|
|
11440
11068
|
for (const parentId of parentsToCheck) {
|
|
@@ -11474,15 +11102,6 @@ async function dispatchActivityDelete(action, options, deps) {
|
|
|
11474
11102
|
recomputeRollupCascadesForParent(parentId, adapter);
|
|
11475
11103
|
}
|
|
11476
11104
|
const correlativeShifts = recomputeCorrelativeIds(adapter);
|
|
11477
|
-
for (const shift of correlativeShifts) {
|
|
11478
|
-
touchedIds.add(shift.activityId);
|
|
11479
|
-
if (beforeSnap.has(shift.activityId)) continue;
|
|
11480
|
-
const liveActivity = adapter.getActivity(shift.activityId);
|
|
11481
|
-
if (!liveActivity) continue;
|
|
11482
|
-
const beforeImage = structuredCloneActivity(liveActivity);
|
|
11483
|
-
if (shift.before !== void 0) beforeImage.correlativeId = shift.before;
|
|
11484
|
-
beforeSnap.set(shift.activityId, beforeImage);
|
|
11485
|
-
}
|
|
11486
11105
|
const { scheduledIds } = await runPostMutation(
|
|
11487
11106
|
{
|
|
11488
11107
|
adapter,
|
|
@@ -11515,7 +11134,7 @@ async function dispatchActivityDelete(action, options, deps) {
|
|
|
11515
11134
|
const snap = beforeSnap.get(String(id));
|
|
11516
11135
|
if (snap) deletedRowsSnap.set(String(id), snap);
|
|
11517
11136
|
}
|
|
11518
|
-
const changes = assembleChangeSet(adapter, {
|
|
11137
|
+
const changes = await assembleChangeSet(adapter, {
|
|
11519
11138
|
source: action,
|
|
11520
11139
|
beforeSnap,
|
|
11521
11140
|
touchedIds,
|
|
@@ -11523,7 +11142,8 @@ async function dispatchActivityDelete(action, options, deps) {
|
|
|
11523
11142
|
sirDetection: "after-diff",
|
|
11524
11143
|
links: buildLinkDeletions(beforeLinks),
|
|
11525
11144
|
trackingEvents: [trackingEvent],
|
|
11526
|
-
hoursPerDay: sector.hoursPerDay
|
|
11145
|
+
hoursPerDay: sector.hoursPerDay,
|
|
11146
|
+
correlativeShifts
|
|
11527
11147
|
});
|
|
11528
11148
|
return {
|
|
11529
11149
|
ok: true,
|
|
@@ -11563,8 +11183,6 @@ function buildLinkDeletions(beforeLinks) {
|
|
|
11563
11183
|
source: { before: String(before.source), after: void 0 },
|
|
11564
11184
|
target: { before: String(before.target), after: void 0 },
|
|
11565
11185
|
type: { before: before.type, after: void 0 },
|
|
11566
|
-
// Engine stores lag in WORKING HOURS — ChangeSet now emits HOURS too.
|
|
11567
|
-
// `toPublicChangeSet` at the facade boundary converts to days (default).
|
|
11568
11186
|
lag: { before: Number(before.lag), after: void 0 }
|
|
11569
11187
|
},
|
|
11570
11188
|
after: null
|
|
@@ -11653,7 +11271,7 @@ async function dispatchActivityMove(action, options, deps) {
|
|
|
11653
11271
|
} else {
|
|
11654
11272
|
if (oldParentKey !== ROOT_PARENT_ID) touched.add(oldParentKey);
|
|
11655
11273
|
}
|
|
11656
|
-
const beforeSnap = snapshotActivities(adapter, touched);
|
|
11274
|
+
const beforeSnap = await snapshotActivities(adapter, touched);
|
|
11657
11275
|
if (parentChanged) {
|
|
11658
11276
|
adapter.setActivityField(
|
|
11659
11277
|
action.activityId,
|
|
@@ -11683,8 +11301,6 @@ async function dispatchActivityMove(action, options, deps) {
|
|
|
11683
11301
|
newChildId: action.activityId,
|
|
11684
11302
|
getParent: (id) => adapter.getActivity(id) ?? null,
|
|
11685
11303
|
isCurrentlyLeaf: wasLeaf,
|
|
11686
|
-
// Move reparents an EXISTING child — legacy never re-stamps the new
|
|
11687
|
-
// parent's progress (it keeps its pre-move leaf value). See JUN-23.
|
|
11688
11304
|
promotionSource: "reparent"
|
|
11689
11305
|
});
|
|
11690
11306
|
if (promotion) {
|
|
@@ -11793,7 +11409,7 @@ async function dispatchActivityMove(action, options, deps) {
|
|
|
11793
11409
|
}
|
|
11794
11410
|
return {
|
|
11795
11411
|
ok: true,
|
|
11796
|
-
changes: assembleChangeSet(adapter, {
|
|
11412
|
+
changes: await assembleChangeSet(adapter, {
|
|
11797
11413
|
source: action,
|
|
11798
11414
|
beforeSnap,
|
|
11799
11415
|
touchedIds: touched,
|
|
@@ -11855,7 +11471,7 @@ async function dispatchActivityIndent(action, options, deps) {
|
|
|
11855
11471
|
touched.add(targetParentId);
|
|
11856
11472
|
if (oldParentId !== ROOT_PARENT_ID) touched.add(oldParentId);
|
|
11857
11473
|
}
|
|
11858
|
-
const beforeSnap = snapshotActivities(adapter, touched);
|
|
11474
|
+
const beforeSnap = await snapshotActivities(adapter, touched);
|
|
11859
11475
|
for (const { activityId, newParentId } of moves) {
|
|
11860
11476
|
adapter.setActivityField(activityId, ACTIVITY_PROPERTY.PARENT, newParentId);
|
|
11861
11477
|
adapter.setActivityField(
|
|
@@ -11879,8 +11495,6 @@ async function dispatchActivityIndent(action, options, deps) {
|
|
|
11879
11495
|
newChildId: activityId,
|
|
11880
11496
|
getParent: (id) => adapter.getActivity(id) ?? null,
|
|
11881
11497
|
isCurrentlyLeaf: wasLeaf,
|
|
11882
|
-
// Indent reparents an EXISTING child — legacy never re-stamps the new
|
|
11883
|
-
// parent's progress (it keeps its pre-indent leaf value). See JUN-23.
|
|
11884
11498
|
promotionSource: "reparent"
|
|
11885
11499
|
});
|
|
11886
11500
|
if (promotion) {
|
|
@@ -11947,33 +11561,8 @@ async function dispatchActivityIndent(action, options, deps) {
|
|
|
11947
11561
|
},
|
|
11948
11562
|
{
|
|
11949
11563
|
action,
|
|
11950
|
-
// A pure indent (reparent) does NOT auto-reschedule dates in legacy:
|
|
11951
|
-
// `actions.indent` runs purely through `gantt.moveTask`, firing only
|
|
11952
|
-
// `onBeforeTaskMove`/`onAfterTaskMove` — never `autoSchedule()` /
|
|
11953
|
-
// `onAfterAutoSchedule`. So the moved child + its downstream chain KEEP
|
|
11954
|
-
// their pre-indent dates; only the new parent's bounds re-roll (via
|
|
11955
|
-
// DHTMLX `_update_parents` in the move's batchUpdate — done unconditionally
|
|
11956
|
-
// by `updateParentBoundsFromChildren` below). The core previously passed
|
|
11957
|
-
// `{}` here, running a full ASAP/ALAP reflow that pulled the moved child +
|
|
11958
|
-
// chain as-early-as-possible — diverging from the oracle (MORNING_QUEUE.md
|
|
11959
|
-
// — JUN-11 corr20 stays 2024-05-07 stale, core moved it to 04-30; JUN-16(B)
|
|
11960
|
-
// corr33 stays 2026-10-21 stale, core pulled it to 09-16). `null` suppresses
|
|
11961
|
-
// the date cascade entirely, completing the outdent mirror (outdent's `{}`
|
|
11962
|
-
// was always a no-op because its moved child keeps its links/position; a
|
|
11963
|
-
// childless leaf + reparent of an EXISTING activity is never the trigger
|
|
11964
|
-
// of an autoSchedule). A SUBSEQUENT date/constraint/link edit still
|
|
11965
|
-
// cascades normally (its own handler passes a non-null trigger).
|
|
11966
11564
|
autoscheduleFrom: null,
|
|
11967
11565
|
recomputeParentsFrom: succeededIds,
|
|
11968
|
-
// A pure indent re-rolls the new parent's start/end/duration but legacy
|
|
11969
|
-
// leaves `for_disable_milestone_duration` STALE at the pre-indent value —
|
|
11970
|
-
// the milestone-promotion branch (`adjustParentMilestone`) only fires for a
|
|
11971
|
-
// 0-duration milestone, never a task → project promotion (MORNING_QUEUE.md
|
|
11972
|
-
// — JUN-18 / JUN-11). A later scheduling recalc that re-rolls these parents
|
|
11973
|
-
// re-derives the mirror = duration — that is how the oracle's mirror is
|
|
11974
|
-
// FRESH whenever an edit follows the indent (MORNING_QUEUE.md — JUN-19).
|
|
11975
|
-
// `resolveDerivedPasses` skips the ancestor stamp for activity-indent.
|
|
11976
|
-
// activity-indent is a structural reparent: leaves EP and CP stale.
|
|
11977
11566
|
now: deps.now,
|
|
11978
11567
|
options
|
|
11979
11568
|
}
|
|
@@ -12005,7 +11594,7 @@ async function dispatchActivityIndent(action, options, deps) {
|
|
|
12005
11594
|
reason: failure.reason
|
|
12006
11595
|
} : { activityId: String(activityId), ok: true };
|
|
12007
11596
|
}),
|
|
12008
|
-
changes: assembleChangeSet(adapter, {
|
|
11597
|
+
changes: await assembleChangeSet(adapter, {
|
|
12009
11598
|
source: action,
|
|
12010
11599
|
beforeSnap,
|
|
12011
11600
|
touchedIds: touched,
|
|
@@ -12103,7 +11692,7 @@ async function dispatchActivityOutdent(action, options, deps) {
|
|
|
12103
11692
|
if (grandparentKey !== ROOT_PARENT_ID) touched.add(String(grandparentKey));
|
|
12104
11693
|
oldParents.add(oldParentKey);
|
|
12105
11694
|
}
|
|
12106
|
-
const beforeSnap = snapshotActivities(adapter, touched);
|
|
11695
|
+
const beforeSnap = await snapshotActivities(adapter, touched);
|
|
12107
11696
|
for (const plan of planned) {
|
|
12108
11697
|
adapter.setActivityField(
|
|
12109
11698
|
plan.activityId,
|
|
@@ -12190,12 +11779,9 @@ async function dispatchActivityOutdent(action, options, deps) {
|
|
|
12190
11779
|
defaultBaseCalendarId: deps.defaultBaseCalendarId
|
|
12191
11780
|
},
|
|
12192
11781
|
{
|
|
12193
|
-
// Empty-batch gate: nothing moved → no autoscheduler pass (the
|
|
12194
|
-
// unconditional parent-bounds rollup still runs).
|
|
12195
11782
|
action,
|
|
12196
11783
|
autoscheduleFrom: succeededIds.length > 0 ? "roots" : null,
|
|
12197
11784
|
recomputeParentsFrom: succeededIds,
|
|
12198
|
-
// activity-outdent is a structural reparent: leaves EP and CP stale.
|
|
12199
11785
|
now: deps.now,
|
|
12200
11786
|
options
|
|
12201
11787
|
}
|
|
@@ -12225,7 +11811,7 @@ async function dispatchActivityOutdent(action, options, deps) {
|
|
|
12225
11811
|
reason: failure.reason
|
|
12226
11812
|
} : { activityId: String(activityId), ok: true };
|
|
12227
11813
|
}),
|
|
12228
|
-
changes: assembleChangeSet(adapter, {
|
|
11814
|
+
changes: await assembleChangeSet(adapter, {
|
|
12229
11815
|
source: action,
|
|
12230
11816
|
beforeSnap,
|
|
12231
11817
|
touchedIds: touched,
|
|
@@ -12262,7 +11848,7 @@ async function dispatchActivitySetProgress(action, options, deps) {
|
|
|
12262
11848
|
action.newValue
|
|
12263
11849
|
);
|
|
12264
11850
|
const touchedIds = collectTouchedIds(action.activityId, changes);
|
|
12265
|
-
const beforeSnap = snapshotActivities(adapter, touchedIds);
|
|
11851
|
+
const beforeSnap = await snapshotActivities(adapter, touchedIds);
|
|
12266
11852
|
applyFieldChanges(adapter, action.activityId, changes);
|
|
12267
11853
|
runPostProcessorsOnAdapter(
|
|
12268
11854
|
action.activityId,
|
|
@@ -12278,7 +11864,6 @@ async function dispatchActivitySetProgress(action, options, deps) {
|
|
|
12278
11864
|
},
|
|
12279
11865
|
{
|
|
12280
11866
|
action,
|
|
12281
|
-
// Pipeline gate: only schedule when the transform asked for it.
|
|
12282
11867
|
autoscheduleFrom: changes.needsAutoSchedule ? action.activityId : null,
|
|
12283
11868
|
recomputeParentsFrom: [],
|
|
12284
11869
|
collectDirty: (sids) => collectDirtyForInlineEdit(action.activityId, touchedIds, sids),
|
|
@@ -12292,7 +11877,7 @@ async function dispatchActivitySetProgress(action, options, deps) {
|
|
|
12292
11877
|
}));
|
|
12293
11878
|
return {
|
|
12294
11879
|
ok: true,
|
|
12295
|
-
changes: assembleChangeSet(adapter, {
|
|
11880
|
+
changes: await assembleChangeSet(adapter, {
|
|
12296
11881
|
source: action,
|
|
12297
11882
|
beforeSnap,
|
|
12298
11883
|
touchedIds,
|
|
@@ -12321,9 +11906,10 @@ async function dispatchDatesBatch(action, options, deps) {
|
|
|
12321
11906
|
mergeBeforeSnapshots(beforeSnap, editTouched, deps);
|
|
12322
11907
|
for (const id of editTouched) touchedIds.add(id);
|
|
12323
11908
|
const beforeLinkLags = snapshotIncomingLinkLags(adapter, edit.activityId);
|
|
12324
|
-
const preEditSnapshot =
|
|
11909
|
+
const preEditSnapshot = snapshotSingleActivity(
|
|
11910
|
+
adapter,
|
|
12325
11911
|
String(edit.activityId)
|
|
12326
|
-
)
|
|
11912
|
+
);
|
|
12327
11913
|
applyFieldChanges(adapter, edit.activityId, outcome.changes);
|
|
12328
11914
|
runPostProcessorsOnAdapter(
|
|
12329
11915
|
edit.activityId,
|
|
@@ -12365,7 +11951,7 @@ async function dispatchDatesBatch(action, options, deps) {
|
|
|
12365
11951
|
return {
|
|
12366
11952
|
ok: true,
|
|
12367
11953
|
verdicts,
|
|
12368
|
-
changes: assembleChangeSet(adapter, {
|
|
11954
|
+
changes: await assembleChangeSet(adapter, {
|
|
12369
11955
|
source: action,
|
|
12370
11956
|
beforeSnap,
|
|
12371
11957
|
touchedIds,
|
|
@@ -12446,8 +12032,11 @@ function mergeBeforeSnapshots(beforeSnap, ids, deps) {
|
|
|
12446
12032
|
if (!beforeSnap.has(id)) missing.add(id);
|
|
12447
12033
|
}
|
|
12448
12034
|
if (missing.size === 0) return;
|
|
12449
|
-
for (const
|
|
12450
|
-
|
|
12035
|
+
for (const missingId of missing) {
|
|
12036
|
+
const liveActivity = deps.adapter.getActivity(missingId);
|
|
12037
|
+
if (liveActivity) {
|
|
12038
|
+
beforeSnap.set(missingId, structuredCloneActivity(liveActivity));
|
|
12039
|
+
}
|
|
12451
12040
|
}
|
|
12452
12041
|
}
|
|
12453
12042
|
|
|
@@ -12487,9 +12076,10 @@ async function dispatchBulkEdit(action, options, deps) {
|
|
|
12487
12076
|
explicitDateEditActivities.add(String(edit.activityId));
|
|
12488
12077
|
}
|
|
12489
12078
|
const beforeLinkLags = snapshotIncomingLinkLags(adapter, edit.activityId);
|
|
12490
|
-
const preEditSnapshot =
|
|
12079
|
+
const preEditSnapshot = snapshotSingleActivity(
|
|
12080
|
+
adapter,
|
|
12491
12081
|
String(edit.activityId)
|
|
12492
|
-
)
|
|
12082
|
+
);
|
|
12493
12083
|
const customIdBeforeApply = readLiveCustomId(edit, deps);
|
|
12494
12084
|
const changes = outcome.changes;
|
|
12495
12085
|
applyFieldChanges(adapter, edit.activityId, changes);
|
|
@@ -12553,14 +12143,11 @@ async function dispatchBulkEdit(action, options, deps) {
|
|
|
12553
12143
|
return {
|
|
12554
12144
|
ok: true,
|
|
12555
12145
|
verdicts,
|
|
12556
|
-
changes: assembleChangeSet(adapter, {
|
|
12146
|
+
changes: await assembleChangeSet(adapter, {
|
|
12557
12147
|
source: action,
|
|
12558
12148
|
beforeSnap,
|
|
12559
12149
|
touchedIds,
|
|
12560
12150
|
scheduledIds,
|
|
12561
|
-
// Los dependientes que mueve el autoscheduler no están en beforeSnap;
|
|
12562
|
-
// sin su before-image el diff los marca FALSE-CREATED y el undo los
|
|
12563
|
-
// borra (fix 4bbccbc de inline-edit).
|
|
12564
12151
|
sirDetection: "before-diff",
|
|
12565
12152
|
links: linkChanges,
|
|
12566
12153
|
trackingEvents,
|
|
@@ -12687,11 +12274,11 @@ function mergeBeforeSnapshots2(beforeSnap, ids, deps) {
|
|
|
12687
12274
|
if (!beforeSnap.has(candidateId)) missing.add(candidateId);
|
|
12688
12275
|
}
|
|
12689
12276
|
if (missing.size === 0) return;
|
|
12690
|
-
for (const
|
|
12691
|
-
deps.adapter
|
|
12692
|
-
|
|
12693
|
-
|
|
12694
|
-
|
|
12277
|
+
for (const missingId of missing) {
|
|
12278
|
+
const liveActivity = deps.adapter.getActivity(missingId);
|
|
12279
|
+
if (liveActivity) {
|
|
12280
|
+
beforeSnap.set(missingId, structuredCloneActivity(liveActivity));
|
|
12281
|
+
}
|
|
12695
12282
|
}
|
|
12696
12283
|
}
|
|
12697
12284
|
|
|
@@ -13115,8 +12702,8 @@ function activeBaselineSignature(deps) {
|
|
|
13115
12702
|
})
|
|
13116
12703
|
);
|
|
13117
12704
|
}
|
|
13118
|
-
function dispatchBaselineApply(action, deps) {
|
|
13119
|
-
const beforeSnap = snapshotActivities(
|
|
12705
|
+
async function dispatchBaselineApply(action, deps) {
|
|
12706
|
+
const beforeSnap = await snapshotActivities(
|
|
13120
12707
|
deps.adapter,
|
|
13121
12708
|
new Set(deps.adapter.getAllIds())
|
|
13122
12709
|
);
|
|
@@ -13136,7 +12723,7 @@ function dispatchBaselineApply(action, deps) {
|
|
|
13136
12723
|
}
|
|
13137
12724
|
return {
|
|
13138
12725
|
ok: true,
|
|
13139
|
-
changes: assembleChangeSet(deps.adapter, {
|
|
12726
|
+
changes: await assembleChangeSet(deps.adapter, {
|
|
13140
12727
|
source: action,
|
|
13141
12728
|
beforeSnap,
|
|
13142
12729
|
touchedIds: changedIds,
|
|
@@ -13153,15 +12740,15 @@ function assertValidCriterion(value) {
|
|
|
13153
12740
|
`ponderator-criterion-set: invalid criterion "${String(value)}"`
|
|
13154
12741
|
);
|
|
13155
12742
|
}
|
|
13156
|
-
function dispatchPonderatorCriterionSet(action, deps) {
|
|
12743
|
+
async function dispatchPonderatorCriterionSet(action, deps) {
|
|
13157
12744
|
assertValidCriterion(action.criterion);
|
|
13158
12745
|
const allIds = new Set(deps.adapter.getAllIds());
|
|
13159
|
-
const beforeSnap = snapshotActivities(deps.adapter, allIds);
|
|
12746
|
+
const beforeSnap = await snapshotActivities(deps.adapter, allIds);
|
|
13160
12747
|
recomputeBaselineWeightedFields(deps, action.criterion);
|
|
13161
12748
|
deps.sector.activityCreter = action.criterion;
|
|
13162
12749
|
return {
|
|
13163
12750
|
ok: true,
|
|
13164
|
-
changes: assembleChangeSet(deps.adapter, {
|
|
12751
|
+
changes: await assembleChangeSet(deps.adapter, {
|
|
13165
12752
|
source: action,
|
|
13166
12753
|
beforeSnap,
|
|
13167
12754
|
touchedIds: allIds,
|
|
@@ -13172,15 +12759,15 @@ function dispatchPonderatorCriterionSet(action, deps) {
|
|
|
13172
12759
|
}
|
|
13173
12760
|
|
|
13174
12761
|
// src/dispatch/handlers/status-criteria-set.ts
|
|
13175
|
-
function dispatchStatusCriteriaSet(action, deps) {
|
|
12762
|
+
async function dispatchStatusCriteriaSet(action, deps) {
|
|
13176
12763
|
const resolved = resolveStatusCriteria(action.criteria);
|
|
13177
12764
|
const allIds = new Set(deps.adapter.getAllIds());
|
|
13178
|
-
const beforeSnap = snapshotActivities(deps.adapter, allIds);
|
|
12765
|
+
const beforeSnap = await snapshotActivities(deps.adapter, allIds);
|
|
13179
12766
|
const changedIds = applyStatusPass(deps.adapter, resolved);
|
|
13180
12767
|
deps.sector.statusCriteria = resolved;
|
|
13181
12768
|
return {
|
|
13182
12769
|
ok: true,
|
|
13183
|
-
changes: assembleChangeSet(deps.adapter, {
|
|
12770
|
+
changes: await assembleChangeSet(deps.adapter, {
|
|
13184
12771
|
source: action,
|
|
13185
12772
|
beforeSnap,
|
|
13186
12773
|
touchedIds: changedIds,
|
|
@@ -13246,6 +12833,15 @@ async function dispatch(action, options, deps) {
|
|
|
13246
12833
|
if (action.kind === "visibility-set") {
|
|
13247
12834
|
return dispatchVisibilitySet(action, selectionDeps(deps));
|
|
13248
12835
|
}
|
|
12836
|
+
if (action.kind === "filter-set") {
|
|
12837
|
+
return dispatchFilterSet(action, {
|
|
12838
|
+
adapter: deps.adapter,
|
|
12839
|
+
hoursPerDay: deps.sector.hoursPerDay
|
|
12840
|
+
});
|
|
12841
|
+
}
|
|
12842
|
+
if (action.kind === "sort-set") {
|
|
12843
|
+
return dispatchSortSet(action, { adapter: deps.adapter });
|
|
12844
|
+
}
|
|
13249
12845
|
if (action.kind === "sir-sync") {
|
|
13250
12846
|
return dispatchSirSync(action, deps);
|
|
13251
12847
|
}
|
|
@@ -15768,9 +15364,7 @@ var defaultLocale = {
|
|
|
15768
15364
|
function createGanttShim(options = {}) {
|
|
15769
15365
|
const userConfig = options.config || {};
|
|
15770
15366
|
const shim = {
|
|
15771
|
-
// ------ Config ------
|
|
15772
15367
|
config: Object.assign({
|
|
15773
|
-
// Defaults críticos para calendar
|
|
15774
15368
|
duration_unit: "hour",
|
|
15775
15369
|
duration_step: 1,
|
|
15776
15370
|
work_time: false,
|
|
@@ -15781,16 +15375,13 @@ function createGanttShim(options = {}) {
|
|
|
15781
15375
|
resource_property: "resource_id",
|
|
15782
15376
|
resource_calendars: {},
|
|
15783
15377
|
dynamic_resource_calendars: false,
|
|
15784
|
-
// Config date module
|
|
15785
15378
|
start_on_monday: true,
|
|
15786
15379
|
server_utc: true,
|
|
15787
15380
|
csp: "auto",
|
|
15788
15381
|
show_errors: false
|
|
15789
15382
|
}, userConfig),
|
|
15790
|
-
// ------ Locale + templates ------
|
|
15791
15383
|
locale: options.locale || defaultLocale,
|
|
15792
15384
|
templates: options.templates || {},
|
|
15793
|
-
// ------ Task resolver (opcional) ------
|
|
15794
15385
|
getTask: options.getTask || function(id) {
|
|
15795
15386
|
return null;
|
|
15796
15387
|
},
|
|
@@ -15800,11 +15391,9 @@ function createGanttShim(options = {}) {
|
|
|
15800
15391
|
isSummaryTask: options.isSummaryTask || function(task) {
|
|
15801
15392
|
return false;
|
|
15802
15393
|
},
|
|
15803
|
-
// ------ State (mínimo) ------
|
|
15804
15394
|
getState: function() {
|
|
15805
15395
|
return { group_mode: false };
|
|
15806
15396
|
},
|
|
15807
|
-
// ------ Eventable (no-ops por defecto) ------
|
|
15808
15397
|
callEvent: function(name, args) {
|
|
15809
15398
|
const handler = options.onEvent;
|
|
15810
15399
|
if (handler) handler(name, args);
|
|
@@ -15818,7 +15407,6 @@ function createGanttShim(options = {}) {
|
|
|
15818
15407
|
},
|
|
15819
15408
|
detachEvent: function() {
|
|
15820
15409
|
},
|
|
15821
|
-
// ------ Utils expuestas en gantt2 ------
|
|
15822
15410
|
defined,
|
|
15823
15411
|
mixin,
|
|
15824
15412
|
copy,
|
|
@@ -15828,7 +15416,6 @@ function createGanttShim(options = {}) {
|
|
|
15828
15416
|
else if (options.silent !== true) console.error("[calendar]", msg);
|
|
15829
15417
|
}
|
|
15830
15418
|
},
|
|
15831
|
-
// ------ $services / $ui — stubs minimales para evitar cracks ------
|
|
15832
15419
|
$services: { getService: function() {
|
|
15833
15420
|
return null;
|
|
15834
15421
|
} },
|
|
@@ -15849,7 +15436,6 @@ function createGanttShim(options = {}) {
|
|
|
15849
15436
|
function createCalendar(options = {}) {
|
|
15850
15437
|
const shim = createGanttShim(options);
|
|
15851
15438
|
return {
|
|
15852
|
-
// ------ Gestión de calendarios ------
|
|
15853
15439
|
addCalendar: function(c) {
|
|
15854
15440
|
return shim.addCalendar(c);
|
|
15855
15441
|
},
|
|
@@ -15871,7 +15457,6 @@ function createCalendar(options = {}) {
|
|
|
15871
15457
|
getResourceCalendar: function(r) {
|
|
15872
15458
|
return shim.getResourceCalendar(r);
|
|
15873
15459
|
},
|
|
15874
|
-
// ------ Cálculo (también disponible en cada Calendar instance) ------
|
|
15875
15460
|
setWorkTime: function(c) {
|
|
15876
15461
|
return shim.setWorkTime(c);
|
|
15877
15462
|
},
|
|
@@ -15893,7 +15478,6 @@ function createCalendar(options = {}) {
|
|
|
15893
15478
|
calculateEndDate: function() {
|
|
15894
15479
|
return shim.calculateEndDate.apply(shim, arguments);
|
|
15895
15480
|
},
|
|
15896
|
-
// ------ Para inspección/debug ------
|
|
15897
15481
|
_internals: shim
|
|
15898
15482
|
};
|
|
15899
15483
|
}
|
|
@@ -15921,16 +15505,11 @@ function normalizeWorktimeHours(hours) {
|
|
|
15921
15505
|
return [`${first}:00-${last + 1}:00`];
|
|
15922
15506
|
}
|
|
15923
15507
|
var DEFAULT_WORKTIME = {
|
|
15924
|
-
// 08:00..16:00 UTC, Mon..Fri. Matches the prior generic fallback used by
|
|
15925
|
-
// synthetic fixtures and CPM nodes whose calendar id is genuinely unknown.
|
|
15926
15508
|
hours: ["8:00-16:00"],
|
|
15927
15509
|
days: [false, true, true, true, true, true, false]
|
|
15928
15510
|
};
|
|
15929
15511
|
var CATALOG_ONLY_CALENDAR_ID = "__main_global__";
|
|
15930
15512
|
var CATALOG_ONLY_WORKTIME = {
|
|
15931
|
-
// Native MAIN/DHTMLX global calendar. A calendar present in the selector but
|
|
15932
|
-
// lacking usable shifts is not registered by MAIN, so its date arithmetic
|
|
15933
|
-
// falls through to this split-day global calendar.
|
|
15934
15513
|
hours: ["8:00-12:00", "13:00-17:00"],
|
|
15935
15514
|
days: [false, true, true, true, true, true, false]
|
|
15936
15515
|
};
|
|
@@ -16122,7 +15701,6 @@ var WriteCapture = class {
|
|
|
16122
15701
|
end() {
|
|
16123
15702
|
this._journal = null;
|
|
16124
15703
|
}
|
|
16125
|
-
/** Field write on an activity — pre-mutation clone on first write per id. */
|
|
16126
15704
|
note(key, current) {
|
|
16127
15705
|
const journal = this._journal;
|
|
16128
15706
|
if (!journal) return;
|
|
@@ -16150,13 +15728,11 @@ var WriteCapture = class {
|
|
|
16150
15728
|
before: cloneLink(current)
|
|
16151
15729
|
});
|
|
16152
15730
|
}
|
|
16153
|
-
/** Pre-sweep correlative_id of an activity the renumbering shifted (first-wins). */
|
|
16154
15731
|
noteCorrelativeBefore(activityId, before) {
|
|
16155
15732
|
const journal = this._journal;
|
|
16156
15733
|
if (!journal || journal.correlativeBefore.has(activityId)) return;
|
|
16157
15734
|
journal.correlativeBefore.set(activityId, before);
|
|
16158
15735
|
}
|
|
16159
|
-
/** Pre-applyResults clone of an activity the autoscheduler will move (first-wins). */
|
|
16160
15736
|
noteScheduledBefore(activityId, current) {
|
|
16161
15737
|
const journal = this._journal;
|
|
16162
15738
|
if (!journal) return;
|
|
@@ -16169,7 +15745,6 @@ var WriteCapture = class {
|
|
|
16169
15745
|
}
|
|
16170
15746
|
journal.dirty.add(activityId);
|
|
16171
15747
|
}
|
|
16172
|
-
/** Field write on a link — pre-mutation clone on first write per link id. */
|
|
16173
15748
|
noteLinkField(linkId, current) {
|
|
16174
15749
|
const journal = this._journal;
|
|
16175
15750
|
if (!journal || journal.linkFieldCaptured.has(linkId)) return;
|
|
@@ -16187,17 +15762,11 @@ function cloneLink(link) {
|
|
|
16187
15762
|
|
|
16188
15763
|
// src/internal/state/calendar-calculator.ts
|
|
16189
15764
|
var CalendarCalculator = class {
|
|
16190
|
-
// In-dispatch calendar API memoization. Lifetime = one scheduler run.
|
|
16191
15765
|
_cache = {
|
|
16192
15766
|
closestWorkTime: /* @__PURE__ */ new Map(),
|
|
16193
15767
|
endDate: /* @__PURE__ */ new Map(),
|
|
16194
15768
|
duration: /* @__PURE__ */ new Map()
|
|
16195
15769
|
};
|
|
16196
|
-
// Single owner of the calendar subsystem. The calc resolves calendars (incl.
|
|
16197
|
-
// the `-base` ones and the default fallback) through the reader — one resolver
|
|
16198
|
-
// for the whole calendar surface instead of a separate Map + default field.
|
|
16199
|
-
/** Resolver for ANY calendar incl. the `-base` ones — also consumed by the
|
|
16200
|
-
* column pipelines via `pipeline-context`. */
|
|
16201
15770
|
reader;
|
|
16202
15771
|
constructor(setup) {
|
|
16203
15772
|
this.reader = setup.reader;
|
|
@@ -16240,11 +15809,6 @@ var CalendarCalculator = class {
|
|
|
16240
15809
|
)
|
|
16241
15810
|
);
|
|
16242
15811
|
}
|
|
16243
|
-
/**
|
|
16244
|
-
* Clears the in-dispatch calendar API memoization. Call at the start of
|
|
16245
|
-
* every scheduler run (calendars are immutable within a dispatch but may
|
|
16246
|
-
* change across dispatches).
|
|
16247
|
-
*/
|
|
16248
15812
|
clearCache() {
|
|
16249
15813
|
this._cache.closestWorkTime.clear();
|
|
16250
15814
|
this._cache.endDate.clear();
|
|
@@ -16277,16 +15841,7 @@ var HierarchyIndex = class {
|
|
|
16277
15841
|
activities;
|
|
16278
15842
|
_childrenByParent = /* @__PURE__ */ new Map();
|
|
16279
15843
|
_roots = [];
|
|
16280
|
-
/**
|
|
16281
|
-
* When true, `_childrenByParent` is stale (a `parent` write happened) and is
|
|
16282
|
-
* lazily rebuilt on the next `getChildren`. A bulk reparent (K rows) marks
|
|
16283
|
-
* dirty K times but pays ONE rebuild on the next read instead of K — turning
|
|
16284
|
-
* bulk indent/outdent from O(K·N) into O(K+N). Only `getChildren` reads this
|
|
16285
|
-
* index; `getParent`/`getParentId`/`isChildOf` read `activities` directly and
|
|
16286
|
-
* are always fresh, so they don't consult the flag. See PERFORMANCE.md §A3.
|
|
16287
|
-
*/
|
|
16288
15844
|
_dirty = false;
|
|
16289
|
-
/** Mark the children index stale; the next `getChildren` rebuilds it once. */
|
|
16290
15845
|
markDirty() {
|
|
16291
15846
|
this._dirty = true;
|
|
16292
15847
|
}
|
|
@@ -16330,11 +15885,6 @@ var HierarchyIndex = class {
|
|
|
16330
15885
|
getParentId(id) {
|
|
16331
15886
|
return this.activities.get(id)?.parentId ?? null;
|
|
16332
15887
|
}
|
|
16333
|
-
/**
|
|
16334
|
-
* Incremental O(1) insert for a freshly added activity (create/paste).
|
|
16335
|
-
* The id is new, so no rebuild is needed — reparenting goes through
|
|
16336
|
-
* `rebuild()` instead.
|
|
16337
|
-
*/
|
|
16338
15888
|
addChild(parentId, id) {
|
|
16339
15889
|
if (this._dirty) return;
|
|
16340
15890
|
if (isRootParent(parentId)) {
|
|
@@ -16346,7 +15896,6 @@ var HierarchyIndex = class {
|
|
|
16346
15896
|
if (arr) arr.push(id);
|
|
16347
15897
|
else this._childrenByParent.set(key, [id]);
|
|
16348
15898
|
}
|
|
16349
|
-
/** Full rebuild from the activity store. */
|
|
16350
15899
|
rebuild() {
|
|
16351
15900
|
this._childrenByParent.clear();
|
|
16352
15901
|
this._roots = [];
|
|
@@ -16379,12 +15928,29 @@ var HierarchyIndex = class {
|
|
|
16379
15928
|
var ViewStateStore = class {
|
|
16380
15929
|
checkedSet = /* @__PURE__ */ new Set();
|
|
16381
15930
|
hiddenSet = /* @__PURE__ */ new Set();
|
|
15931
|
+
activeFilter = null;
|
|
15932
|
+
activeOrder = null;
|
|
16382
15933
|
isChecked(activityId) {
|
|
16383
15934
|
return this.checkedSet.has(activityId);
|
|
16384
15935
|
}
|
|
16385
15936
|
isVisible(activityId) {
|
|
16386
15937
|
return !this.hiddenSet.has(activityId);
|
|
16387
15938
|
}
|
|
15939
|
+
hiddenIds() {
|
|
15940
|
+
return [...this.hiddenSet];
|
|
15941
|
+
}
|
|
15942
|
+
getActiveFilter() {
|
|
15943
|
+
return this.activeFilter;
|
|
15944
|
+
}
|
|
15945
|
+
setActiveFilter(nextFilter) {
|
|
15946
|
+
this.activeFilter = nextFilter;
|
|
15947
|
+
}
|
|
15948
|
+
getActiveOrder() {
|
|
15949
|
+
return this.activeOrder;
|
|
15950
|
+
}
|
|
15951
|
+
setActiveOrder(nextOrder) {
|
|
15952
|
+
this.activeOrder = nextOrder;
|
|
15953
|
+
}
|
|
16388
15954
|
checkedIds() {
|
|
16389
15955
|
return [...this.checkedSet];
|
|
16390
15956
|
}
|
|
@@ -16410,58 +15976,49 @@ var ViewStateStore = class {
|
|
|
16410
15976
|
hydrate(seed2) {
|
|
16411
15977
|
this.checkedSet = new Set(seed2.checkedIds ?? []);
|
|
16412
15978
|
this.hiddenSet = new Set(seed2.hiddenIds ?? []);
|
|
15979
|
+
this.activeFilter = null;
|
|
15980
|
+
this.activeOrder = null;
|
|
16413
15981
|
}
|
|
16414
15982
|
snapshot() {
|
|
16415
15983
|
return {
|
|
16416
15984
|
checked: new Set(this.checkedSet),
|
|
16417
|
-
hidden: new Set(this.hiddenSet)
|
|
15985
|
+
hidden: new Set(this.hiddenSet),
|
|
15986
|
+
activeFilter: this.activeFilter,
|
|
15987
|
+
activeOrder: this.activeOrder
|
|
16418
15988
|
};
|
|
16419
15989
|
}
|
|
16420
15990
|
restore(snapshot) {
|
|
16421
15991
|
this.checkedSet = new Set(snapshot.checked);
|
|
16422
15992
|
this.hiddenSet = new Set(snapshot.hidden);
|
|
15993
|
+
this.activeFilter = snapshot.activeFilter;
|
|
15994
|
+
this.activeOrder = snapshot.activeOrder;
|
|
16423
15995
|
}
|
|
16424
15996
|
};
|
|
16425
15997
|
|
|
16426
15998
|
// src/internal/state/schedule-state.ts
|
|
16427
15999
|
var ScheduleState = class {
|
|
16428
|
-
// Private so every mutation routes through setActivityField/addActivity/…
|
|
16429
|
-
// (the only path that feeds the write-capture → ChangeSet). External readers
|
|
16430
|
-
// use the AutoSchedulerPort read methods (getActivity / getAllActivities / …).
|
|
16431
16000
|
_activities = /* @__PURE__ */ new Map();
|
|
16432
|
-
// Transient gesture state: the start_date an activity had at its last
|
|
16433
|
-
// duration edit / drag. Read only by the no-op constraint revert to decide
|
|
16434
|
-
// whether a soft constraint repositioned the activity. Never persisted,
|
|
16435
|
-
// never in the ChangeSet — not domain data on CoreActivity.
|
|
16436
16001
|
_lastStartDate = /* @__PURE__ */ new Map();
|
|
16437
|
-
// Transient gesture state: what a leaf looked like right before it gained its
|
|
16438
|
-
// first child and became a summary. Read by the demotion to give the activity
|
|
16439
|
-
// its own values back instead of the aggregate its children left behind. Not
|
|
16440
|
-
// persisted and not in the ChangeSet: it only makes sense inside the session
|
|
16441
|
-
// that performed the promotion. Kept (not consumed) so undo/redo of a
|
|
16442
|
-
// demotion restores identically every time.
|
|
16443
16002
|
_promotionSnapshot = /* @__PURE__ */ new Map();
|
|
16444
16003
|
_links = /* @__PURE__ */ new Map();
|
|
16445
16004
|
_outgoing = /* @__PURE__ */ new Map();
|
|
16446
16005
|
_incoming = /* @__PURE__ */ new Map();
|
|
16447
|
-
// Parent → children index. Assigned in the constructor (needs the
|
|
16448
|
-
// activities Map reference). See `HierarchyIndex`.
|
|
16449
16006
|
_hierarchy;
|
|
16007
|
+
_buildOrderComparator;
|
|
16450
16008
|
_cache = {
|
|
16451
16009
|
ids: null,
|
|
16452
|
-
visualOrderIds: null
|
|
16010
|
+
visualOrderIds: null,
|
|
16011
|
+
orderComparator: null
|
|
16453
16012
|
};
|
|
16454
|
-
// Per-dispatch write journal. See `WriteCapture` / `ActivityWriteCapture`.
|
|
16455
16013
|
_writeCapture = new WriteCapture();
|
|
16456
16014
|
_viewState = new ViewStateStore();
|
|
16457
16015
|
_viewStateBefore = null;
|
|
16458
16016
|
_lastStartDateBefore = null;
|
|
16459
16017
|
_promotionSnapshotBefore = null;
|
|
16460
|
-
// Calendar arithmetic + in-dispatch memoization. Assigned in the
|
|
16461
|
-
// constructor once the calendar reader is built. See `CalendarCalculator`.
|
|
16462
16018
|
_calendar;
|
|
16463
16019
|
_flags;
|
|
16464
|
-
constructor(snapshot) {
|
|
16020
|
+
constructor(snapshot, buildOrderComparator = () => null) {
|
|
16021
|
+
this._buildOrderComparator = buildOrderComparator;
|
|
16465
16022
|
for (const activity of snapshot.activities) {
|
|
16466
16023
|
this._activities.set(activity.id, activity);
|
|
16467
16024
|
}
|
|
@@ -16476,22 +16033,12 @@ var ScheduleState = class {
|
|
|
16476
16033
|
this._hierarchy = new HierarchyIndex(this._activities);
|
|
16477
16034
|
this._hierarchy.rebuild();
|
|
16478
16035
|
}
|
|
16479
|
-
// -- AutoSchedulerPort: reads ------------------------------------------------
|
|
16480
|
-
/**
|
|
16481
|
-
* Materializes every alive activity. O(N) allocation.
|
|
16482
|
-
* AVOID per-frame / per-dispatch consumers — prefer `forEachActivity` /
|
|
16483
|
-
* `getAllIds` when only ids or fast field reads are needed.
|
|
16484
|
-
*/
|
|
16485
16036
|
getAllActivities() {
|
|
16486
16037
|
return Array.from(this._activities.values());
|
|
16487
16038
|
}
|
|
16488
16039
|
getAllLinks() {
|
|
16489
16040
|
return Array.from(this._links.values());
|
|
16490
16041
|
}
|
|
16491
|
-
/**
|
|
16492
|
-
* Read-only snapshot of every alive activity id. Cached and invalidated
|
|
16493
|
-
* lazily on structural mutations (add/remove/parent change).
|
|
16494
|
-
*/
|
|
16495
16042
|
getAllIds() {
|
|
16496
16043
|
if (this._cache.ids) return this._cache.ids;
|
|
16497
16044
|
this._cache.ids = Array.from(this._activities.keys());
|
|
@@ -16500,14 +16047,6 @@ var ScheduleState = class {
|
|
|
16500
16047
|
activityCount() {
|
|
16501
16048
|
return this._activities.size;
|
|
16502
16049
|
}
|
|
16503
|
-
/**
|
|
16504
|
-
* Every alive activity id in canonical DFS visual order (pre-order from
|
|
16505
|
-
* roots, siblings by `correlative_id` ASC — `iterateInVisualOrder`).
|
|
16506
|
-
* Cached like `getAllIds`; invalidated on add/remove, on `parent` /
|
|
16507
|
-
* `correlative_id` writes, and by `recomputeCorrelativeIds` (the only
|
|
16508
|
-
* order chokepoint, which mutates `correlative_id` directly on the
|
|
16509
|
-
* snapshots without going through `setActivityField`).
|
|
16510
|
-
*/
|
|
16511
16050
|
getVisualOrderIds() {
|
|
16512
16051
|
if (this._cache.visualOrderIds) return this._cache.visualOrderIds;
|
|
16513
16052
|
this._cache.visualOrderIds = iterateInVisualOrder(this).map(
|
|
@@ -16515,14 +16054,9 @@ var ScheduleState = class {
|
|
|
16515
16054
|
);
|
|
16516
16055
|
return this._cache.visualOrderIds;
|
|
16517
16056
|
}
|
|
16518
|
-
/** Drops the memoized visual order. See `getVisualOrderIds`. */
|
|
16519
16057
|
invalidateVisualOrderIds() {
|
|
16520
16058
|
this._cache.visualOrderIds = null;
|
|
16521
16059
|
}
|
|
16522
|
-
/**
|
|
16523
|
-
* Iterates every alive activity without materializing intermediate arrays.
|
|
16524
|
-
* Use in hot paths that today call `getAllActivities()` only to walk it.
|
|
16525
|
-
*/
|
|
16526
16060
|
forEachActivity(visit) {
|
|
16527
16061
|
for (const [id, activity] of this._activities) {
|
|
16528
16062
|
visit(activity, id);
|
|
@@ -16575,6 +16109,9 @@ var ScheduleState = class {
|
|
|
16575
16109
|
checkedIds() {
|
|
16576
16110
|
return this._viewState.checkedIds();
|
|
16577
16111
|
}
|
|
16112
|
+
hiddenIds() {
|
|
16113
|
+
return this._viewState.hiddenIds();
|
|
16114
|
+
}
|
|
16578
16115
|
setChecked(activityId, nextChecked) {
|
|
16579
16116
|
this._captureViewStateOnce();
|
|
16580
16117
|
return this._viewState.setChecked(String(activityId), nextChecked);
|
|
@@ -16583,8 +16120,54 @@ var ScheduleState = class {
|
|
|
16583
16120
|
this._captureViewStateOnce();
|
|
16584
16121
|
return this._viewState.setVisible(String(activityId), nextVisible);
|
|
16585
16122
|
}
|
|
16123
|
+
getActiveFilter() {
|
|
16124
|
+
return this._viewState.getActiveFilter();
|
|
16125
|
+
}
|
|
16126
|
+
setActiveFilter(nextFilter) {
|
|
16127
|
+
this._captureViewStateOnce();
|
|
16128
|
+
this._viewState.setActiveFilter(nextFilter);
|
|
16129
|
+
}
|
|
16130
|
+
getActiveOrder() {
|
|
16131
|
+
return this._viewState.getActiveOrder();
|
|
16132
|
+
}
|
|
16133
|
+
setActiveOrder(nextOrder) {
|
|
16134
|
+
this._captureViewStateOnce();
|
|
16135
|
+
this._viewState.setActiveOrder(nextOrder);
|
|
16136
|
+
this.invalidateDerivedOrder();
|
|
16137
|
+
}
|
|
16138
|
+
/**
|
|
16139
|
+
* Rebuild-on-demand, memoized: at most one build per invalidation, never one
|
|
16140
|
+
* per comparison. getChildrenInVisualOrder asks for this once and then sorts a
|
|
16141
|
+
* whole sibling group with it, and collectBranchOrder walks every branch, so a
|
|
16142
|
+
* build per read would be thousands per dispatch.
|
|
16143
|
+
*
|
|
16144
|
+
* The factory reads hoursPerDay and the collation locale at build time, so a
|
|
16145
|
+
* rebuilt comparator always reflects the current context — that is what keeps
|
|
16146
|
+
* ordering and filtering from seeing two different hoursPerDay.
|
|
16147
|
+
*/
|
|
16148
|
+
getOrderComparator() {
|
|
16149
|
+
const activeOrder = this._viewState.getActiveOrder();
|
|
16150
|
+
if (activeOrder === null) {
|
|
16151
|
+
this._cache.orderComparator = null;
|
|
16152
|
+
return null;
|
|
16153
|
+
}
|
|
16154
|
+
if (this._cache.orderComparator) return this._cache.orderComparator;
|
|
16155
|
+
this._cache.orderComparator = this._buildOrderComparator(activeOrder);
|
|
16156
|
+
return this._cache.orderComparator;
|
|
16157
|
+
}
|
|
16158
|
+
/**
|
|
16159
|
+
* Both order caches, always together. The comparator decides the sequence, so
|
|
16160
|
+
* a rebuilt comparator with a surviving sequence would paint the old order.
|
|
16161
|
+
* invalidateVisualOrderIds stays separate on purpose: a structural change
|
|
16162
|
+
* moves rows without touching the rules, so the comparator is still valid.
|
|
16163
|
+
*/
|
|
16164
|
+
invalidateDerivedOrder() {
|
|
16165
|
+
this._cache.orderComparator = null;
|
|
16166
|
+
this._cache.visualOrderIds = null;
|
|
16167
|
+
}
|
|
16586
16168
|
hydrateViewState(seed2) {
|
|
16587
16169
|
this._viewState.hydrate(seed2);
|
|
16170
|
+
this.invalidateDerivedOrder();
|
|
16588
16171
|
}
|
|
16589
16172
|
_captureViewStateOnce() {
|
|
16590
16173
|
if (this._writeCapture.peek() === null) return;
|
|
@@ -16598,7 +16181,6 @@ var ScheduleState = class {
|
|
|
16598
16181
|
getIncomingLinkIds(activityId) {
|
|
16599
16182
|
return this._incoming.get(String(activityId)) ?? EMPTY_LINK_IDS;
|
|
16600
16183
|
}
|
|
16601
|
-
// -- AutoSchedulerPort: hierarchy --------------------------------------------
|
|
16602
16184
|
getChildren(parentId) {
|
|
16603
16185
|
return this._hierarchy.getChildren(parentId);
|
|
16604
16186
|
}
|
|
@@ -16614,7 +16196,6 @@ var ScheduleState = class {
|
|
|
16614
16196
|
getRootIds() {
|
|
16615
16197
|
return this._hierarchy.getRootIds();
|
|
16616
16198
|
}
|
|
16617
|
-
// -- AutoSchedulerPort: calendar (snapshot-aware, M-F 08-16 UTC fallback) ---
|
|
16618
16199
|
getClosestWorkTime(params) {
|
|
16619
16200
|
return this._calendar.getClosestWorkTime(params);
|
|
16620
16201
|
}
|
|
@@ -16624,66 +16205,44 @@ var ScheduleState = class {
|
|
|
16624
16205
|
calculateDuration(params) {
|
|
16625
16206
|
return this._calendar.calculateDuration(params);
|
|
16626
16207
|
}
|
|
16627
|
-
/**
|
|
16628
|
-
* Clears the in-dispatch calendar API memoization. Call at the start of
|
|
16629
|
-
* every scheduler run (calendars are immutable within a dispatch but may
|
|
16630
|
-
* change across dispatches).
|
|
16631
|
-
*/
|
|
16632
16208
|
clearCalendarCache() {
|
|
16633
16209
|
this._calendar.clearCache();
|
|
16634
16210
|
}
|
|
16635
|
-
// Calendar resolver exposed for external consumers (initial-passes'
|
|
16636
|
-
// expected_progress, adjust-link-lag, pipeline-context). The single owner is
|
|
16637
|
-
// `_calendar`; this getter just delegates.
|
|
16638
16211
|
get calendarReader() {
|
|
16639
16212
|
return this._calendar.reader;
|
|
16640
16213
|
}
|
|
16641
|
-
// -- AutoSchedulerPort: mutations --------------------------------------------
|
|
16642
16214
|
batchUpdate(runMutations) {
|
|
16643
16215
|
runMutations();
|
|
16644
16216
|
}
|
|
16645
|
-
/**
|
|
16646
|
-
* Part of the `AutoSchedulerPort` port (live caller: `applyResults`). No-op
|
|
16647
|
-
* here because activities mutate in place via `getLiveActivity`; only a
|
|
16648
|
-
* DHTMLX-backed adapter needs this to trigger a re-render.
|
|
16649
|
-
*/
|
|
16650
16217
|
updateActivity(_id) {
|
|
16651
16218
|
}
|
|
16652
16219
|
getLiveActivity(activityId) {
|
|
16653
16220
|
return this.getActivity(activityId);
|
|
16654
16221
|
}
|
|
16655
|
-
// -- AutoSchedulerPort: flags / config ---------------------------------------
|
|
16656
16222
|
getFlags() {
|
|
16657
16223
|
return {
|
|
16658
16224
|
...this._flags,
|
|
16659
16225
|
allCheckedTaskIds: this._viewState.checkedIds()
|
|
16660
16226
|
};
|
|
16661
16227
|
}
|
|
16662
|
-
// Backend ships no project-level dates, so this is always null in
|
|
16663
|
-
// production. The ALAP root-boundary branch that reads it stays dormant.
|
|
16664
16228
|
getProjectEnd() {
|
|
16665
16229
|
return null;
|
|
16666
16230
|
}
|
|
16667
|
-
// -- Write capture (per-dispatch journal) --------------------------------
|
|
16668
|
-
/** Start recording every `setActivityField` write of the current dispatch. */
|
|
16669
16231
|
beginWriteCapture() {
|
|
16670
16232
|
this._writeCapture.begin();
|
|
16671
16233
|
this._viewStateBefore = null;
|
|
16672
16234
|
this._lastStartDateBefore = null;
|
|
16673
16235
|
this._promotionSnapshotBefore = null;
|
|
16674
16236
|
}
|
|
16675
|
-
/** The live journal, or null when no capture is active. */
|
|
16676
16237
|
peekWriteCapture() {
|
|
16677
16238
|
return this._writeCapture.peek();
|
|
16678
16239
|
}
|
|
16679
|
-
/** Stop and discard the current dispatch's write journal. */
|
|
16680
16240
|
endWriteCapture() {
|
|
16681
16241
|
this._writeCapture.end();
|
|
16682
16242
|
this._viewStateBefore = null;
|
|
16683
16243
|
this._lastStartDateBefore = null;
|
|
16684
16244
|
this._promotionSnapshotBefore = null;
|
|
16685
16245
|
}
|
|
16686
|
-
// -- Replay-specific mutators --------------------------------------------
|
|
16687
16246
|
setActivityField(activityId, field, value) {
|
|
16688
16247
|
const activity = this.getActivity(activityId);
|
|
16689
16248
|
if (!activity) return;
|
|
@@ -16749,11 +16308,6 @@ var ScheduleState = class {
|
|
|
16749
16308
|
this._writeCapture.noteLinkField(String(linkId), link);
|
|
16750
16309
|
Reflect.set(link, field, value);
|
|
16751
16310
|
}
|
|
16752
|
-
/**
|
|
16753
|
-
* Applies the backend identity returned after a successful persistence
|
|
16754
|
-
* request. `proplannerId` is deliberately not a regular editable link field:
|
|
16755
|
-
* it is boundary-owned identity and must never enter link-update/undo logic.
|
|
16756
|
-
*/
|
|
16757
16311
|
setLinkProplannerId(linkId, proplannerId) {
|
|
16758
16312
|
const link = this.getLink(linkId);
|
|
16759
16313
|
if (!link) return;
|
|
@@ -16793,28 +16347,9 @@ var ScheduleState = class {
|
|
|
16793
16347
|
this._cache.visualOrderIds = null;
|
|
16794
16348
|
this._hierarchy.markDirty();
|
|
16795
16349
|
}
|
|
16796
|
-
/**
|
|
16797
|
-
* Transactional rollback: invert every journaled mutation so the store returns
|
|
16798
|
-
* to its pre-dispatch state. Consumed by the facade on a failed dispatch,
|
|
16799
|
-
* BEFORE `endWriteCapture` discards the journal. Reverse-chronological replay,
|
|
16800
|
-
* bucketed in the dependency order the red-team fixed (endpoints before links,
|
|
16801
|
-
* re-inserts before re-adds). All writes are DIRECT (never through the
|
|
16802
|
-
* journaling mutators) so the rollback does not re-journal itself. O(touched).
|
|
16803
|
-
*
|
|
16804
|
-
* NOTE: covers everything routed through setActivityField + the structural
|
|
16805
|
-
* mutators (the whole handler phase). The autoscheduler's `applyResults` date
|
|
16806
|
-
* writes bypass the journal and are not yet reverted here (transaction plan
|
|
16807
|
-
* Stage 4) — a create that throws AFTER autoschedule leaves those dates, which
|
|
16808
|
-
* is still strictly less corrupt than today's no-rollback.
|
|
16809
|
-
*/
|
|
16810
|
-
/** Pre-sweep correlative_id of an activity the renumbering shifted. Journaled
|
|
16811
|
-
* separately (the sweep bypasses setActivityField) so rollback can revert it. */
|
|
16812
16350
|
noteCorrelativeBefore(activityId, before) {
|
|
16813
16351
|
this._writeCapture.noteCorrelativeBefore(activityId, before);
|
|
16814
16352
|
}
|
|
16815
|
-
/** Pre-applyResults clone of an activity the autoscheduler will move. Journaled
|
|
16816
|
-
* separately (applyResults bypasses setActivityField) so rollback can revert
|
|
16817
|
-
* the scheduler's date writes. */
|
|
16818
16353
|
noteScheduledBefore(activityId, current) {
|
|
16819
16354
|
this._writeCapture.noteScheduledBefore(activityId, current);
|
|
16820
16355
|
}
|
|
@@ -16832,6 +16367,7 @@ var ScheduleState = class {
|
|
|
16832
16367
|
this._restoreActivityFields(before);
|
|
16833
16368
|
if (this._viewStateBefore !== null) {
|
|
16834
16369
|
this._viewState.restore(this._viewStateBefore);
|
|
16370
|
+
this.invalidateDerivedOrder();
|
|
16835
16371
|
}
|
|
16836
16372
|
if (this._promotionSnapshotBefore !== null) {
|
|
16837
16373
|
this._promotionSnapshot = this._promotionSnapshotBefore;
|
|
@@ -16924,11 +16460,6 @@ function buildFlags(snapshot) {
|
|
|
16924
16460
|
};
|
|
16925
16461
|
}
|
|
16926
16462
|
|
|
16927
|
-
// src/shared/clone-domain-value.ts
|
|
16928
|
-
function cloneDomainValue(value) {
|
|
16929
|
-
return structuredClone(value);
|
|
16930
|
-
}
|
|
16931
|
-
|
|
16932
16463
|
// src/init/read-api.ts
|
|
16933
16464
|
function readActivity(state, id) {
|
|
16934
16465
|
const activity = state.getActivity(id);
|
|
@@ -16962,7 +16493,7 @@ function readChildrenIds(state, parentId) {
|
|
|
16962
16493
|
});
|
|
16963
16494
|
return roots;
|
|
16964
16495
|
}
|
|
16965
|
-
return
|
|
16496
|
+
return getChildrenInVisualOrder(key, state);
|
|
16966
16497
|
}
|
|
16967
16498
|
function readSelectedActivityIds(state) {
|
|
16968
16499
|
return state.checkedIds().map(String);
|
|
@@ -17020,9 +16551,6 @@ function computeProjectWorkHours(calendars) {
|
|
|
17020
16551
|
// src/internal/state/pipeline-context.ts
|
|
17021
16552
|
function buildPipelineContext(adapter, options) {
|
|
17022
16553
|
return {
|
|
17023
|
-
// Same work-calendar engine instance used by the mock adapter so both
|
|
17024
|
-
// halves of the replay (auto-scheduler + column pipelines) agree on
|
|
17025
|
-
// working-time math.
|
|
17026
16554
|
calendars: adapter.calendarReader,
|
|
17027
16555
|
hierarchy: createStateBackedHierarchyReader(adapter),
|
|
17028
16556
|
activityReader: createStateBackedActivityReader(adapter),
|
|
@@ -17039,6 +16567,21 @@ function willRunCriticalPath(action) {
|
|
|
17039
16567
|
}
|
|
17040
16568
|
|
|
17041
16569
|
// src/dispatch/undo/undo-entry.ts
|
|
16570
|
+
function buildHistoryChangeSet(changes) {
|
|
16571
|
+
const activitiesWithoutAfter = changes.activities.map((entry) => ({
|
|
16572
|
+
...entry,
|
|
16573
|
+
after: null
|
|
16574
|
+
}));
|
|
16575
|
+
const linksWithoutAfter = changes.links.map((entry) => ({
|
|
16576
|
+
...entry,
|
|
16577
|
+
after: null
|
|
16578
|
+
}));
|
|
16579
|
+
return cloneDomainValue({
|
|
16580
|
+
...changes,
|
|
16581
|
+
activities: activitiesWithoutAfter,
|
|
16582
|
+
links: linksWithoutAfter
|
|
16583
|
+
});
|
|
16584
|
+
}
|
|
17042
16585
|
function buildUndoEntry(changeSet, beforeSnap, beforeLinks, afterSnap, afterLinks) {
|
|
17043
16586
|
return { changeSet, beforeSnap, beforeLinks, afterSnap, afterLinks };
|
|
17044
16587
|
}
|
|
@@ -17094,7 +16637,7 @@ function mergeCoalesced(top, next) {
|
|
|
17094
16637
|
}
|
|
17095
16638
|
function getDispatchHistoryPolicy(action) {
|
|
17096
16639
|
if (action.kind === "persistence-acknowledge") return "clear-on-success";
|
|
17097
|
-
if (action.kind === "sir-sync" || action.kind === "activity-lookahead-sync" || action.kind === "baseline-apply" || action.kind === "ponderator-criterion-set" || action.kind === "status-criteria-set") {
|
|
16640
|
+
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 === "selection-toggle" || action.kind === "selection-replace" || action.kind === "visibility-set" || action.kind === "filter-set" || action.kind === "sort-set") {
|
|
17098
16641
|
return "skip";
|
|
17099
16642
|
}
|
|
17100
16643
|
return "record";
|
|
@@ -17336,24 +16879,20 @@ var UndoRecorder = class {
|
|
|
17336
16879
|
redoStack = [];
|
|
17337
16880
|
_lastKey = null;
|
|
17338
16881
|
_lastTime = 0;
|
|
17339
|
-
/**
|
|
17340
|
-
* Push a forward entry; a new action invalidates the redo branch. When the
|
|
17341
|
-
* entry coalesces with the top one (same cell key, within the time window),
|
|
17342
|
-
* it merges into the top step instead of pushing a new one (decision #4).
|
|
17343
|
-
*/
|
|
17344
16882
|
record(entry, coalesceKey = null, now = 0) {
|
|
17345
16883
|
const top = this.undoStack[this.undoStack.length - 1];
|
|
17346
16884
|
if (coalesceKey != null && coalesceKey === this._lastKey && now - this._lastTime <= COALESCE_WINDOW_MS && top !== void 0 && canCoalesce(top, entry)) {
|
|
17347
16885
|
this.undoStack[this.undoStack.length - 1] = mergeCoalesced(top, entry);
|
|
17348
16886
|
} else {
|
|
17349
16887
|
this.undoStack.push(entry);
|
|
17350
|
-
if (this.undoStack.length > this.maxDepth)
|
|
16888
|
+
if (this.undoStack.length > this.maxDepth) {
|
|
16889
|
+
this.undoStack.splice(0, this.undoStack.length - this.maxDepth);
|
|
16890
|
+
}
|
|
17351
16891
|
}
|
|
17352
16892
|
this._lastKey = coalesceKey;
|
|
17353
16893
|
this._lastTime = now;
|
|
17354
16894
|
this.redoStack.length = 0;
|
|
17355
16895
|
}
|
|
17356
|
-
/** Break the coalescing chain (called on undo/redo). */
|
|
17357
16896
|
resetCoalesce() {
|
|
17358
16897
|
this._lastKey = null;
|
|
17359
16898
|
}
|
|
@@ -17385,13 +16924,48 @@ var UndoRecorder = class {
|
|
|
17385
16924
|
}
|
|
17386
16925
|
};
|
|
17387
16926
|
|
|
16927
|
+
// src/dispatch/shared/resequenced-parents.ts
|
|
16928
|
+
var POSITIONAL_FIELDS = ["parentId", "correlativeId"];
|
|
16929
|
+
function collectResequencedParents(changes, parentOf) {
|
|
16930
|
+
const touched = /* @__PURE__ */ new Set();
|
|
16931
|
+
const addParentOf = (activityId) => {
|
|
16932
|
+
const parentId = parentOf(activityId);
|
|
16933
|
+
touched.add(parentId === null ? ROOT_PARENT_ID : String(parentId));
|
|
16934
|
+
};
|
|
16935
|
+
for (const change of changes.activities) {
|
|
16936
|
+
const activityId = String(change.id);
|
|
16937
|
+
if (change.kind === "created") {
|
|
16938
|
+
addParentOf(activityId);
|
|
16939
|
+
continue;
|
|
16940
|
+
}
|
|
16941
|
+
if (change.kind === "deleted") {
|
|
16942
|
+
const deletedFields = change.fields;
|
|
16943
|
+
if (deletedFields && "parentId" in deletedFields) {
|
|
16944
|
+
touched.add(parentKeyOf2(deletedFields.parentId?.before));
|
|
16945
|
+
}
|
|
16946
|
+
continue;
|
|
16947
|
+
}
|
|
16948
|
+
const fields = change.fields;
|
|
16949
|
+
if (!fields) continue;
|
|
16950
|
+
const movedPositionally = POSITIONAL_FIELDS.some(
|
|
16951
|
+
(field) => field in fields
|
|
16952
|
+
);
|
|
16953
|
+
if (!movedPositionally) continue;
|
|
16954
|
+
addParentOf(activityId);
|
|
16955
|
+
if ("parentId" in fields) {
|
|
16956
|
+
touched.add(parentKeyOf2(fields.parentId?.before));
|
|
16957
|
+
}
|
|
16958
|
+
}
|
|
16959
|
+
return touched;
|
|
16960
|
+
}
|
|
16961
|
+
function parentKeyOf2(parentId) {
|
|
16962
|
+
if (parentId === null || parentId === void 0) return ROOT_PARENT_ID;
|
|
16963
|
+
return String(parentId);
|
|
16964
|
+
}
|
|
16965
|
+
|
|
17388
16966
|
// src/init/build-state-snapshot.ts
|
|
17389
16967
|
function buildStoreLink(link) {
|
|
17390
16968
|
return {
|
|
17391
|
-
// Spread first to preserve passthrough backend fields (proplannerId,
|
|
17392
|
-
// ganttId, sectorId) through the snapshot — dropping proplannerId here was
|
|
17393
|
-
// a bug: the core lost each link's backend id, so save dirty-detection and
|
|
17394
|
-
// the DHTMLX adapter could not tell persisted links from new ones.
|
|
17395
16969
|
...link,
|
|
17396
16970
|
id: String(link.id),
|
|
17397
16971
|
source: String(link.source),
|
|
@@ -17404,11 +16978,6 @@ function serializeWorktime(worktime) {
|
|
|
17404
16978
|
return {
|
|
17405
16979
|
days: worktime.days,
|
|
17406
16980
|
hours: worktime.hours,
|
|
17407
|
-
// Preserve per-date overrides (holidays + workday shift exceptions)
|
|
17408
|
-
// through the snapshot so the work-calendar engine sees them when
|
|
17409
|
-
// the state hydrates. Dropping these here was the bug that made
|
|
17410
|
-
// multi-shift / exception-day calendars snap to wrong hours after
|
|
17411
|
-
// every edit.
|
|
17412
16981
|
...worktime.dates ? { dates: worktime.dates } : {},
|
|
17413
16982
|
...worktime.customWeeks ? { customWeeks: worktime.customWeeks } : {}
|
|
17414
16983
|
};
|
|
@@ -17525,13 +17094,11 @@ var SaveTracker = class {
|
|
|
17525
17094
|
initialized = false;
|
|
17526
17095
|
linksAtLastSave = /* @__PURE__ */ new Map();
|
|
17527
17096
|
activitiesAtLastSave = /* @__PURE__ */ new Map();
|
|
17528
|
-
/** Take the initial snapshot once (after the autoscheduler settles). */
|
|
17529
17097
|
init(activities, links) {
|
|
17530
17098
|
this.snapshotActivities(activities);
|
|
17531
17099
|
this.snapshotLinks(links);
|
|
17532
17100
|
this.initialized = true;
|
|
17533
17101
|
}
|
|
17534
|
-
/** Re-snapshot activities (call after a save persists them). */
|
|
17535
17102
|
snapshotActivities(activities) {
|
|
17536
17103
|
this.activitiesAtLastSave.clear();
|
|
17537
17104
|
for (const activity of activities) {
|
|
@@ -17542,7 +17109,6 @@ var SaveTracker = class {
|
|
|
17542
17109
|
);
|
|
17543
17110
|
}
|
|
17544
17111
|
}
|
|
17545
|
-
/** Re-snapshot links (call after a save persists them). */
|
|
17546
17112
|
snapshotLinks(links) {
|
|
17547
17113
|
this.linksAtLastSave.clear();
|
|
17548
17114
|
for (const link of links) {
|
|
@@ -17553,7 +17119,6 @@ var SaveTracker = class {
|
|
|
17553
17119
|
});
|
|
17554
17120
|
}
|
|
17555
17121
|
}
|
|
17556
|
-
/** Persisted activities whose value changed since the last snapshot. */
|
|
17557
17122
|
modifiedActivities(activities) {
|
|
17558
17123
|
if (!this.initialized) return [];
|
|
17559
17124
|
return activities.filter((activity) => {
|
|
@@ -17564,7 +17129,6 @@ var SaveTracker = class {
|
|
|
17564
17129
|
return activityChangedSince(activity, saved);
|
|
17565
17130
|
});
|
|
17566
17131
|
}
|
|
17567
|
-
/** Persisted links whose `lag`/`type` changed since the last snapshot. */
|
|
17568
17132
|
modifiedLinks(links) {
|
|
17569
17133
|
if (!this.initialized) return [];
|
|
17570
17134
|
return links.filter((link) => {
|
|
@@ -17574,7 +17138,6 @@ var SaveTracker = class {
|
|
|
17574
17138
|
return link.lag !== saved.lag || link.type !== saved.type;
|
|
17575
17139
|
});
|
|
17576
17140
|
}
|
|
17577
|
-
/** Drop both mirrors (teardown). */
|
|
17578
17141
|
clear() {
|
|
17579
17142
|
this.linksAtLastSave.clear();
|
|
17580
17143
|
this.activitiesAtLastSave.clear();
|
|
@@ -18344,35 +17907,58 @@ function cloneStats(stats) {
|
|
|
18344
17907
|
var CustomIdTracker = class {
|
|
18345
17908
|
prefixMap = /* @__PURE__ */ new Map();
|
|
18346
17909
|
processedIds = /* @__PURE__ */ new Set();
|
|
18347
|
-
|
|
17910
|
+
_journalPrefixBefore = null;
|
|
17911
|
+
_journalIds = null;
|
|
18348
17912
|
beginCustomIdTransaction() {
|
|
18349
|
-
this.
|
|
17913
|
+
this._journalPrefixBefore = /* @__PURE__ */ new Map();
|
|
17914
|
+
this._journalIds = [];
|
|
18350
17915
|
}
|
|
18351
17916
|
commitCustomIdTransaction() {
|
|
18352
|
-
this.
|
|
17917
|
+
this._journalPrefixBefore = null;
|
|
17918
|
+
this._journalIds = null;
|
|
18353
17919
|
}
|
|
18354
17920
|
rollbackCustomIdTransaction() {
|
|
18355
|
-
const
|
|
18356
|
-
|
|
18357
|
-
|
|
18358
|
-
|
|
18359
|
-
if (
|
|
18360
|
-
else this.prefixMap.set(prefix,
|
|
17921
|
+
const prefixBeforeByPrefix = this._journalPrefixBefore;
|
|
17922
|
+
const journaledIds = this._journalIds;
|
|
17923
|
+
if (prefixBeforeByPrefix === null || journaledIds === null) return;
|
|
17924
|
+
for (const [prefix, statsBefore] of prefixBeforeByPrefix) {
|
|
17925
|
+
if (statsBefore === null) this.prefixMap.delete(prefix);
|
|
17926
|
+
else this.prefixMap.set(prefix, statsBefore);
|
|
17927
|
+
}
|
|
17928
|
+
for (const entry of [...journaledIds].reverse()) {
|
|
18361
17929
|
if (entry.hadId) this.processedIds.add(entry.customId);
|
|
18362
17930
|
else this.processedIds.delete(entry.customId);
|
|
18363
17931
|
}
|
|
18364
|
-
this.
|
|
17932
|
+
this._journalPrefixBefore = null;
|
|
17933
|
+
this._journalIds = null;
|
|
18365
17934
|
}
|
|
18366
17935
|
_noteCustomIdBefore(customId) {
|
|
18367
|
-
if (this.
|
|
17936
|
+
if (this._journalPrefixBefore === null || this._journalIds === null) {
|
|
17937
|
+
return;
|
|
17938
|
+
}
|
|
18368
17939
|
const { prefix } = this.analyzeCustomId(customId);
|
|
18369
|
-
|
|
18370
|
-
|
|
17940
|
+
if (!this._journalPrefixBefore.has(prefix)) {
|
|
17941
|
+
const current = this.prefixMap.get(prefix);
|
|
17942
|
+
this._journalPrefixBefore.set(
|
|
17943
|
+
prefix,
|
|
17944
|
+
current ? cloneStats(current) : null
|
|
17945
|
+
);
|
|
17946
|
+
}
|
|
17947
|
+
this._journalIds.push({
|
|
18371
17948
|
customId,
|
|
18372
|
-
prefixBefore: current ? cloneStats(current) : null,
|
|
18373
17949
|
hadId: this.processedIds.has(customId)
|
|
18374
17950
|
});
|
|
18375
17951
|
}
|
|
17952
|
+
_ensureFreshBounds(prefix) {
|
|
17953
|
+
const stats = this.prefixMap.get(prefix);
|
|
17954
|
+
if (!stats?.boundsDirty) return;
|
|
17955
|
+
stats.boundsDirty = false;
|
|
17956
|
+
const remaining = Array.from(stats.usedSuffixes);
|
|
17957
|
+
stats.min = minSuffixFromArray(remaining);
|
|
17958
|
+
stats.max = maxSuffixFromArray(remaining);
|
|
17959
|
+
stats.quantity = remaining.length;
|
|
17960
|
+
this._recalculateNext(prefix);
|
|
17961
|
+
}
|
|
18376
17962
|
defaultPrefix;
|
|
18377
17963
|
suffixIncrement;
|
|
18378
17964
|
constructor(options = {}) {
|
|
@@ -18392,6 +17978,7 @@ var CustomIdTracker = class {
|
|
|
18392
17978
|
};
|
|
18393
17979
|
}
|
|
18394
17980
|
_updatePrefixStats(prefix, suffix) {
|
|
17981
|
+
this._ensureFreshBounds(prefix);
|
|
18395
17982
|
if (!this.prefixMap.has(prefix)) {
|
|
18396
17983
|
this.prefixMap.set(prefix, {
|
|
18397
17984
|
min: suffix,
|
|
@@ -18418,6 +18005,7 @@ var CustomIdTracker = class {
|
|
|
18418
18005
|
stats.next = next ?? this.suffixIncrement;
|
|
18419
18006
|
}
|
|
18420
18007
|
getPrefixStats(prefix) {
|
|
18008
|
+
this._ensureFreshBounds(prefix);
|
|
18421
18009
|
const stats = this.prefixMap.get(prefix);
|
|
18422
18010
|
if (!stats) return null;
|
|
18423
18011
|
return {
|
|
@@ -18428,6 +18016,7 @@ var CustomIdTracker = class {
|
|
|
18428
18016
|
};
|
|
18429
18017
|
}
|
|
18430
18018
|
getNextSuffix(prefix) {
|
|
18019
|
+
this._ensureFreshBounds(prefix);
|
|
18431
18020
|
const stats = this.prefixMap.get(prefix);
|
|
18432
18021
|
return stats ? stats.next : this.suffixIncrement;
|
|
18433
18022
|
}
|
|
@@ -18441,6 +18030,7 @@ var CustomIdTracker = class {
|
|
|
18441
18030
|
const { prefix, suffix } = this.analyzeCustomId(customId);
|
|
18442
18031
|
if (!prefix && !suffix) return { prefix, suffix };
|
|
18443
18032
|
this._noteCustomIdBefore(customId);
|
|
18033
|
+
this._ensureFreshBounds(prefix);
|
|
18444
18034
|
if (this.prefixMap.has(prefix)) {
|
|
18445
18035
|
const stats = this.prefixMap.get(prefix);
|
|
18446
18036
|
if (!stats.usedSuffixes.has(suffix)) {
|
|
@@ -18471,22 +18061,12 @@ var CustomIdTracker = class {
|
|
|
18471
18061
|
this._noteCustomIdBefore(customId);
|
|
18472
18062
|
const currentStats = this.prefixMap.get(prefix);
|
|
18473
18063
|
if (currentStats.usedSuffixes.has(suffix)) {
|
|
18474
|
-
|
|
18475
|
-
|
|
18064
|
+
currentStats.usedSuffixes.delete(suffix);
|
|
18065
|
+
currentStats.quantity -= 1;
|
|
18066
|
+
if (currentStats.usedSuffixes.size === 0) {
|
|
18476
18067
|
this.prefixMap.delete(prefix);
|
|
18477
18068
|
} else {
|
|
18478
|
-
|
|
18479
|
-
newUsed.delete(suffix);
|
|
18480
|
-
const remaining = Array.from(newUsed);
|
|
18481
|
-
if (remaining.length === 0) {
|
|
18482
|
-
this.prefixMap.delete(prefix);
|
|
18483
|
-
} else {
|
|
18484
|
-
currentStats.usedSuffixes = newUsed;
|
|
18485
|
-
currentStats.min = minSuffixFromArray(remaining);
|
|
18486
|
-
currentStats.max = maxSuffixFromArray(remaining);
|
|
18487
|
-
currentStats.quantity = newQuantity;
|
|
18488
|
-
this._recalculateNext(prefix);
|
|
18489
|
-
}
|
|
18069
|
+
currentStats.boundsDirty = true;
|
|
18490
18070
|
}
|
|
18491
18071
|
}
|
|
18492
18072
|
this.processedIds.delete(customId);
|
|
@@ -18506,12 +18086,19 @@ var CustomIdTracker = class {
|
|
|
18506
18086
|
return customId.length > MAX_CUSTOM_ID_LENGTH;
|
|
18507
18087
|
}
|
|
18508
18088
|
_shouldSearchForGaps(prefix) {
|
|
18089
|
+
this._ensureFreshBounds(prefix);
|
|
18509
18090
|
if (!this.prefixMap.has(prefix)) return false;
|
|
18510
18091
|
const stats = this.prefixMap.get(prefix);
|
|
18511
18092
|
const nextWouldBe = `${prefix}${addToSuffix(stats.max, this.suffixIncrement)}`;
|
|
18512
18093
|
return nextWouldBe.length > MAX_CUSTOM_ID_LENGTH;
|
|
18513
18094
|
}
|
|
18095
|
+
_suffixForUnknownPrefix(prefix, baseSuffix) {
|
|
18096
|
+
const candidate = baseSuffix && isValidSuffix(baseSuffix) ? baseSuffix : this.suffixIncrement;
|
|
18097
|
+
if (`${prefix}${candidate}`.length > MAX_CUSTOM_ID_LENGTH) return null;
|
|
18098
|
+
return candidate;
|
|
18099
|
+
}
|
|
18514
18100
|
_findFirstAvailableGap(prefix) {
|
|
18101
|
+
this._ensureFreshBounds(prefix);
|
|
18515
18102
|
if (!this.prefixMap.has(prefix)) return null;
|
|
18516
18103
|
const stats = this.prefixMap.get(prefix);
|
|
18517
18104
|
let candidate = this.suffixIncrement;
|
|
@@ -18535,10 +18122,9 @@ var CustomIdTracker = class {
|
|
|
18535
18122
|
return `${this.defaultPrefix}${nextSuffix}`;
|
|
18536
18123
|
}
|
|
18537
18124
|
getNextAvailableSuffix(prefix, baseSuffix = null) {
|
|
18125
|
+
this._ensureFreshBounds(prefix);
|
|
18538
18126
|
if (!this.prefixMap.has(prefix)) {
|
|
18539
|
-
|
|
18540
|
-
if (`${prefix}${candidate2}`.length > MAX_CUSTOM_ID_LENGTH) return null;
|
|
18541
|
-
return candidate2;
|
|
18127
|
+
return this._suffixForUnknownPrefix(prefix, baseSuffix);
|
|
18542
18128
|
}
|
|
18543
18129
|
const stats = this.prefixMap.get(prefix);
|
|
18544
18130
|
const step = this.suffixIncrement;
|
|
@@ -18579,9 +18165,6 @@ var CustomIdTracker = class {
|
|
|
18579
18165
|
}
|
|
18580
18166
|
return generatedId;
|
|
18581
18167
|
}
|
|
18582
|
-
/**
|
|
18583
|
-
* Seed the tracker from an array of activities. Idempotent.
|
|
18584
|
-
*/
|
|
18585
18168
|
populateFromActivities(activities) {
|
|
18586
18169
|
if (!Array.isArray(activities)) return this;
|
|
18587
18170
|
const uniqueCustomIds = [
|
|
@@ -18602,14 +18185,6 @@ var CustomIdTracker = class {
|
|
|
18602
18185
|
getDefaults() {
|
|
18603
18186
|
return { prefix: this.defaultPrefix, increment: this.suffixIncrement };
|
|
18604
18187
|
}
|
|
18605
|
-
/**
|
|
18606
|
-
* Generates a custom ID for a new child activity.
|
|
18607
|
-
*
|
|
18608
|
-
* Three strategies (see `selectGenerationStrategy`):
|
|
18609
|
-
* - parentConversion: parent has customId → release it, child uses defaults.
|
|
18610
|
-
* - pasteReference: reference has customId → use its prefix + suffix as base.
|
|
18611
|
-
* - noContext: no reference → use defaults.
|
|
18612
|
-
*/
|
|
18613
18188
|
generateCustomIdForNewChild(params) {
|
|
18614
18189
|
const { activity, useActivityCustomIdAsReference = false } = params;
|
|
18615
18190
|
const customId = getCustomIdFromActivity(activity);
|
|
@@ -18623,6 +18198,7 @@ var CustomIdTracker = class {
|
|
|
18623
18198
|
);
|
|
18624
18199
|
let capturedNextSuffix = null;
|
|
18625
18200
|
if (strategyKey === "parentConversion" && this.prefixMap.has(prefix)) {
|
|
18201
|
+
this._ensureFreshBounds(prefix);
|
|
18626
18202
|
const currentMax = this.prefixMap.get(prefix).max;
|
|
18627
18203
|
capturedNextSuffix = addToSuffix(currentMax, this.suffixIncrement);
|
|
18628
18204
|
}
|
|
@@ -18653,11 +18229,6 @@ var CustomIdTracker = class {
|
|
|
18653
18229
|
return noContextStrategy(this.defaultPrefix);
|
|
18654
18230
|
}
|
|
18655
18231
|
}
|
|
18656
|
-
/**
|
|
18657
|
-
* Generates customId for parent-to-child conversion after outdent demote.
|
|
18658
|
-
* If `siblingCustomId` is provided, follows its pattern (prefix + next
|
|
18659
|
-
* suffix). Otherwise uses defaults.
|
|
18660
|
-
*/
|
|
18661
18232
|
generateCustomIdForRestoredChild(siblingCustomId = null) {
|
|
18662
18233
|
if (siblingCustomId) {
|
|
18663
18234
|
const trimmed = siblingCustomId.trim();
|
|
@@ -18693,11 +18264,6 @@ var CustomIdTracker = class {
|
|
|
18693
18264
|
hasPrefix(prefix) {
|
|
18694
18265
|
return this.prefixMap.has(prefix);
|
|
18695
18266
|
}
|
|
18696
|
-
/**
|
|
18697
|
-
* O(1) check — used by inline-edit to validate "no duplicate". When
|
|
18698
|
-
* `currentCustomId` is passed, returns false if the new value matches
|
|
18699
|
-
* (no-op edit). Used by the dispatch's `customIdPipeline.validate`.
|
|
18700
|
-
*/
|
|
18701
18267
|
isCustomIdInUse(customId, currentCustomId = null) {
|
|
18702
18268
|
if (!customId || typeof customId !== "string" || !customId.trim()) {
|
|
18703
18269
|
return false;
|
|
@@ -18710,6 +18276,65 @@ var CustomIdTracker = class {
|
|
|
18710
18276
|
}
|
|
18711
18277
|
};
|
|
18712
18278
|
|
|
18279
|
+
// src/internal/order/build-comparator.ts
|
|
18280
|
+
var MISSING_LAST = 1;
|
|
18281
|
+
var MISSING_FIRST = -1;
|
|
18282
|
+
function compareMissing(aMissing, bMissing) {
|
|
18283
|
+
if (!aMissing && !bMissing) return null;
|
|
18284
|
+
if (aMissing && bMissing) return 0;
|
|
18285
|
+
return aMissing ? MISSING_LAST : MISSING_FIRST;
|
|
18286
|
+
}
|
|
18287
|
+
function isMissing(value) {
|
|
18288
|
+
return value === null || value === void 0;
|
|
18289
|
+
}
|
|
18290
|
+
function enumRank(value, order) {
|
|
18291
|
+
const index = order.indexOf(String(value));
|
|
18292
|
+
return index === -1 ? order.length : index;
|
|
18293
|
+
}
|
|
18294
|
+
function compareValues(a, b, locale) {
|
|
18295
|
+
if (a instanceof Date && b instanceof Date) {
|
|
18296
|
+
return a.getTime() - b.getTime();
|
|
18297
|
+
}
|
|
18298
|
+
if (typeof a === "number" && typeof b === "number") {
|
|
18299
|
+
return a - b;
|
|
18300
|
+
}
|
|
18301
|
+
if (typeof a === "boolean" && typeof b === "boolean") {
|
|
18302
|
+
return Number(a) - Number(b);
|
|
18303
|
+
}
|
|
18304
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
18305
|
+
return a.length - b.length;
|
|
18306
|
+
}
|
|
18307
|
+
return String(a).localeCompare(String(b), locale, {
|
|
18308
|
+
sensitivity: "base",
|
|
18309
|
+
numeric: true
|
|
18310
|
+
});
|
|
18311
|
+
}
|
|
18312
|
+
function compareByRule(rule, context) {
|
|
18313
|
+
const descriptor = getFieldDescriptor(rule.field);
|
|
18314
|
+
if (descriptor === null) return null;
|
|
18315
|
+
return (a, b) => {
|
|
18316
|
+
const valueA = descriptor.extract(a, context);
|
|
18317
|
+
const valueB = descriptor.extract(b, context);
|
|
18318
|
+
const missing = compareMissing(isMissing(valueA), isMissing(valueB));
|
|
18319
|
+
if (missing !== null) return missing;
|
|
18320
|
+
const result = descriptor.valueKind === "enum" ? enumRank(valueA, descriptor.order) - enumRank(valueB, descriptor.order) : compareValues(valueA, valueB, context.locale);
|
|
18321
|
+
return rule.direction === "desc" ? -result : result;
|
|
18322
|
+
};
|
|
18323
|
+
}
|
|
18324
|
+
function buildComparator(order, context) {
|
|
18325
|
+
const comparators = order.rules.map((rule) => compareByRule(rule, context)).filter(
|
|
18326
|
+
(comparator) => comparator !== null
|
|
18327
|
+
);
|
|
18328
|
+
if (comparators.length === 0) return null;
|
|
18329
|
+
return (a, b) => {
|
|
18330
|
+
for (const comparator of comparators) {
|
|
18331
|
+
const result = comparator(a, b);
|
|
18332
|
+
if (result !== 0) return result;
|
|
18333
|
+
}
|
|
18334
|
+
return 0;
|
|
18335
|
+
};
|
|
18336
|
+
}
|
|
18337
|
+
|
|
18713
18338
|
// src/internal/post-processors/demote-childless-summaries.ts
|
|
18714
18339
|
function demoteChildlessSummaries(state) {
|
|
18715
18340
|
const idsToDemote = [];
|
|
@@ -18864,8 +18489,6 @@ function normalizeMilestoneConstraintDatesForDisplay(state) {
|
|
|
18864
18489
|
var SCHEDULE_CORE_STATUS = {
|
|
18865
18490
|
READY: "ready",
|
|
18866
18491
|
DESTROYED: "destroyed",
|
|
18867
|
-
/** A rollback failed mid-restore — state may be inconsistent; the host must
|
|
18868
|
-
* reload from backend. All further dispatches are refused. */
|
|
18869
18492
|
POISONED: "poisoned"
|
|
18870
18493
|
};
|
|
18871
18494
|
function initializeCore(input) {
|
|
@@ -18892,7 +18515,8 @@ function initializeCore(input) {
|
|
|
18892
18515
|
parsed2.calendars,
|
|
18893
18516
|
baseCalendars
|
|
18894
18517
|
);
|
|
18895
|
-
const
|
|
18518
|
+
const buildOrderComparator = (order) => buildComparator(order, buildFilterContext(sector.hoursPerDay));
|
|
18519
|
+
const state = new ScheduleState(snapshot, buildOrderComparator);
|
|
18896
18520
|
state.hydrateViewState({ hiddenIds: parsed2.viewStateSeed.hiddenIds });
|
|
18897
18521
|
const scheduler = new AutoScheduler(state, reporter);
|
|
18898
18522
|
demoteChildlessSummaries(state);
|
|
@@ -18925,9 +18549,6 @@ function initializeCore(input) {
|
|
|
18925
18549
|
sector,
|
|
18926
18550
|
scheduler,
|
|
18927
18551
|
skipAutoSchedule: input.skipInitialAutoSchedule === true,
|
|
18928
|
-
// `loadNow` is rounded to end-of-local-day (legacy `calculateExpected`
|
|
18929
|
-
// parity) — the LOAD expected_progress pass. Dispatch-time recomputes call
|
|
18930
|
-
// `clock()` fresh, so a long-lived session tracks the real day.
|
|
18931
18552
|
now: loadNow ?? void 0
|
|
18932
18553
|
});
|
|
18933
18554
|
return {
|
|
@@ -19043,13 +18664,18 @@ var ScheduleCore = class {
|
|
|
19043
18664
|
this.assertReady();
|
|
19044
18665
|
return readSelectedActivityIds(this.coreRuntime.state);
|
|
19045
18666
|
}
|
|
19046
|
-
|
|
19047
|
-
|
|
19048
|
-
|
|
19049
|
-
|
|
19050
|
-
|
|
19051
|
-
|
|
19052
|
-
|
|
18667
|
+
getHiddenActivityIds() {
|
|
18668
|
+
this.assertReady();
|
|
18669
|
+
return this.coreRuntime.state.hiddenIds().map(String);
|
|
18670
|
+
}
|
|
18671
|
+
getActiveFilter() {
|
|
18672
|
+
this.assertReady();
|
|
18673
|
+
return this.coreRuntime.state.getActiveFilter();
|
|
18674
|
+
}
|
|
18675
|
+
getActiveOrder() {
|
|
18676
|
+
this.assertReady();
|
|
18677
|
+
return this.coreRuntime.state.getActiveOrder();
|
|
18678
|
+
}
|
|
19053
18679
|
getVisualOrderIds() {
|
|
19054
18680
|
this.assertReady();
|
|
19055
18681
|
return [...this.coreRuntime.state.getVisualOrderIds()];
|
|
@@ -19149,7 +18775,7 @@ var ScheduleCore = class {
|
|
|
19149
18775
|
);
|
|
19150
18776
|
this._undo.record(
|
|
19151
18777
|
buildUndoEntry(
|
|
19152
|
-
result.changes,
|
|
18778
|
+
buildHistoryChangeSet(result.changes),
|
|
19153
18779
|
result.__beforeSnap,
|
|
19154
18780
|
result.__beforeLinks,
|
|
19155
18781
|
created.afterSnap,
|
|
@@ -19166,19 +18792,13 @@ var ScheduleCore = class {
|
|
|
19166
18792
|
this._saveTracker.snapshotLinks(this.getAllLinksView());
|
|
19167
18793
|
this._undo.clear();
|
|
19168
18794
|
}
|
|
18795
|
+
result = this._withReappliedViewState(action, result);
|
|
19169
18796
|
if (!result.ok) return result;
|
|
19170
18797
|
if (dispatchChangesSchedulingState(action) && changeSetIsSubstantive(result.changes)) {
|
|
19171
18798
|
this._recordScheduleMutation(options.skipCriticalPath !== true);
|
|
19172
18799
|
}
|
|
19173
|
-
return
|
|
18800
|
+
return toPublicDispatchResult(result);
|
|
19174
18801
|
}
|
|
19175
|
-
/**
|
|
19176
|
-
* Starts or joins the Critical Path calculation for the current schedule
|
|
19177
|
-
* revision. Snapshot capture and the final commit are serialized with user
|
|
19178
|
-
* mutations, but the expensive calculation runs outside `_opQueue` against
|
|
19179
|
-
* an isolated state. A newer revision aborts this job and makes its result
|
|
19180
|
-
* ineligible to commit.
|
|
19181
|
-
*/
|
|
19182
18802
|
recomputeCriticalPath() {
|
|
19183
18803
|
const operation = this._enqueue(async () => ({
|
|
19184
18804
|
job: this._startCriticalPathForCurrentRevision()
|
|
@@ -19194,6 +18814,99 @@ var ScheduleCore = class {
|
|
|
19194
18814
|
await this.recomputeCriticalPath();
|
|
19195
18815
|
}
|
|
19196
18816
|
}
|
|
18817
|
+
_withReappliedViewState(action, result) {
|
|
18818
|
+
if (!result.ok || !reappliesViewState(action)) return result;
|
|
18819
|
+
const merged = this._reapplyViewState(result.changes);
|
|
18820
|
+
return merged === null ? result : { ...result, changes: merged };
|
|
18821
|
+
}
|
|
18822
|
+
/**
|
|
18823
|
+
* The single place the two view-state passes are chained. Dispatch, undo and
|
|
18824
|
+
* redo all route through here: when this existed only inside the dispatch
|
|
18825
|
+
* path, undo and redo reapplied the filter and forgot the order, so an edit
|
|
18826
|
+
* that moved a row and was then undone left the row in its new position.
|
|
18827
|
+
*
|
|
18828
|
+
* The sequence between the passes is indifferent. Filter and order are
|
|
18829
|
+
* orthogonal projections over the same tree — the filter decides which rows
|
|
18830
|
+
* exist on screen and never reads the order; the order sequences every
|
|
18831
|
+
* sibling group from the hierarchy index and never reads visibility. Either
|
|
18832
|
+
* sequence produces the same ChangeSet.
|
|
18833
|
+
*
|
|
18834
|
+
* Both passes answer null while their state is inactive, so an unfiltered,
|
|
18835
|
+
* unsorted schedule pays two property reads.
|
|
18836
|
+
*/
|
|
18837
|
+
_reapplyViewState(changes) {
|
|
18838
|
+
const withFilter = this._reapplyActiveFilter(changes);
|
|
18839
|
+
const withOrder = this._reapplyActiveOrder(withFilter ?? changes);
|
|
18840
|
+
const sequenced = this._emitTouchedBranchOrder(
|
|
18841
|
+
withOrder ?? withFilter ?? changes
|
|
18842
|
+
);
|
|
18843
|
+
return sequenced ?? withOrder ?? withFilter;
|
|
18844
|
+
}
|
|
18845
|
+
/**
|
|
18846
|
+
* Emits `order` for the branches this mutation resequenced, when no user order
|
|
18847
|
+
* is active.
|
|
18848
|
+
*
|
|
18849
|
+
* The contract is that `order` reports a CHANGED SEQUENCE, not the presence of
|
|
18850
|
+
* a sort. Tying emission to the cause instead of the effect is what produced
|
|
18851
|
+
* the undo bug and, later, the reparent ones: without an active order a move,
|
|
18852
|
+
* an indent, an outdent or the undo of any of them rearranged rows and said
|
|
18853
|
+
* nothing, so an incremental consumer kept the old sequence. The undo of a
|
|
18854
|
+
* reparent was the worst of them — it carried neither `order` nor a single
|
|
18855
|
+
* correlativeId, so the position was not recoverable by any consumer.
|
|
18856
|
+
*
|
|
18857
|
+
* The touched branches are derived from the ChangeSet rather than accumulated
|
|
18858
|
+
* in the state: an entity whose parentId or correlativeId moved, plus the
|
|
18859
|
+
* parents of created and deleted rows, is exactly the set of branches whose
|
|
18860
|
+
* sequence can differ. That keeps this linear in the blast radius, adds
|
|
18861
|
+
* nothing to the write path, and cannot leak across dispatches.
|
|
18862
|
+
*/
|
|
18863
|
+
_emitTouchedBranchOrder(changes) {
|
|
18864
|
+
const adapter = this.coreRuntime.state;
|
|
18865
|
+
if (adapter.getActiveOrder() !== null) return null;
|
|
18866
|
+
const touched = collectResequencedParents(
|
|
18867
|
+
changes,
|
|
18868
|
+
(activityId) => adapter.getParentId(activityId)
|
|
18869
|
+
);
|
|
18870
|
+
if (touched.size === 0) return null;
|
|
18871
|
+
const order = [...touched].map((parentId) => ({
|
|
18872
|
+
parentId,
|
|
18873
|
+
childIds: getChildrenInVisualOrder(parentId, adapter)
|
|
18874
|
+
})).filter((branch) => branch.childIds.length > 1);
|
|
18875
|
+
if (order.length === 0) return null;
|
|
18876
|
+
return { ...changes, order };
|
|
18877
|
+
}
|
|
18878
|
+
/**
|
|
18879
|
+
* Re-sequences the grid after any mutation that could have changed a value the
|
|
18880
|
+
* active order sorts by. Ordering is a view over the data, so an edit that
|
|
18881
|
+
* moves a row past its sibling must move the row, exactly as the filter makes
|
|
18882
|
+
* a no-longer-matching row disappear.
|
|
18883
|
+
*
|
|
18884
|
+
* Production only re-sorts after a bar drag; diverging from that is a
|
|
18885
|
+
* deliberate product decision, not an oversight.
|
|
18886
|
+
*/
|
|
18887
|
+
_reapplyActiveOrder(changes) {
|
|
18888
|
+
const adapter = this.coreRuntime.state;
|
|
18889
|
+
if (adapter.getActiveOrder() === null) return null;
|
|
18890
|
+
adapter.invalidateDerivedOrder();
|
|
18891
|
+
return { ...changes, order: collectBranchOrder(adapter) };
|
|
18892
|
+
}
|
|
18893
|
+
_reapplyActiveFilter(changes) {
|
|
18894
|
+
const filter = this.coreRuntime.state.getActiveFilter();
|
|
18895
|
+
if (filter === null) return null;
|
|
18896
|
+
const adapter = this.coreRuntime.state;
|
|
18897
|
+
const visibleIds = evaluateVisibleIds({
|
|
18898
|
+
activities: adapter.getAllActivities(),
|
|
18899
|
+
parentOf: (activityId) => adapter.getParentId(activityId),
|
|
18900
|
+
filter,
|
|
18901
|
+
context: buildFilterContext(this.coreRuntime.sector.hoursPerDay)
|
|
18902
|
+
});
|
|
18903
|
+
const viewState = applyVisibleSet(adapter, visibleIds);
|
|
18904
|
+
if (viewState.length === 0) return null;
|
|
18905
|
+
return {
|
|
18906
|
+
...changes,
|
|
18907
|
+
viewState: [...changes.viewState ?? [], ...viewState]
|
|
18908
|
+
};
|
|
18909
|
+
}
|
|
19197
18910
|
_recordScheduleMutation(criticalPathIsFresh) {
|
|
19198
18911
|
this._scheduleRevision++;
|
|
19199
18912
|
if (this._activeCriticalPath) {
|
|
@@ -19244,7 +18957,7 @@ var ScheduleCore = class {
|
|
|
19244
18957
|
for (const [activityId, fields] of fieldsByActivity) {
|
|
19245
18958
|
this.coreRuntime.state.setActivityFields(activityId, fields);
|
|
19246
18959
|
}
|
|
19247
|
-
changes = assembleChangeSet(this.coreRuntime.state, {
|
|
18960
|
+
changes = await assembleChangeSet(this.coreRuntime.state, {
|
|
19248
18961
|
source: { kind: "init" },
|
|
19249
18962
|
beforeSnap: /* @__PURE__ */ new Map(),
|
|
19250
18963
|
touchedIds: [],
|
|
@@ -19271,7 +18984,6 @@ var ScheduleCore = class {
|
|
|
19271
18984
|
void promise.then(clearIfActive, clearIfActive);
|
|
19272
18985
|
return promise;
|
|
19273
18986
|
}
|
|
19274
|
-
// bridge-load artifact: emits HOURS (no duration/lag diff anyway; bridge applies verbatim).
|
|
19275
18987
|
async _runCriticalPathAndCapture() {
|
|
19276
18988
|
if (this._status === SCHEDULE_CORE_STATUS.DESTROYED) {
|
|
19277
18989
|
return {
|
|
@@ -19292,7 +19004,7 @@ var ScheduleCore = class {
|
|
|
19292
19004
|
this.coreRuntime.state,
|
|
19293
19005
|
this.coreRuntime.sector.hoursPerDay
|
|
19294
19006
|
);
|
|
19295
|
-
changes = assembleChangeSet(this.coreRuntime.state, {
|
|
19007
|
+
changes = await assembleChangeSet(this.coreRuntime.state, {
|
|
19296
19008
|
source: { kind: "init" },
|
|
19297
19009
|
beforeSnap: /* @__PURE__ */ new Map(),
|
|
19298
19010
|
touchedIds: [],
|
|
@@ -19305,11 +19017,6 @@ var ScheduleCore = class {
|
|
|
19305
19017
|
}
|
|
19306
19018
|
return { changes };
|
|
19307
19019
|
}
|
|
19308
|
-
/**
|
|
19309
|
-
* Undo/Redo restores the user's historical mutation while retaining current
|
|
19310
|
-
* non-historical truth (for example a refreshed baseline). Re-derive every
|
|
19311
|
-
* value that depends on both so the restored model is immediately coherent.
|
|
19312
|
-
*/
|
|
19313
19020
|
_recomputeAfterHistoryRestore() {
|
|
19314
19021
|
const state = this.coreRuntime.state;
|
|
19315
19022
|
recomputeAllProgressRollup(state);
|
|
@@ -19345,7 +19052,12 @@ var ScheduleCore = class {
|
|
|
19345
19052
|
if (needsResync(entry)) this._resyncCustomIdTrackerFromModel();
|
|
19346
19053
|
this._undo.pushRedo(entry);
|
|
19347
19054
|
this._undo.resetCoalesce();
|
|
19348
|
-
|
|
19055
|
+
const changes = buildInverseChangeSet(
|
|
19056
|
+
this.coreRuntime.state,
|
|
19057
|
+
entry,
|
|
19058
|
+
"before"
|
|
19059
|
+
);
|
|
19060
|
+
return this._reapplyViewState(changes) ?? changes;
|
|
19349
19061
|
});
|
|
19350
19062
|
void operation.then(
|
|
19351
19063
|
(changes) => {
|
|
@@ -19373,7 +19085,12 @@ var ScheduleCore = class {
|
|
|
19373
19085
|
if (needsResync(entry)) this._resyncCustomIdTrackerFromModel();
|
|
19374
19086
|
this._undo.pushUndo(entry);
|
|
19375
19087
|
this._undo.resetCoalesce();
|
|
19376
|
-
|
|
19088
|
+
const changes = buildInverseChangeSet(
|
|
19089
|
+
this.coreRuntime.state,
|
|
19090
|
+
entry,
|
|
19091
|
+
"after"
|
|
19092
|
+
);
|
|
19093
|
+
return this._reapplyViewState(changes) ?? changes;
|
|
19377
19094
|
});
|
|
19378
19095
|
void operation.then(
|
|
19379
19096
|
(changes) => {
|
|
@@ -19396,11 +19113,6 @@ var ScheduleCore = class {
|
|
|
19396
19113
|
canRedo() {
|
|
19397
19114
|
return this._undo.canRedo();
|
|
19398
19115
|
}
|
|
19399
|
-
/**
|
|
19400
|
-
* Establishes a new persistence boundary without mutating schedule state.
|
|
19401
|
-
* Completed saves call this synchronously so neither prior undo entries nor
|
|
19402
|
-
* their redo branch can cross the persisted boundary.
|
|
19403
|
-
*/
|
|
19404
19116
|
clearHistory() {
|
|
19405
19117
|
this._undo.clear();
|
|
19406
19118
|
}
|
|
@@ -19435,13 +19147,6 @@ var ScheduleCore = class {
|
|
|
19435
19147
|
);
|
|
19436
19148
|
}
|
|
19437
19149
|
}
|
|
19438
|
-
/**
|
|
19439
|
-
* Revert the current dispatch's mutations from the write-capture journal. If
|
|
19440
|
-
* the restore ITSELF throws, the state may be a third, partially-inverted
|
|
19441
|
-
* state — worse than either endpoint — so poison the core: refuse all further
|
|
19442
|
-
* dispatches and surface the fault so the host reloads from backend. A failed
|
|
19443
|
-
* rollback is never swallowed.
|
|
19444
|
-
*/
|
|
19445
19150
|
_rollback() {
|
|
19446
19151
|
try {
|
|
19447
19152
|
this.coreRuntime.state.restoreFromCapture();
|
|
@@ -19456,6 +19161,14 @@ var ScheduleCore = class {
|
|
|
19456
19161
|
}
|
|
19457
19162
|
}
|
|
19458
19163
|
};
|
|
19164
|
+
function toPublicDispatchResult(result) {
|
|
19165
|
+
const {
|
|
19166
|
+
__beforeSnap: droppedSnapshots,
|
|
19167
|
+
__beforeLinks: droppedLinks,
|
|
19168
|
+
...publicResult
|
|
19169
|
+
} = result;
|
|
19170
|
+
return publicResult;
|
|
19171
|
+
}
|
|
19459
19172
|
|
|
19460
19173
|
// src/boundary/save/link-changes.ts
|
|
19461
19174
|
function checkNoUpdatedLinks(baseline, current) {
|
|
@@ -19510,6 +19223,8 @@ var DISPATCH_ACTION_KIND = {
|
|
|
19510
19223
|
SELECTION_TOGGLE: "selection-toggle",
|
|
19511
19224
|
SELECTION_REPLACE: "selection-replace",
|
|
19512
19225
|
VISIBILITY_SET: "visibility-set",
|
|
19226
|
+
FILTER_SET: "filter-set",
|
|
19227
|
+
SORT_SET: "sort-set",
|
|
19513
19228
|
SIR_SYNC: "sir-sync",
|
|
19514
19229
|
ACTIVITY_LOOKAHEAD_SYNC: "activity-lookahead-sync"
|
|
19515
19230
|
};
|
|
@@ -19535,6 +19250,8 @@ var KIND_CATALOG_COVERS_UNION = {
|
|
|
19535
19250
|
[DISPATCH_ACTION_KIND.SELECTION_TOGGLE]: true,
|
|
19536
19251
|
[DISPATCH_ACTION_KIND.SELECTION_REPLACE]: true,
|
|
19537
19252
|
[DISPATCH_ACTION_KIND.VISIBILITY_SET]: true,
|
|
19253
|
+
[DISPATCH_ACTION_KIND.FILTER_SET]: true,
|
|
19254
|
+
[DISPATCH_ACTION_KIND.SORT_SET]: true,
|
|
19538
19255
|
[DISPATCH_ACTION_KIND.SIR_SYNC]: true,
|
|
19539
19256
|
[DISPATCH_ACTION_KIND.ACTIVITY_LOOKAHEAD_SYNC]: true
|
|
19540
19257
|
};
|