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