@outbuild-company/schedule-core 1.1.2 → 1.3.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 +1291 -1579
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +49 -823
- package/dist/index.d.ts +49 -823
- package/dist/index.js +1291 -1579
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,79 +1,9 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared types for the custom AutoScheduler and its satellite packages
|
|
3
|
-
* (recording, replay, shadow, discovery).
|
|
4
|
-
*
|
|
5
|
-
* This file is the single seam between all components. All scheduler code
|
|
6
|
-
* depends ONLY on these types — never on the DHTMLX gantt object directly.
|
|
7
|
-
*/
|
|
8
|
-
type ActivityId$1 = string;
|
|
9
|
-
type LinkId$1 = string;
|
|
10
|
-
/** Value constants for link types. Matches `gantt.config.links`. */
|
|
11
1
|
declare const LINK_TYPE: {
|
|
12
2
|
readonly FINISH_TO_START: "0";
|
|
13
3
|
readonly START_TO_START: "1";
|
|
14
4
|
readonly FINISH_TO_FINISH: "2";
|
|
15
5
|
readonly START_TO_FINISH: "3";
|
|
16
6
|
};
|
|
17
|
-
interface LinkSnapshot {
|
|
18
|
-
id: LinkId$1;
|
|
19
|
-
source: ActivityId$1;
|
|
20
|
-
target: ActivityId$1;
|
|
21
|
-
type: LinkType;
|
|
22
|
-
lag: number;
|
|
23
|
-
/**
|
|
24
|
-
* Precomputed lag components for a VIRTUAL summary-expanded link. When
|
|
25
|
-
* present, the link calculator uses them verbatim instead of deriving the
|
|
26
|
-
* components from leaf durations (the normal `normalize` switch).
|
|
27
|
-
*
|
|
28
|
-
* These exist so an FF/SF link INTO a summary can carry the SUMMARY's
|
|
29
|
-
* duration (`_targetLag = -summary.duration`) and the per-leaf offset from
|
|
30
|
-
* the summary's start (`_trueLag = userLag + off_tgt(leaf)`), matching legacy
|
|
31
|
-
* `_getImplicitLinks`/`_convertToFinishToStartLink` under
|
|
32
|
-
* `auto_scheduling_move_projects`. Computed ONCE at expansion time
|
|
33
|
-
* (`parent-link-expansion.ts`), never per scheduling tick.
|
|
34
|
-
*
|
|
35
|
-
* All three must be set together (or none): a half-populated link would mix
|
|
36
|
-
* precomputed and derived components. Only the FF/SF-into-summary path emits
|
|
37
|
-
* them; every other link leaves them undefined and hits the fast path.
|
|
38
|
-
*/
|
|
39
|
-
_sourceLag?: number;
|
|
40
|
-
_targetLag?: number;
|
|
41
|
-
_trueLag?: number;
|
|
42
|
-
ganttId?: number;
|
|
43
|
-
sectorId?: number;
|
|
44
|
-
/** BE row id (distinct from the schedule-level `id`). */
|
|
45
|
-
proplannerId?: number;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Constraint Rules — single source of truth.
|
|
50
|
-
*
|
|
51
|
-
* This module owns the definition of constraint types and the rules that
|
|
52
|
-
* govern them. Both the autoscheduler and the manual scheduling pipelines
|
|
53
|
-
* (column edits, drag, bulk) consume the same primitives from here.
|
|
54
|
-
*
|
|
55
|
-
* Two surfaces:
|
|
56
|
-
*
|
|
57
|
-
* (a) Manual scheduling — pipelines call `checkConstraintViolation()` after
|
|
58
|
-
* a user types a new value, to decide whether to emit a warning.
|
|
59
|
-
* Surface: scalar Date inputs, no adapter needed.
|
|
60
|
-
*
|
|
61
|
-
* (b) Autoscheduler — `computeConstraintBounds()` derives the four date
|
|
62
|
-
* boundaries (earliest/latest × start/end) an activity's constraint
|
|
63
|
-
* imposes. `isStartWithinBounds()` and `isEndWithinBounds()` are used
|
|
64
|
-
* by `limitPlanDates()` to decide whether a candidate date (from a
|
|
65
|
-
* link) respects the constraint.
|
|
66
|
-
*
|
|
67
|
-
* Domain invariant the autoscheduler must respect:
|
|
68
|
-
* The autoscheduler never moves an activity to a date that violates that
|
|
69
|
-
* activity's own constraint. If a cascade via a link would push the
|
|
70
|
-
* activity outside its constraint bounds, the activity stays put.
|
|
71
|
-
*
|
|
72
|
-
* Manual scheduling does NOT enforce this — a user is allowed to type a
|
|
73
|
-
* value that violates their own constraint. The pipeline applies the edit
|
|
74
|
-
* and emits a warning; the UI decides what to do with the warning (typically
|
|
75
|
-
* shows a "constraint violation detected" modal and offers to revert).
|
|
76
|
-
*/
|
|
77
7
|
|
|
78
8
|
type ConstraintType = 'asap' | 'alap' | 'snet' | 'snlt' | 'fnet' | 'fnlt' | 'mso' | 'mfo';
|
|
79
9
|
declare const CONSTRAINT_TYPE: {
|
|
@@ -87,104 +17,44 @@ declare const CONSTRAINT_TYPE: {
|
|
|
87
17
|
readonly MFO: "mfo";
|
|
88
18
|
};
|
|
89
19
|
|
|
90
|
-
/**
|
|
91
|
-
* Public internal model types — the normalized form the core works with
|
|
92
|
-
* after parsing the backend payload.
|
|
93
|
-
*
|
|
94
|
-
* Field naming follows snake_case for entity fields (matches backend +
|
|
95
|
-
* DHTMLX convention) and camelCase for everything else, per Q14 in
|
|
96
|
-
* SCHEDULE_CORE_API.md.
|
|
97
|
-
*/
|
|
98
20
|
type ActivityId = string;
|
|
99
21
|
type LinkId = string;
|
|
100
22
|
type CalendarId = string;
|
|
101
23
|
type ActivityType = 'project' | 'task' | 'milestone';
|
|
102
24
|
|
|
103
|
-
/** DHTMLX link kinds: 0 = FS, 1 = SS, 2 = FF, 3 = SF. */
|
|
104
25
|
type LinkType = '0' | '1' | '2' | '3';
|
|
105
|
-
/** Direction for closest-work-time snapping. */
|
|
106
26
|
type WorkTimeDirection = 'future' | 'past';
|
|
107
27
|
declare const WORK_TIME_DIRECTION: {
|
|
108
28
|
readonly FUTURE: "future";
|
|
109
29
|
readonly PAST: "past";
|
|
110
30
|
};
|
|
111
|
-
/** Calendar query granularity (the engine boundary adds 'minute'/'any'). */
|
|
112
31
|
type CalendarUnit = 'hour' | 'day';
|
|
113
32
|
declare const CALENDAR_UNIT: {
|
|
114
33
|
readonly HOUR: "hour";
|
|
115
34
|
readonly DAY: "day";
|
|
116
35
|
};
|
|
117
|
-
/**
|
|
118
|
-
* Project-level criterion used to redistribute `ponderator` (weight) among
|
|
119
|
-
* sibling activities. Backend stores it lowercase on `projects.activity_creter`
|
|
120
|
-
* (`'duration' | 'cost' | 'hh'`, default `'duration'`); the core normalizes
|
|
121
|
-
* to uppercase. See `getActiveBaseline` / `recomputePonderatorsForParent`.
|
|
122
|
-
*/
|
|
123
36
|
type ActivityCreter = 'DURATION' | 'COST' | 'HH';
|
|
124
|
-
/** Criterion for the `status` column: compare progress against baseline or live expected. */
|
|
125
37
|
type StatusCriteria = 'Baseline' | 'Actual';
|
|
126
|
-
/**
|
|
127
|
-
* A versioned container of baseline points for a sector
|
|
128
|
-
* (backend `sectorbaselineversion` model). Exactly one version per sector
|
|
129
|
-
* has `active: true` — that is the one the ponderator computation and the
|
|
130
|
-
* baseline columns read.
|
|
131
|
-
*/
|
|
132
38
|
interface BaselineVersion {
|
|
133
39
|
id?: number;
|
|
134
40
|
name?: string | null;
|
|
135
|
-
/** Marks the live baseline. Exactly one active version per sector. */
|
|
136
41
|
active?: boolean;
|
|
137
42
|
visible?: boolean;
|
|
138
|
-
/** Backend extras passed through opaquely. */
|
|
139
43
|
[key: string]: unknown;
|
|
140
44
|
}
|
|
141
|
-
/**
|
|
142
|
-
* A single baseline data point for an activity, as stored by the backend
|
|
143
|
-
* (`sectorbaselinepoint` model) and carried verbatim through the core.
|
|
144
|
-
* Snapshots the activity's planned start/end/duration/cost/work at the
|
|
145
|
-
* moment a baseline version was saved. The schedule reads the ACTIVE point
|
|
146
|
-
* (see `getActiveBaseline`) to derive `ponderator` (baseline-only, no
|
|
147
|
-
* fallback — see memory `project_ponderator_baseline_fix`).
|
|
148
|
-
*
|
|
149
|
-
* Casing note: the frontend baseline columns (`startBaseCol` …
|
|
150
|
-
* `durationBaseCol`) read these fields directly off the activity, so the
|
|
151
|
-
* core preserves the backend snake_case exactly (passthrough, not parsed).
|
|
152
|
-
*
|
|
153
|
-
* Unit trap: `duration` is in DAYS (backend unit), unlike the activity's
|
|
154
|
-
* `duration` which the core models in working hours — convert with the
|
|
155
|
-
* sector's hours-per-day before arithmetic (legacy `transformDaysToHours`).
|
|
156
|
-
*/
|
|
157
45
|
interface BaselinePoint {
|
|
158
|
-
/** Planned start, backend date string `"YYYY/MM/DD H:MM"` or ISO. */
|
|
159
46
|
start_date: string;
|
|
160
|
-
/** Planned end (inclusive). */
|
|
161
47
|
end_date: string;
|
|
162
|
-
/** Planned duration in DAYS (backend unit). */
|
|
163
48
|
duration: number;
|
|
164
|
-
/** Planned cost. May arrive as a numeric string. */
|
|
165
49
|
cost: number | string;
|
|
166
|
-
/** Planned work hours (HH). May arrive as a numeric string. */
|
|
167
50
|
hh_work: number | string;
|
|
168
|
-
/** The version this point belongs to; `.active` selects the live one. */
|
|
169
51
|
sectorbaselineversion?: BaselineVersion;
|
|
170
52
|
sectorbaselineversionId?: number;
|
|
171
53
|
baseCalendarId?: number;
|
|
172
54
|
hoursPerDay?: number;
|
|
173
55
|
hoursPerWeek?: number;
|
|
174
|
-
/** Backend extras passed through opaquely. */
|
|
175
56
|
[key: string]: unknown;
|
|
176
57
|
}
|
|
177
|
-
/**
|
|
178
|
-
* Pure-domain activity model produced by `parseFromBackend`. Snake_case
|
|
179
|
-
* matches the backend convention. No index signature — every field is
|
|
180
|
-
* explicit. New backend fields must be added here and preserved by
|
|
181
|
-
* `normalize-activity.ts`.
|
|
182
|
-
*/
|
|
183
|
-
/**
|
|
184
|
-
* A pending SIR freezing an activity, reduced to the only field the core
|
|
185
|
-
* needs: its id (equal to the backend SIR id and the front's Redux item id).
|
|
186
|
-
* The schedule load already filters to pending, so presence ⇒ pending.
|
|
187
|
-
*/
|
|
188
58
|
interface PendingRequest {
|
|
189
59
|
id: string;
|
|
190
60
|
}
|
|
@@ -218,7 +88,6 @@ interface CoreBaselinePoint {
|
|
|
218
88
|
workHours: number;
|
|
219
89
|
versionId: number | null;
|
|
220
90
|
isActiveVersion: boolean;
|
|
221
|
-
/** Whether this version is the one selected for visual comparison. */
|
|
222
91
|
isVisibleVersion: boolean;
|
|
223
92
|
baseCalendarId: CalendarId | null;
|
|
224
93
|
hoursPerDay: number | null;
|
|
@@ -269,17 +138,6 @@ interface CoreActivity {
|
|
|
269
138
|
expectedProgressBaseline: number | null;
|
|
270
139
|
status: ActivityStatus | null;
|
|
271
140
|
criticalPath: CriticalPathResult | null;
|
|
272
|
-
/** Internal reversible leaf→project promotion state; never serialized. */
|
|
273
|
-
promotionRestore: {
|
|
274
|
-
type: 'task' | 'milestone';
|
|
275
|
-
startDate: Date;
|
|
276
|
-
endDate: Date;
|
|
277
|
-
durationHours: number;
|
|
278
|
-
expectedProgressBaseline: number | null;
|
|
279
|
-
constraintType: ConstraintType;
|
|
280
|
-
constraintDate: Date | null;
|
|
281
|
-
progress: number;
|
|
282
|
-
} | null;
|
|
283
141
|
}
|
|
284
142
|
interface Link {
|
|
285
143
|
id: LinkId;
|
|
@@ -289,79 +147,25 @@ interface Link {
|
|
|
289
147
|
lag: number;
|
|
290
148
|
ganttId?: number;
|
|
291
149
|
sectorId?: number;
|
|
292
|
-
/** BE row id (distinct from the schedule-level `id`/`unique_id`). */
|
|
293
150
|
proplannerId?: number;
|
|
294
151
|
}
|
|
295
152
|
interface CalendarWorktime {
|
|
296
|
-
/**
|
|
297
|
-
* Per-weekday working hours, length 7 — index 0 = Sunday.
|
|
298
|
-
*
|
|
299
|
-
* - `false` → non-working day
|
|
300
|
-
* - `string[]` → working day with these `"HH:MM-HH:MM"` windows
|
|
301
|
-
* (supports per-day variation, e.g. a short Friday,
|
|
302
|
-
* and multi-shift split days like `["8-12","13-17"]`)
|
|
303
|
-
*
|
|
304
|
-
* Single source of truth: this is exactly what `parseFromBackend` emits. A
|
|
305
|
-
* usable working day carries its resolved windows; `[]` is reserved for a
|
|
306
|
-
* catalog calendar that declares the day as working but provides no usable
|
|
307
|
-
* shift anywhere. Those catalog-only calendars remain selectable/persistable
|
|
308
|
-
* but are deliberately not registered as arithmetic calendars. The vendored
|
|
309
|
-
* work-calendar engine natively also accepts a boolean `true` per day (DHTMLX
|
|
310
|
-
* contract), but that form never appears in the domain `Calendar`; it is
|
|
311
|
-
* reserved for the engine-facing internals (`SnapshotWorktime`,
|
|
312
|
-
* synthetic replay fixtures).
|
|
313
|
-
*
|
|
314
|
-
* The work-calendar engine consumes each weekday independently, so
|
|
315
|
-
* different days can carry different windows.
|
|
316
|
-
*/
|
|
317
153
|
days: Array<false | string[]>;
|
|
318
|
-
/**
|
|
319
|
-
* Default working-hour windows (`"HH:MM-HH:MM"`). Used as the engine's
|
|
320
|
-
* global fallback. `parseFromBackend` sets it to the first usable working
|
|
321
|
-
* day's windows, or `[]` when the calendar has no usable shift.
|
|
322
|
-
*/
|
|
323
154
|
hours: string[];
|
|
324
|
-
/**
|
|
325
|
-
* Per-date exceptions: holidays (non-working) and date-level shift
|
|
326
|
-
* overrides. Keys are `Date.UTC(year, month, day)` (UTC midnight epoch
|
|
327
|
-
* ms) stringified — this matches the lookup the work-calendar engine
|
|
328
|
-
* performs internally at `calendar.dates[dateValue]`.
|
|
329
|
-
*
|
|
330
|
-
* Value semantics:
|
|
331
|
-
* - `false` → the day is non-working
|
|
332
|
-
* - `string[]` → use these `"HH:MM-HH:MM"` windows instead
|
|
333
|
-
* of the default `hours`
|
|
334
|
-
*
|
|
335
|
-
* Source: `BackendCalendarInput.exceptiondays[]` after the adapter expands
|
|
336
|
-
* `from_date`/`to_date` ranges into individual UTC days.
|
|
337
|
-
*/
|
|
338
155
|
dates?: Record<string, false | string[]>;
|
|
339
|
-
/** Optional per-week overrides for advanced calendars. */
|
|
340
156
|
customWeeks?: Record<string, unknown>;
|
|
341
157
|
}
|
|
342
158
|
interface Calendar {
|
|
343
159
|
id: CalendarId;
|
|
344
|
-
/** Display name. Used by the DHTMLX calendar-selector column. */
|
|
345
160
|
name: string;
|
|
346
161
|
worktime: CalendarWorktime;
|
|
347
162
|
is_default: boolean;
|
|
348
|
-
/**
|
|
349
|
-
* True for "base" calendars (baseline comparison). The backend ships
|
|
350
|
-
* these with an `id` suffixed `-base` and `baseDefault` instead of
|
|
351
|
-
* `is_default`. The bridge uses this to set `gantt.defaultBaseCalendar`
|
|
352
|
-
* and to keep base calendars out of the selector dropdown.
|
|
353
|
-
*/
|
|
354
163
|
baseDefault?: boolean;
|
|
355
|
-
/**
|
|
356
|
-
* Date-keyed map of exceptions (holidays, working overrides).
|
|
357
|
-
* Keys are `YYYY-MM-DD` UTC.
|
|
358
|
-
*/
|
|
359
164
|
exceptions?: Record<string, {
|
|
360
165
|
working: boolean;
|
|
361
166
|
hours?: string[];
|
|
362
167
|
}>;
|
|
363
168
|
}
|
|
364
|
-
/** Sector metadata the core respects from the backend. */
|
|
365
169
|
interface SectorMetadata {
|
|
366
170
|
id: string;
|
|
367
171
|
name: string;
|
|
@@ -370,48 +174,12 @@ interface SectorMetadata {
|
|
|
370
174
|
dateFormat: string;
|
|
371
175
|
projectId: number;
|
|
372
176
|
companyId: number;
|
|
373
|
-
/**
|
|
374
|
-
* Project's `custom_id_prefix` (Outbuild project setting). Used by the
|
|
375
|
-
* CustomIdTracker to generate ids for new activities. Falls back to
|
|
376
|
-
* `'A'` if not provided.
|
|
377
|
-
*/
|
|
378
177
|
customIdPrefix?: string;
|
|
379
|
-
/**
|
|
380
|
-
* Project's `custom_id_increment` (Outbuild project setting), as a
|
|
381
|
-
* string so leading zeros are preserved. Used by the CustomIdTracker
|
|
382
|
-
* to choose the next suffix step. Falls back to `'10'` if not provided.
|
|
383
|
-
*/
|
|
384
178
|
customIdIncrement?: string;
|
|
385
|
-
/**
|
|
386
|
-
* Legacy Primavera-import flag. When true, the core recomputes each
|
|
387
|
-
* activity's `duration` from its start/end against its calendar at load
|
|
388
|
-
* (Primavera stores end-driven durations that may not match the
|
|
389
|
-
* calendar). Mirrors the legacy `fixPrimaveraDurations`. See CALENDARS.md.
|
|
390
|
-
*/
|
|
391
179
|
updateDurationForPrimaveraEndDate?: boolean;
|
|
392
|
-
/**
|
|
393
|
-
* Project's `activity_creter` — criterion for ponderator redistribution
|
|
394
|
-
* (`'DURATION' | 'COST' | 'HH'`). Lives at the project level; arrives via
|
|
395
|
-
* the sector payload's pass-through bucket. `parseSector` always sets it,
|
|
396
|
-
* defaulting to `'DURATION'` (the backend default) when absent/unknown.
|
|
397
|
-
*/
|
|
398
180
|
activityCreter?: ActivityCreter;
|
|
399
|
-
/**
|
|
400
|
-
* Project's status criterion for the `status` column — `'Baseline'` compares
|
|
401
|
-
* `progress` against `expected_progress_base`, `'Actual'` against
|
|
402
|
-
* `expected_progress`. Mutable at runtime via `ScheduleCore.setStatusCriteria`
|
|
403
|
-
* (the Baseline↔Actual toggle). Not a backend field (client-only session
|
|
404
|
-
* setting); a complete sector always carries it — `parseSector` sets the
|
|
405
|
-
* default and `resolveStatusCriteria` normalizes the client override at init.
|
|
406
|
-
* See `docs/domain/columns/COLUMN_status.md`.
|
|
407
|
-
*/
|
|
408
181
|
statusCriteria: StatusCriteria;
|
|
409
182
|
}
|
|
410
|
-
/**
|
|
411
|
-
* A single entity mutation record emitted by a dispatch ChangeSet.
|
|
412
|
-
* Layer-neutral: contains no dispatch-specific dependencies and is used
|
|
413
|
-
* both by `dispatch/` and by `internal/tracking/`.
|
|
414
|
-
*/
|
|
415
183
|
interface EntityChange<T> {
|
|
416
184
|
id: string;
|
|
417
185
|
kind: 'created' | 'updated' | 'deleted';
|
|
@@ -465,45 +233,33 @@ declare const COLUMN: {
|
|
|
465
233
|
};
|
|
466
234
|
type ColumnName = (typeof COLUMN)[keyof typeof COLUMN];
|
|
467
235
|
|
|
468
|
-
/**
|
|
469
|
-
* Task creation pipeline — types.
|
|
470
|
-
*
|
|
471
|
-
* Ports the pure parts of `src/assets/js/custom_actions/createTask/` into a
|
|
472
|
-
* functional pipeline that replay tests (and eventually prod) can invoke
|
|
473
|
-
* against an adapter instead of the live gantt.
|
|
474
|
-
*/
|
|
475
|
-
|
|
476
|
-
/**
|
|
477
|
-
* Closed, canonical contract for create/paste overrides: camelCase, working
|
|
478
|
-
* hours, limited to the fields a caller may seed on a new activity. Identity
|
|
479
|
-
* and structure (`id`/`parentId`/`correlativeId`/`uniqueCorrelativeId`),
|
|
480
|
-
* derived/CP/baseline outputs and view-state are NOT overridable. PP2 adapts
|
|
481
|
-
* its own vocabulary to this contract in step 9.
|
|
482
|
-
*/
|
|
483
236
|
declare const CREATION_OVERRIDE_FIELD_LIST: readonly ["name", "description", "type", "startDate", "durationHours", "constraintType", "constraintDate", "calendarId", "assignedDefaultCalendar", "autoScheduling", "progress", "cost", "usedCost", "realCost", "workHours", "realWorkHours", "ponderator", "hasCustomPonderator", "customId", "subcontractId", "responsableIds", "tagIds", "isLookahead"];
|
|
484
237
|
type CreationOverrideField = (typeof CREATION_OVERRIDE_FIELD_LIST)[number];
|
|
485
238
|
type CreationOverrides = Partial<Pick<CoreActivity, CreationOverrideField>>;
|
|
486
239
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
240
|
+
type StringOperator = 'includes' | 'notIncludes' | 'is' | 'isNot';
|
|
241
|
+
type NumberOperator = 'equals' | 'notEquals' | 'greaterThan' | 'lessThan' | 'greaterOrEqual' | 'lessOrEqual';
|
|
242
|
+
type DateOperator = 'after' | 'before';
|
|
243
|
+
type MembershipOperator = 'someOf' | 'notSomeOf';
|
|
244
|
+
type FilterOperator = StringOperator | NumberOperator | DateOperator | MembershipOperator;
|
|
245
|
+
type FilterField = 'name' | 'description' | 'customId' | 'correlativeId' | 'uniqueCorrelativeId' | 'progress' | 'durationDays' | 'calendarDuration' | 'cost' | 'usedCost' | 'realCost' | 'workHours' | 'realWorkHours' | 'ponderator' | 'freeSlackDays' | 'totalSlackDays' | 'expectedProgressBaseline' | 'baselineDurationDays' | 'baselineCost' | 'baselineWorkHours' | 'startDate' | 'endDate' | 'constraintDate' | 'baselineStartDate' | 'baselineEndDate' | 'earlyStart' | 'earlyFinish' | 'lateStart' | 'lateFinish' | 'responsableIds' | 'tagIds' | 'status' | 'constraintType' | 'calendarId' | 'subcontractId' | 'isCritical';
|
|
246
|
+
type FilterScalarValue = string | number | Date;
|
|
247
|
+
type FilterCriterionValue = FilterScalarValue | ReadonlyArray<string | number>;
|
|
248
|
+
interface FilterCriterion {
|
|
249
|
+
readonly field: FilterField;
|
|
250
|
+
readonly operator: FilterOperator;
|
|
251
|
+
readonly value: FilterCriterionValue;
|
|
252
|
+
}
|
|
253
|
+
interface FilterDateRange {
|
|
254
|
+
readonly start: Date;
|
|
255
|
+
readonly end: Date;
|
|
256
|
+
}
|
|
257
|
+
interface FilterState {
|
|
258
|
+
readonly criteria: ReadonlyArray<FilterCriterion>;
|
|
259
|
+
readonly logic: 'and' | 'or';
|
|
260
|
+
readonly dateRange?: FilterDateRange;
|
|
261
|
+
}
|
|
262
|
+
|
|
507
263
|
type LinksBatchOperation = {
|
|
508
264
|
kind: 'create';
|
|
509
265
|
source: ActivityId;
|
|
@@ -544,13 +300,6 @@ type DispatchAction = {
|
|
|
544
300
|
column: string;
|
|
545
301
|
newValue: unknown;
|
|
546
302
|
} | {
|
|
547
|
-
/**
|
|
548
|
-
* K ediciones de fecha como UNA unidad de trabajo (multi-drag): cada
|
|
549
|
-
* edit corre su pipeline individual (verdict por barra), pero el
|
|
550
|
-
* post-mutation (autoscheduler → bounds → CP) corre UNA sola vez y
|
|
551
|
-
* sale UN ChangeSet. Patrón hermano de `activity-paste` /
|
|
552
|
-
* `dispatchInlineEditLinks`. Track onAfterTaskDrag F2.2.
|
|
553
|
-
*/
|
|
554
303
|
kind: 'dates-batch';
|
|
555
304
|
edits: ReadonlyArray<{
|
|
556
305
|
activityId: ActivityId;
|
|
@@ -558,21 +307,6 @@ type DispatchAction = {
|
|
|
558
307
|
newValue: unknown;
|
|
559
308
|
}>;
|
|
560
309
|
} | {
|
|
561
|
-
/**
|
|
562
|
-
* K edits on ANY pipeline column as ONE unit of work — the
|
|
563
|
-
* generalization of `dates-batch` to the 16 registry columns
|
|
564
|
-
* (schedule bulk editors / modals; PLAN_convergencia_wiring §4.1).
|
|
565
|
-
* Each edit resolves its pipeline via `findPipelineForColumn` and
|
|
566
|
-
* runs phases 1-4 with an individual verdict (a rejected edit does
|
|
567
|
-
* NOT abort the others — paste semantics). A column without a
|
|
568
|
-
* pipeline (e.g. the link columns `custom_predecessors` /
|
|
569
|
-
* `custom_sucessors`, which mutate the link graph and dispatch as
|
|
570
|
-
* link intents) rejects ONLY that edit. The post-mutation pass
|
|
571
|
-
* (autoscheduler → parent bounds → CP) runs ONCE at the end and a
|
|
572
|
-
* single ChangeSet comes out = ONE undo step (never coalesces).
|
|
573
|
-
* Supports both shapes: K activities × same column, and 1 activity
|
|
574
|
-
* × several columns (atomic multi-field edit).
|
|
575
|
-
*/
|
|
576
310
|
kind: 'bulk-edit';
|
|
577
311
|
edits: ReadonlyArray<{
|
|
578
312
|
activityId: ActivityId;
|
|
@@ -585,16 +319,12 @@ type DispatchAction = {
|
|
|
585
319
|
source: ActivityId;
|
|
586
320
|
target: ActivityId;
|
|
587
321
|
type: LinkType;
|
|
588
|
-
/** Lag in DAYS (public boundary unit; converted to working hours inside). */
|
|
589
322
|
lag: number;
|
|
590
|
-
/** Optional explicit id (tests pass deterministic ids). */
|
|
591
323
|
linkId?: LinkId;
|
|
592
324
|
} | {
|
|
593
325
|
kind: 'link-update';
|
|
594
326
|
linkId: LinkId;
|
|
595
|
-
/** New type. Omit to preserve. */
|
|
596
327
|
type?: LinkType;
|
|
597
|
-
/** New lag in DAYS (public boundary unit). Omit to preserve. */
|
|
598
328
|
lag?: number;
|
|
599
329
|
} | {
|
|
600
330
|
kind: 'link-delete';
|
|
@@ -604,254 +334,84 @@ type DispatchAction = {
|
|
|
604
334
|
operations: ReadonlyArray<LinksBatchOperation>;
|
|
605
335
|
} | {
|
|
606
336
|
kind: 'activity-create';
|
|
607
|
-
/** Where to put the new activity. Use `'0'` for root. */
|
|
608
337
|
parentId: ActivityId | '0';
|
|
609
|
-
/**
|
|
610
|
-
* Optional — insert the new activity immediately AFTER this sibling.
|
|
611
|
-
* If omitted (and `beforeSiblingId` also omitted), the new activity
|
|
612
|
-
* is appended as the last child of `parentId`. The sibling must
|
|
613
|
-
* currently be a child of `parentId`, otherwise the dispatch is
|
|
614
|
-
* rejected. Mutually exclusive with `beforeSiblingId`.
|
|
615
|
-
*/
|
|
616
338
|
afterSiblingId?: ActivityId | undefined;
|
|
617
|
-
/**
|
|
618
|
-
* Optional — insert the new activity immediately BEFORE this sibling.
|
|
619
|
-
* Use case: "insert as first child" (`beforeSiblingId = currentFirstChild`)
|
|
620
|
-
* or "insert at position N" (`beforeSiblingId = children[N]`).
|
|
621
|
-
* The sibling must currently be a child of `parentId`, otherwise the
|
|
622
|
-
* dispatch is rejected. Mutually exclusive with `afterSiblingId`.
|
|
623
|
-
*/
|
|
624
339
|
beforeSiblingId?: ActivityId | undefined;
|
|
625
|
-
/**
|
|
626
|
-
* Canonical field overrides applied on top of the creation defaults —
|
|
627
|
-
* camelCase, working hours, limited to creation-writable fields
|
|
628
|
-
* (`CreationOverrides`). Identity/structure and derived outputs are not
|
|
629
|
-
* overridable.
|
|
630
|
-
*/
|
|
631
340
|
overrides?: CreationOverrides;
|
|
632
|
-
/**
|
|
633
|
-
* Deterministic activity id — used by tests and by replay flows
|
|
634
|
-
* (paste, undo) that need to assign a specific id. If omitted, the
|
|
635
|
-
* core's internal id generator allocates one.
|
|
636
|
-
*/
|
|
637
341
|
activityId?: ActivityId;
|
|
638
|
-
/**
|
|
639
|
-
* Where this create originated from — passed through to the
|
|
640
|
-
* `schedule_activity_creation` Amplitude event. Free-form string
|
|
641
|
-
* (matches legacy `INSERT_EVENT_SOURCES`).
|
|
642
|
-
*/
|
|
643
342
|
eventSource?: string | undefined;
|
|
644
343
|
} | {
|
|
645
344
|
kind: 'activity-delete';
|
|
646
|
-
/**
|
|
647
|
-
* IDs to delete. Each id triggers a cascade delete of its entire
|
|
648
|
-
* subtree. Links incident to any deleted activity are removed too.
|
|
649
|
-
* Operation is atomic — if any id is missing, the whole dispatch is
|
|
650
|
-
* rejected before mutating anything.
|
|
651
|
-
*/
|
|
652
345
|
activityIds: ReadonlyArray<ActivityId>;
|
|
653
346
|
eventSource?: string;
|
|
654
347
|
} | {
|
|
655
348
|
kind: 'activity-move';
|
|
656
|
-
/**
|
|
657
|
-
* The activity to move. Single-id only — for batch reorder use
|
|
658
|
-
* multiple dispatches (each one observes the post-previous state).
|
|
659
|
-
*/
|
|
660
349
|
activityId: ActivityId;
|
|
661
|
-
/** Destination parent. Same as current parent = reorder within. */
|
|
662
350
|
parentId: ActivityId | '0';
|
|
663
|
-
/**
|
|
664
|
-
* Optional — position the moved activity immediately below this
|
|
665
|
-
* sibling. If omitted, appended as the last child of `parentId`.
|
|
666
|
-
* The sibling must currently be a child of `parentId`; otherwise
|
|
667
|
-
* the dispatch is rejected. Mutually exclusive with `beforeSiblingId`.
|
|
668
|
-
*/
|
|
669
351
|
afterSiblingId?: ActivityId;
|
|
670
352
|
beforeSiblingId?: ActivityId;
|
|
671
353
|
eventSource?: string;
|
|
672
354
|
} | {
|
|
673
355
|
kind: 'activity-indent';
|
|
674
|
-
/**
|
|
675
|
-
* IDs to indent. Multi-select honors chain semantics: each id is
|
|
676
|
-
* moved under its closest previous sibling that is NOT in the
|
|
677
|
-
* selected set, so consecutive selected siblings all land under the
|
|
678
|
-
* same anchor (matches legacy `findPreviousNonSelectedSibling`).
|
|
679
|
-
*/
|
|
680
356
|
activityIds: ReadonlyArray<ActivityId>;
|
|
681
357
|
eventSource?: string;
|
|
682
358
|
} | {
|
|
683
359
|
kind: 'activity-outdent';
|
|
684
|
-
/**
|
|
685
|
-
* IDs to outdent. Multi-select preserves relative order among the
|
|
686
|
-
* selected siblings via initial-index capture (matches legacy
|
|
687
|
-
* `initialFirstSiblings` + `initialTaskIndexes` pre-loop setup).
|
|
688
|
-
*/
|
|
689
360
|
activityIds: ReadonlyArray<ActivityId>;
|
|
690
361
|
eventSource?: string;
|
|
691
362
|
} | {
|
|
692
|
-
/**
|
|
693
|
-
* Set progress to 0 or 100 with recursive cascade semantics.
|
|
694
|
-
*
|
|
695
|
-
* Triggered by the schedule's "complete" / "uncomplete" buttons.
|
|
696
|
-
* **Distinct intent from `inline-edit`** — bypasses the
|
|
697
|
-
* `isSummaryActivity` gate of `progressPipeline.canEdit` because
|
|
698
|
-
* the user is explicitly invoking the recursive operation
|
|
699
|
-
* ("complete this parent and all its descendants"), not editing
|
|
700
|
-
* a single cell.
|
|
701
|
-
*
|
|
702
|
-
* Inline edits on the progress column still use `inline-edit` with
|
|
703
|
-
* full `canEdit`/`validate` gating (which blocks summary activities
|
|
704
|
-
* by design). See [[complete activity business rules]] R8 and the
|
|
705
|
-
* bifurcation rationale.
|
|
706
|
-
*
|
|
707
|
-
* Internally reuses the `progressPipeline.transform` so cascade,
|
|
708
|
-
* rollup, tracking and visualization are identical to inline-edit
|
|
709
|
-
* with newValue=0 or newValue=100.
|
|
710
|
-
*/
|
|
711
363
|
kind: 'activity-set-progress';
|
|
712
364
|
activityId: ActivityId;
|
|
713
|
-
/** Strictly 0 (uncomplete) or 100 (complete). */
|
|
714
365
|
newValue: 0 | 100;
|
|
715
366
|
eventSource?: string;
|
|
716
367
|
} | {
|
|
717
|
-
/**
|
|
718
|
-
* Checkbox selection toggle (2026-06-06). The core is the
|
|
719
|
-
* authority of the check state (`checked` / `visibleChecked` /
|
|
720
|
-
* `mustApplyVisibleChecked` written as a single bit): it runs the
|
|
721
|
-
* full propagation (descendants cascade, frozen partition with
|
|
722
|
-
* parent blocking, unified upward pass — see
|
|
723
|
-
* `internal/selection/compute-selection-update.ts`) and emits a
|
|
724
|
-
* prop-only ChangeSet the bridge applies in bulk to DHTMLX
|
|
725
|
-
* (silent store write + viewport repaint). No autoscheduler, no
|
|
726
|
-
* critical path.
|
|
727
|
-
*/
|
|
728
368
|
kind: 'selection-toggle';
|
|
729
369
|
activityId: ActivityId;
|
|
730
|
-
/** Checkbox state AFTER the user click. */
|
|
731
370
|
isChecked: boolean;
|
|
732
|
-
/**
|
|
733
|
-
* Ids frozen by pending SIRs, computed by the caller from the
|
|
734
|
-
* runtime (DHTMLX task props — the core's own `pendingRequests`
|
|
735
|
-
* is load-time-stale until TODO #10). When omitted, the core
|
|
736
|
-
* falls back to its own snapshots.
|
|
737
|
-
*/
|
|
738
371
|
frozenIds?: ReadonlyArray<ActivityId>;
|
|
739
|
-
/**
|
|
740
|
-
* Enable the upward auto-check of ancestors when all their
|
|
741
|
-
* checkable children become selected. Mirrors the (inverted)
|
|
742
|
-
* CHECKBOX_NOT_AUTOMATIC_PARENT_SELECTION flag. Default: false.
|
|
743
|
-
*/
|
|
744
372
|
autoCheckParents?: boolean;
|
|
745
373
|
eventSource?: string;
|
|
746
374
|
} | {
|
|
747
|
-
/**
|
|
748
|
-
* Replace the whole selection with an exact id set — no
|
|
749
|
-
* propagation. Used by clear / block-selection / external sync.
|
|
750
|
-
* Unknown ids are ignored. Same prop-only ChangeSet contract as
|
|
751
|
-
* `selection-toggle`.
|
|
752
|
-
*/
|
|
753
375
|
kind: 'selection-replace';
|
|
754
376
|
activityIds: ReadonlyArray<ActivityId>;
|
|
755
377
|
eventSource?: string;
|
|
756
378
|
} | {
|
|
757
|
-
/**
|
|
758
|
-
* View-model visibility set (Fase 1, 2026-07-04). ABSOLUTE set: the
|
|
759
|
-
* UI sends the COMPLETE list of ids visible after its filters run;
|
|
760
|
-
* the core diffs against the current `visible` bits (an id changes
|
|
761
|
-
* when `(visible !== false) !== willBeVisible`) and emits a
|
|
762
|
-
* prop-only ChangeSet carrying ONLY the `visible` field for the
|
|
763
|
-
* activities that changed. Unknown ids are ignored. Same prop-only
|
|
764
|
-
* contract as `selection-replace`: no autoscheduler, no critical
|
|
765
|
-
* path, no undo step. Idempotent.
|
|
766
|
-
*/
|
|
767
379
|
kind: 'visibility-set';
|
|
768
380
|
visibleIds: ReadonlyArray<ActivityId>;
|
|
769
381
|
eventSource?: string;
|
|
770
382
|
} | {
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
* ChangeSet; no autoscheduler, no CP. Idempotent.
|
|
778
|
-
*/
|
|
383
|
+
kind: 'filter-set';
|
|
384
|
+
criteria: ReadonlyArray<FilterCriterion>;
|
|
385
|
+
logic: 'and' | 'or';
|
|
386
|
+
dateRange?: FilterDateRange;
|
|
387
|
+
eventSource?: string;
|
|
388
|
+
} | {
|
|
779
389
|
kind: 'sir-sync';
|
|
780
390
|
activityId: ActivityId;
|
|
781
391
|
pendingRequests: ReadonlyArray<PendingRequest>;
|
|
782
392
|
eventSource?: string;
|
|
783
393
|
} | {
|
|
784
|
-
/**
|
|
785
|
-
* Synchronize the schedule-side flags owned by Lookahead task
|
|
786
|
-
* creation/deletion. The Lookahead records remain at the application
|
|
787
|
-
* boundary; the core owns these flags because they affect schedule
|
|
788
|
-
* editing rules and the public activity view.
|
|
789
|
-
*/
|
|
790
394
|
kind: 'activity-lookahead-sync';
|
|
791
395
|
activityIds: ReadonlyArray<ActivityId>;
|
|
792
396
|
isLookahead: boolean;
|
|
793
397
|
hasLookaheadTasks: boolean;
|
|
794
398
|
eventSource?: string;
|
|
795
399
|
} | {
|
|
796
|
-
/**
|
|
797
|
-
* Bulk paste (2026-06-08). Creates N activities (preserving the
|
|
798
|
-
* copied subtree hierarchy) plus M internal links in a SINGLE
|
|
799
|
-
* atomic ChangeSet — the future unit of undo. Replaces the
|
|
800
|
-
* DHTMLX-side paste that bypassed the core via `gantt.isPasting`.
|
|
801
|
-
*
|
|
802
|
-
* The caller (bridge) supplies, per activity, the field
|
|
803
|
-
* `overrides` already shaped by the paste prepare step (resets +
|
|
804
|
-
* validated catalogs). The core allocates ids/uids, re-hangs the
|
|
805
|
-
* hierarchy via `originalId → newId`, promotes parents, runs the
|
|
806
|
-
* hh/cost cascade + correlative sweep + autoscheduler ONCE at the
|
|
807
|
-
* end of the batch (not per activity).
|
|
808
|
-
*
|
|
809
|
-
* See [[COPY_PASTE_CORE_MIGRATION_DESIGN]].
|
|
810
|
-
*/
|
|
811
400
|
kind: 'activity-paste';
|
|
812
|
-
/**
|
|
813
|
-
* Where the pasted roots land. `{ parentId, index }` pastes INSIDE
|
|
814
|
-
* the reference (index 0 = first child). `{ afterSiblingId }`
|
|
815
|
-
* pastes as a sibling immediately below the reference; the parent
|
|
816
|
-
* is derived from the sibling.
|
|
817
|
-
*/
|
|
818
401
|
destination: {
|
|
819
402
|
parentId: ActivityId | '0';
|
|
820
403
|
index: number;
|
|
821
404
|
} | {
|
|
822
405
|
afterSiblingId: ActivityId;
|
|
823
406
|
};
|
|
824
|
-
/**
|
|
825
|
-
* The activity the paste is anchored to (the single selected row).
|
|
826
|
-
* Used as the custom_id reference for pasted children. Replaces
|
|
827
|
-
* the legacy `gantt.pasteReferenceActivity` instance flag.
|
|
828
|
-
*/
|
|
829
407
|
referenceActivityId: ActivityId;
|
|
830
|
-
/**
|
|
831
|
-
* Activities to create, in tree order (parents before children).
|
|
832
|
-
* `originalId` / `originalParentId` are the ids from the copied
|
|
833
|
-
* payload; the core remaps them to freshly allocated ids and uses
|
|
834
|
-
* the remap to re-hang the hierarchy and the links. A pasted activity
|
|
835
|
-
* may carry its visible baseline snapshot, but it is not enrolled in an
|
|
836
|
-
* already-created historical baseline.
|
|
837
|
-
*/
|
|
838
408
|
activities: ReadonlyArray<PastedActivityInput>;
|
|
839
|
-
/**
|
|
840
|
-
* Internal links to recreate. `source`/`target` reference the
|
|
841
|
-
* ORIGINAL (copied) ids; links with an endpoint outside the
|
|
842
|
-
* pasted set are dropped (dangling).
|
|
843
|
-
*/
|
|
844
409
|
links: ReadonlyArray<PastedLinkInput>;
|
|
845
410
|
eventSource?: string;
|
|
846
411
|
};
|
|
847
412
|
interface PastedActivityInput {
|
|
848
413
|
readonly originalId: ActivityId;
|
|
849
414
|
readonly originalParentId: ActivityId | '0';
|
|
850
|
-
/**
|
|
851
|
-
* Optional explicit destination id. Production normally omits it and lets
|
|
852
|
-
* the adapter allocate; recorder replay supplies MAIN's observed id so the
|
|
853
|
-
* whole-tree oracle can compare identity without an invented id remap.
|
|
854
|
-
*/
|
|
855
415
|
readonly activityId?: ActivityId;
|
|
856
416
|
readonly overrides: CreationOverrides;
|
|
857
417
|
readonly baselineSnapshot?: ActivityBaselineSnapshot | null;
|
|
@@ -860,49 +420,20 @@ interface PastedLinkInput {
|
|
|
860
420
|
readonly source: ActivityId;
|
|
861
421
|
readonly target: ActivityId;
|
|
862
422
|
readonly type: LinkType;
|
|
863
|
-
/** Lag in DAYS (public boundary unit; converted to working hours inside). */
|
|
864
423
|
readonly lag: number;
|
|
865
424
|
readonly linkId?: LinkId;
|
|
866
425
|
}
|
|
867
426
|
interface DispatchOptions {
|
|
868
|
-
/** Skip the autoscheduler pass after the mutation. Default: false. */
|
|
869
427
|
skipAutoSchedule?: boolean;
|
|
870
|
-
/** Skip the CP recompute after the mutation. Default: false. */
|
|
871
428
|
skipCriticalPath?: boolean;
|
|
872
|
-
/**
|
|
873
|
-
* Unit of the INPUT `newValue` for unit-bearing inline-edit columns (today:
|
|
874
|
-
* duration). Default 'days' (public contract; card + tests send days). The
|
|
875
|
-
* DHTMLX grid editor produces the store unit (HOURS via formatter.parse), so
|
|
876
|
-
* the bridge passes 'hours' for those edits → the pipeline skips the days→hours
|
|
877
|
-
* conversion instead of double-converting.
|
|
878
|
-
*/
|
|
879
429
|
inputUnit?: 'days' | 'hours';
|
|
880
430
|
}
|
|
881
431
|
type DispatchResult = {
|
|
882
432
|
ok: true;
|
|
883
433
|
changes: ChangeSet;
|
|
884
|
-
/**
|
|
885
|
-
* Solo los intents batch (`dates-batch` / `bulk-edit`): resultado
|
|
886
|
-
* POR EDIT, en el orden de `edits`. Un edit rechazado no aborta a
|
|
887
|
-
* los demás (semántica paste); el bridge re-proyecta solo los
|
|
888
|
-
* rechazados.
|
|
889
|
-
*/
|
|
890
434
|
verdicts?: ReadonlyArray<DatesBatchVerdict>;
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
* deleted/structurally-removed activity row, keyed by STRING id. The
|
|
894
|
-
* ChangeSet emits deleted rows as `{ kind:'deleted', after:null }` with no
|
|
895
|
-
* `before`, so resurrection on undo needs this. Populated by structural
|
|
896
|
-
* handlers (delete/move/paste); stripped before the result reaches the
|
|
897
|
-
* bridge in the Wave-3 integration.
|
|
898
|
-
*/
|
|
899
|
-
__beforeSnap?: ReadonlyMap<string, CoreActivity>;
|
|
900
|
-
/**
|
|
901
|
-
* INTERNAL (undo / B4). Incident links of deleted activities, keyed by
|
|
902
|
-
* STRING id (EntityChange link ids are String()-normalized). Carries the
|
|
903
|
-
* engine `LinkSnapshot` (lag in working hours) for unit-correct re-add.
|
|
904
|
-
*/
|
|
905
|
-
__beforeLinks?: ReadonlyMap<string, LinkSnapshot>;
|
|
435
|
+
activityVerdicts?: ReadonlyArray<DatesBatchVerdict>;
|
|
436
|
+
linkVerdicts?: ReadonlyArray<LinkBatchVerdict>;
|
|
906
437
|
} | {
|
|
907
438
|
ok: false;
|
|
908
439
|
reason: string;
|
|
@@ -917,39 +448,33 @@ type DatesBatchVerdict = {
|
|
|
917
448
|
reason: string;
|
|
918
449
|
alertKey?: string | undefined;
|
|
919
450
|
};
|
|
451
|
+
type LinkBatchVerdict = {
|
|
452
|
+
operationIndex: number;
|
|
453
|
+
kind: LinksBatchOperation['kind'];
|
|
454
|
+
ok: true;
|
|
455
|
+
linkId: string;
|
|
456
|
+
} | {
|
|
457
|
+
operationIndex: number;
|
|
458
|
+
kind: LinksBatchOperation['kind'];
|
|
459
|
+
ok: false;
|
|
460
|
+
reason: string;
|
|
461
|
+
};
|
|
920
462
|
|
|
921
463
|
interface TrackingEvent {
|
|
922
464
|
name: string;
|
|
923
465
|
properties: Record<string, unknown>;
|
|
924
466
|
}
|
|
925
|
-
/**
|
|
926
|
-
* Side effects a dispatch emits that are NOT entity-field changes and NOT
|
|
927
|
-
* Amplitude tracking — commands the bridge must act on. Today: SIR
|
|
928
|
-
* auto-reject (a frozen activity's dates changed or it was deleted, so its
|
|
929
|
-
* pending SIR must be rejected). The core owns the rule; the bridge consumes
|
|
930
|
-
* the effect (Redux REJECTED; durable persistence rides the activity save).
|
|
931
|
-
* See `SIR_MAP.md` §10.
|
|
932
|
-
*/
|
|
933
467
|
type ScheduleEffect = {
|
|
934
468
|
kind: 'sir-auto-reject';
|
|
935
469
|
activityId: ActivityId;
|
|
936
|
-
/** Backend SIR id == the front Redux item id (see parseFromBackend A1). */
|
|
937
470
|
sirId: string;
|
|
938
471
|
reason: 'date_changed' | 'activity_deleted';
|
|
939
472
|
};
|
|
940
|
-
/**
|
|
941
|
-
* A direct user edit violated the activity's own (pre-edit) constraint. Per
|
|
942
|
-
* the canonical model (PRD constraint violations, R2/R3): the edit APPLIES
|
|
943
|
-
* anyway — the warning is data for the UI (constraint validation modal),
|
|
944
|
-
* never a rejection, and it is only emitted from direct edits (the
|
|
945
|
-
* autoscheduler never violates, R1). Decision D-A 2026-07-04.
|
|
946
|
-
*/
|
|
947
473
|
interface ConstraintWarning {
|
|
948
474
|
kind: 'constraint_violation';
|
|
949
475
|
activityId: ActivityId;
|
|
950
476
|
constraintType: ConstraintType;
|
|
951
477
|
constraintDate: Date;
|
|
952
|
-
/** The projected date that violated (start or end, per constraint type). */
|
|
953
478
|
projectedDate: Date;
|
|
954
479
|
messageKey: string;
|
|
955
480
|
}
|
|
@@ -975,23 +500,12 @@ interface ChangeSet {
|
|
|
975
500
|
calendars: ReadonlyArray<EntityChange<Calendar>>;
|
|
976
501
|
trackingEvents: ReadonlyArray<TrackingEvent>;
|
|
977
502
|
viewState?: ReadonlyArray<ViewStateChange>;
|
|
978
|
-
/**
|
|
979
|
-
* Optional — present only when the dispatch produced side effects. Builders
|
|
980
|
-
* that emit none omit it; consumers read `changeSet.effects ?? []`. Kept
|
|
981
|
-
* optional to avoid churning every ChangeSet construction site. SIR (A4).
|
|
982
|
-
*/
|
|
983
503
|
effects?: ReadonlyArray<ScheduleEffect>;
|
|
984
|
-
/**
|
|
985
|
-
* Optional — present only when a direct edit violated a constraint (see
|
|
986
|
-
* `ConstraintWarning`). Consumers read `changeSet.warnings ?? []`.
|
|
987
|
-
*/
|
|
988
504
|
warnings?: ReadonlyArray<ConstraintWarning>;
|
|
989
505
|
}
|
|
990
506
|
|
|
991
507
|
interface ProjectWorkHours {
|
|
992
|
-
/** Earliest start of the working day across the week, `"HH:MM"`. */
|
|
993
508
|
startHour: string;
|
|
994
|
-
/** Latest end of the working day across the week, `"HH:MM"`. */
|
|
995
509
|
endHour: string;
|
|
996
510
|
}
|
|
997
511
|
|
|
@@ -1100,102 +614,18 @@ interface BackendScheduleInput {
|
|
|
1100
614
|
baseCalendars?: BackendCalendarInput[] | undefined;
|
|
1101
615
|
}
|
|
1102
616
|
|
|
1103
|
-
/**
|
|
1104
|
-
* Injected reporting port. The core is UI-agnostic: it cannot `console.*`,
|
|
1105
|
-
* show UI, or know about Sentry. When it hits a recoverable data-quality
|
|
1106
|
-
* issue (`warn`) or a failure it could not complete (`error`), it calls this
|
|
1107
|
-
* port; the consumer (react_client) implements it and decides the outcome
|
|
1108
|
-
* (Sentry, toast, nothing). Same injected-port pattern as `AutoSchedulerPort`.
|
|
1109
|
-
*/
|
|
1110
617
|
interface ScheduleCoreReporter {
|
|
1111
|
-
/** Recoverable data-quality issue; the core continues with its fallback. */
|
|
1112
618
|
warn(message: string, context?: unknown): void;
|
|
1113
|
-
/** A real failure the core could not complete. */
|
|
1114
619
|
error(message: string, cause?: unknown): void;
|
|
1115
620
|
}
|
|
1116
621
|
|
|
1117
|
-
/**
|
|
1118
|
-
* initialize-core — the construction + load-pass orchestration extracted from
|
|
1119
|
-
* the `ScheduleCore` constructor. `initializeCore(input)` performs the entire
|
|
1120
|
-
* load sequence (parse → snapshot → state → demote → id generators →
|
|
1121
|
-
* custom-id tracker → optional baseline block → initial passes) and returns
|
|
1122
|
-
* the assembled internals (`CoreInternals`) for the facade to assign. The
|
|
1123
|
-
* facade constructor is assignment-only.
|
|
1124
|
-
*
|
|
1125
|
-
* The load-pass ORDER here is a CONTRACT — see `CURSOR.md`
|
|
1126
|
-
* §"Flujo de core.dispatch paso a paso" and the inline comments below. Do not
|
|
1127
|
-
* reorder, merge, or drop any step.
|
|
1128
|
-
*
|
|
1129
|
-
* The public types (`ScheduleCoreStatus`, `ScheduleCoreInput`) live here so
|
|
1130
|
-
* `initialize-core.ts` never imports from `scheduleCore.ts` (which imports
|
|
1131
|
-
* `initializeCore`), avoiding an import cycle. `scheduleCore.ts` re-exports the
|
|
1132
|
-
* two public types
|
|
1133
|
-
* so `src/index.ts`'s existing `export type { ... } from './init/schedule-core.js'`
|
|
1134
|
-
* keeps resolving unchanged.
|
|
1135
|
-
*/
|
|
1136
|
-
|
|
1137
622
|
type ScheduleCoreStatus = 'ready' | 'destroyed' | 'poisoned';
|
|
1138
623
|
interface ScheduleCoreInput extends BackendScheduleInput {
|
|
1139
|
-
/**
|
|
1140
|
-
* Skip the full autoscheduler pass that normally runs from the
|
|
1141
|
-
* constructor (`runInitialPasses`).
|
|
1142
|
-
*
|
|
1143
|
-
* Backend data already ships with `start_date` / `end_date` / `duration`
|
|
1144
|
-
* scheduled — running the full ASAP+ALAP graph at load is redundant and
|
|
1145
|
-
* extremely slow on large schedules (thousands of activities + links).
|
|
1146
|
-
*
|
|
1147
|
-
* When `true`, the constructor still runs the lightweight bottom-up
|
|
1148
|
-
* post-processors (`updateParentBoundsFromChildren`) so parent bounds
|
|
1149
|
-
* and progress rollup are consistent. The autoscheduler runs lazily on
|
|
1150
|
-
* the first `dispatch(...)` call.
|
|
1151
|
-
*
|
|
1152
|
-
* Default: `false` (preserve existing behaviour). The bridge in
|
|
1153
|
-
* `react_client/` sets this to `true` for production loads.
|
|
1154
|
-
*/
|
|
1155
624
|
skipInitialAutoSchedule?: boolean;
|
|
1156
|
-
/**
|
|
1157
|
-
* Baseline points (backend `sectorbaselinepoint[]`, the `activityponts`
|
|
1158
|
-
* endpoint payload) to overlay at load. Each point maps to an activity by
|
|
1159
|
-
* `point.activityId` → `activity.proplannerId`. When present, the constructor
|
|
1160
|
-
* overlays them so the baseline columns + `expected_progress_base` can read the
|
|
1161
|
-
* ACTIVE point. NB: ponderators are NOT recomputed at load (backend ships the
|
|
1162
|
-
* value prod renders verbatim — recomputing diverges); `goCalculatePonderators`
|
|
1163
|
-
* is a save-time op. Omit (or pass `[]`) for projects with no baseline.
|
|
1164
|
-
*/
|
|
1165
625
|
baselinePoints?: readonly BaselinePoint[];
|
|
1166
|
-
/**
|
|
1167
|
-
* Clock port for time-dependent columns (`expected_progress*`). A FUNCTION
|
|
1168
|
-
* (not a frozen instant): the core calls it FRESH each time it needs "today"
|
|
1169
|
-
* (load + every dispatch that recomputes expected_progress), so the value
|
|
1170
|
-
* tracks the real day even on a long-lived session — never congelado.
|
|
1171
|
-
*
|
|
1172
|
-
* Opt-in (no default): omit it → the core does NOT compute `expected_progress`
|
|
1173
|
-
* (preserves the legacy path; keeps the test suite deterministic). Production
|
|
1174
|
-
* injects `() => new Date()`; tests inject `() => fixedDate` for reproducibility.
|
|
1175
|
-
* The core never calls `new Date()` itself — this port is the only time source.
|
|
1176
|
-
*/
|
|
1177
626
|
clock?: () => Date;
|
|
1178
|
-
/**
|
|
1179
|
-
* Critical-path mode at LOAD. The CP is ALWAYS computed; this flag only
|
|
1180
|
-
* decides WHEN `core.ready` is considered settled:
|
|
1181
|
-
* - `false` (default — front): `core.ready` resolves WITHOUT the CP (fast
|
|
1182
|
-
* load); the CP runs async and is delivered via `core.criticalPathReady`.
|
|
1183
|
-
* - `true` (backend, no front): `core.ready` WAITS for the CP — it is part of
|
|
1184
|
-
* the load (blocking). The caller does a single `await core.ready` and has
|
|
1185
|
-
* the dates + CP fields ready.
|
|
1186
|
-
*/
|
|
1187
627
|
criticalPathOnLoad?: boolean;
|
|
1188
|
-
/**
|
|
1189
|
-
* Initial status criterion (`'Baseline' | 'Actual'`) for the `status` column.
|
|
1190
|
-
* Not a backend field (client-only view pref); the client passes the current
|
|
1191
|
-
* value, defaulting to `'Baseline'`. Overrides the sector default when present.
|
|
1192
|
-
* Changed at runtime via `ScheduleCore.setStatusCriteria`.
|
|
1193
|
-
*/
|
|
1194
628
|
statusCriteria?: StatusCriteria;
|
|
1195
|
-
/**
|
|
1196
|
-
* Optional injected port for data-quality warnings and scheduling errors.
|
|
1197
|
-
* Defaults to a no-op when absent (the core never touches console/Sentry).
|
|
1198
|
-
*/
|
|
1199
629
|
reporter?: ScheduleCoreReporter;
|
|
1200
630
|
}
|
|
1201
631
|
|
|
@@ -1211,7 +641,7 @@ declare class ScheduleCore {
|
|
|
1211
641
|
get ready(): Promise<void>;
|
|
1212
642
|
get criticalPathReady(): Promise<{
|
|
1213
643
|
changes: ChangeSet;
|
|
1214
|
-
}>;
|
|
644
|
+
} | null>;
|
|
1215
645
|
get status(): ScheduleCoreStatus;
|
|
1216
646
|
getSector(): Readonly<SectorMetadata>;
|
|
1217
647
|
getActivityView(id: ActivityId): Readonly<CoreActivity> | null;
|
|
@@ -1224,13 +654,7 @@ declare class ScheduleCore {
|
|
|
1224
654
|
forEachActivityId(visit: (id: string) => void): void;
|
|
1225
655
|
getChildrenIds(parentId: ActivityId | '0'): ReadonlyArray<ActivityId>;
|
|
1226
656
|
getSelectedActivityIds(): string[];
|
|
1227
|
-
|
|
1228
|
-
* Every activity id in canonical DFS visual order (pre-order from roots,
|
|
1229
|
-
* siblings by `correlative_id` ASC) — ALL activities; filtering by
|
|
1230
|
-
* `visible` is the consumer's job. Memoized in the state and invalidated
|
|
1231
|
-
* on any structural mutation (add/remove/reparent/renumber), so repeated
|
|
1232
|
-
* reads between mutations are O(1).
|
|
1233
|
-
*/
|
|
657
|
+
getHiddenActivityIds(): string[];
|
|
1234
658
|
getVisualOrderIds(): ReadonlyArray<ActivityId>;
|
|
1235
659
|
hasChild(parentId: ActivityId | '0'): boolean;
|
|
1236
660
|
getCalendar(id: CalendarId): Readonly<Calendar> | null;
|
|
@@ -1243,52 +667,30 @@ declare class ScheduleCore {
|
|
|
1243
667
|
private _enqueue;
|
|
1244
668
|
dispatch(action: DispatchAction, options?: DispatchOptions): Promise<DispatchResult>;
|
|
1245
669
|
private _dispatchInner;
|
|
1246
|
-
/**
|
|
1247
|
-
* Starts or joins the Critical Path calculation for the current schedule
|
|
1248
|
-
* revision. Snapshot capture and the final commit are serialized with user
|
|
1249
|
-
* mutations, but the expensive calculation runs outside `_opQueue` against
|
|
1250
|
-
* an isolated state. A newer revision aborts this job and makes its result
|
|
1251
|
-
* ineligible to commit.
|
|
1252
|
-
*/
|
|
1253
670
|
recomputeCriticalPath(): Promise<{
|
|
1254
671
|
changes: ChangeSet;
|
|
1255
672
|
} | null>;
|
|
1256
673
|
isCriticalPathSettled(): boolean;
|
|
1257
674
|
whenCriticalPathSettled(): Promise<void>;
|
|
675
|
+
private _withReappliedFilter;
|
|
676
|
+
private _reapplyActiveFilter;
|
|
1258
677
|
private _recordScheduleMutation;
|
|
1259
678
|
private _startCriticalPathForCurrentRevision;
|
|
1260
679
|
private _runCriticalPathAndCapture;
|
|
1261
|
-
/**
|
|
1262
|
-
* Undo/Redo restores the user's historical mutation while retaining current
|
|
1263
|
-
* non-historical truth (for example a refreshed baseline). Re-derive every
|
|
1264
|
-
* value that depends on both so the restored model is immediately coherent.
|
|
1265
|
-
*/
|
|
1266
680
|
private _recomputeAfterHistoryRestore;
|
|
1267
681
|
undo(): Promise<ChangeSet | null>;
|
|
1268
682
|
redo(): Promise<ChangeSet | null>;
|
|
1269
683
|
canUndo(): boolean;
|
|
1270
684
|
canRedo(): boolean;
|
|
1271
|
-
/**
|
|
1272
|
-
* Establishes a new persistence boundary without mutating schedule state.
|
|
1273
|
-
* Completed saves call this synchronously so neither prior undo entries nor
|
|
1274
|
-
* their redo branch can cross the persisted boundary.
|
|
1275
|
-
*/
|
|
1276
685
|
clearHistory(): void;
|
|
1277
686
|
undoDepth(): number;
|
|
1278
687
|
private _resyncCustomIdTrackerFromModel;
|
|
1279
688
|
destroy(): void;
|
|
1280
689
|
private readonly _initPromise;
|
|
1281
|
-
private
|
|
690
|
+
private _criticalPathReady;
|
|
1282
691
|
private readonly _ready;
|
|
1283
692
|
private readonly _saveTracker;
|
|
1284
693
|
private assertReady;
|
|
1285
|
-
/**
|
|
1286
|
-
* Revert the current dispatch's mutations from the write-capture journal. If
|
|
1287
|
-
* the restore ITSELF throws, the state may be a third, partially-inverted
|
|
1288
|
-
* state — worse than either endpoint — so poison the core: refuse all further
|
|
1289
|
-
* dispatches and surface the fault so the host reloads from backend. A failed
|
|
1290
|
-
* rollback is never swallowed.
|
|
1291
|
-
*/
|
|
1292
694
|
private _rollback;
|
|
1293
695
|
}
|
|
1294
696
|
|
|
@@ -1305,25 +707,6 @@ interface ParsedInput {
|
|
|
1305
707
|
}
|
|
1306
708
|
declare function parseFromBackend(input: BackendScheduleInput, reporter?: ScheduleCoreReporter): ParsedInput;
|
|
1307
709
|
|
|
1308
|
-
/**
|
|
1309
|
-
* Returns the ACTIVE baseline point of an activity, or null.
|
|
1310
|
-
*
|
|
1311
|
-
* Ported verbatim from the legacy selector used across the schedule
|
|
1312
|
-
* (`react_client/src/views/ganttContainer/gantt/gantt.helper.js`
|
|
1313
|
-
* calculatePonderators / getDurationRecursively, and the baseline columns
|
|
1314
|
-
* `startBaseCol`…`durationBaseCol`):
|
|
1315
|
-
*
|
|
1316
|
-
* activity.baseline_points.find(b => b.sectorbaselineversion?.active)
|
|
1317
|
-
*
|
|
1318
|
-
* Exactly one version per sector is active. Returns null when the activity
|
|
1319
|
-
* has no `baseline_points`, an empty array, or no point whose version is
|
|
1320
|
-
* active — matching the legacy behavior where such activities get
|
|
1321
|
-
* `ponderator = 0` (baseline-only, no fallback to real values; see memory
|
|
1322
|
-
* `project_ponderator_baseline_fix`).
|
|
1323
|
-
*
|
|
1324
|
-
* The `active` flag is treated as truthy (not strictly `=== true`) to match
|
|
1325
|
-
* the legacy `if (base.sectorbaselineversion.active)` check.
|
|
1326
|
-
*/
|
|
1327
710
|
declare function getActiveBaseline(activity: {
|
|
1328
711
|
baselinePoints?: readonly CoreBaselinePoint[];
|
|
1329
712
|
} | null | undefined): CoreBaselinePoint | null;
|
|
@@ -1331,135 +714,48 @@ declare function getActiveBaseline(activity: {
|
|
|
1331
714
|
interface CalendarLike {
|
|
1332
715
|
calculateDuration(start: Date, end: Date): number;
|
|
1333
716
|
}
|
|
1334
|
-
/**
|
|
1335
|
-
* Expected % a baseline-planned activity should have completed by `now`,
|
|
1336
|
-
* measured in working time against its baseline calendar. Faithful port of
|
|
1337
|
-
* legacy `calculateExpected` (lookahead-common.js): edge rules first, else the
|
|
1338
|
-
* working-time ratio. Returns 0..100. `now` should already be the comparison
|
|
1339
|
-
* instant the caller wants (e.g. end-of-day).
|
|
1340
|
-
*
|
|
1341
|
-
* Shared by the `expected_progress` (live) and `expected_progress_base` columns
|
|
1342
|
-
* (column-owns-everything: the formula is the one piece both columns share).
|
|
1343
|
-
*/
|
|
1344
717
|
declare function expectedProgressFromBaseline(start: Date, end: Date, now: Date, calendar: CalendarLike): number;
|
|
1345
718
|
|
|
1346
719
|
interface ExpectedProgressAdapter {
|
|
1347
720
|
getChildrenIds(parentId: string | 0): readonly string[];
|
|
1348
721
|
getActivity(id: string): Record<string, unknown> | null;
|
|
1349
722
|
setActivityField(id: string, field: string, value: unknown): void;
|
|
1350
|
-
/** Resolve a baseline calendar by its engine id (`${baseCalendarId}-base`). */
|
|
1351
723
|
getBaseCalendar(engineId: string): CalendarLike | null;
|
|
1352
724
|
}
|
|
1353
|
-
/**
|
|
1354
|
-
* Walks the tree from `rootIds`, writing `expected_progress_base` on every
|
|
1355
|
-
* activity: leaves from their baseline calendar, parents as
|
|
1356
|
-
* `Σ(childBase × child.ponderator) / 100` (faithful port of engine.ts
|
|
1357
|
-
* aggregateHierarchy). Returns the ids whose value changed.
|
|
1358
|
-
*/
|
|
1359
725
|
declare function computeExpectedProgress(rootIds: readonly string[], now: Date, adapter: ExpectedProgressAdapter, defaultBaseCalendarId?: string | null): string[];
|
|
1360
726
|
|
|
1361
727
|
type StaticActivityDefaults = Omit<CoreActivity, 'id' | 'parentId' | 'name' | 'startDate' | 'endDate' | 'durationHours' | 'calendarId' | 'uniqueCorrelativeId'>;
|
|
1362
728
|
declare const NEW_ACTIVITY_DEFAULTS: Readonly<StaticActivityDefaults>;
|
|
1363
729
|
|
|
1364
|
-
/**
|
|
1365
|
-
* Schedule-core equivalent of the legacy frontend `checkNoUpdatedLinks`.
|
|
1366
|
-
*
|
|
1367
|
-
* Returns the CURRENT links that were MODIFIED relative to a `baseline` (the
|
|
1368
|
-
* last loaded/saved link state). A link is "modified" iff its `lag` or `type`
|
|
1369
|
-
* differs from its baseline counterpart (matched by `id`).
|
|
1370
|
-
*
|
|
1371
|
-
* Why only lag/type: empirically those are the only mutable fields of a link —
|
|
1372
|
-
* `source`/`target` are identity, and the rest are backend/derived. The core
|
|
1373
|
-
* `link-update` intent (`dispatch/types.ts`) changes exactly "lag and/or type",
|
|
1374
|
-
* so this comparison is complete.
|
|
1375
|
-
*
|
|
1376
|
-
* New links (absent from baseline) and deleted links (present only in baseline)
|
|
1377
|
-
* are NOT "modified" — those belong to the unsaved / deleted buckets. The
|
|
1378
|
-
* baseline is supplied by the caller (the save flow's reference snapshot); per
|
|
1379
|
-
* interface discipline this is a pure helper, not a method on the core/port.
|
|
1380
|
-
*/
|
|
1381
730
|
declare function checkNoUpdatedLinks(baseline: readonly Link[], current: readonly Link[]): Link[];
|
|
1382
731
|
|
|
1383
|
-
/**
|
|
1384
|
-
* Schedule-core equivalent of the legacy frontend `checkNoSavedActivities` /
|
|
1385
|
-
* `checkNoSavedLinks`: an entity is "unsaved" when it has no backend id
|
|
1386
|
-
* (`proplannerId`) — i.e. it was created in-session and not yet persisted.
|
|
1387
|
-
*
|
|
1388
|
-
* Pure helper (same `!proplannerId` criterion as legacy, so 0/null/undefined
|
|
1389
|
-
* all count as unsaved). Works on `core.getAllActivitiesView()` / `getAllLinks()`
|
|
1390
|
-
* or on `gantt.serialize().data` — both carry `proplannerId`. Per interface
|
|
1391
|
-
* discipline this is a helper, not a method on the core/port.
|
|
1392
|
-
*/
|
|
1393
732
|
interface WithProplannerId {
|
|
1394
733
|
proplannerId?: number | null;
|
|
1395
734
|
[key: string]: unknown;
|
|
1396
735
|
}
|
|
1397
736
|
declare const getUnsavedActivities: <T extends WithProplannerId>(activities?: readonly T[]) => T[];
|
|
1398
737
|
|
|
1399
|
-
/**
|
|
1400
|
-
* Returns a microtask-priority yield. Resolves on the next event-loop
|
|
1401
|
-
* tick — the browser is free to paint, handle input, or process other
|
|
1402
|
-
* tasks in between.
|
|
1403
|
-
*/
|
|
1404
738
|
declare function yieldToBrowser(): Promise<void>;
|
|
1405
739
|
|
|
1406
|
-
/**
|
|
1407
|
-
* Does this dispatch recompute the critical path? The single authority for the
|
|
1408
|
-
* question, shared by the dispatch gate (`resolveDerivedPasses`) and the
|
|
1409
|
-
* bridge, which reads it to defer the CP out of the paint. Mirrors legacy: the
|
|
1410
|
-
* CP re-derives on every scheduling change. Prop-only/administrative intents
|
|
1411
|
-
* and edits that touch only non-scheduling columns leave the current CP
|
|
1412
|
-
* revision intact; structural reparents are never exempt.
|
|
1413
|
-
*/
|
|
1414
740
|
declare function willRunCriticalPath(action: DispatchAction): boolean;
|
|
1415
741
|
|
|
1416
|
-
/** Activity types */
|
|
1417
742
|
declare const ACTIVITY_TYPE: {
|
|
1418
743
|
readonly TASK: "task";
|
|
1419
744
|
readonly PROJECT: "project";
|
|
1420
745
|
readonly MILESTONE: "milestone";
|
|
1421
746
|
};
|
|
1422
747
|
|
|
1423
|
-
/**
|
|
1424
|
-
* Root-parent sentinel — single source of truth.
|
|
1425
|
-
*
|
|
1426
|
-
* Root-level activities have meant "root" under several shapes across the
|
|
1427
|
-
* codebase and the recorded data: string `'0'` (post-parse domain model),
|
|
1428
|
-
* numeric `0` (DHTMLX / engine seam), and nullish. `isRootParent` accepts
|
|
1429
|
-
* all of them; `normalizeParentKey` collapses them to the canonical `'0'`.
|
|
1430
|
-
*
|
|
1431
|
-
* NOTE: `'0'` is overloaded elsewhere in the domain (FS link-type code,
|
|
1432
|
-
* correlative ids). These constants are ONLY for the parent axis.
|
|
1433
|
-
*/
|
|
1434
|
-
/** Canonical root-parent id in the post-parse domain model. */
|
|
1435
748
|
declare const ROOT_PARENT_ID: "0";
|
|
1436
|
-
/** True when `parent` denotes the root level, under any historical shape. */
|
|
1437
749
|
declare function isRootParent(parent: unknown): boolean;
|
|
1438
|
-
/** Collapse any root shape to the canonical `'0'`; stringify the rest. */
|
|
1439
750
|
declare function normalizeParentKey(parent: unknown): string;
|
|
1440
751
|
|
|
1441
|
-
/**
|
|
1442
|
-
* Canonical bidirectional map between DHTMLX link kinds ('0'-'3') and the
|
|
1443
|
-
* backend/display two-letter codes (fs/ss/ff/sf), plus the predecessor
|
|
1444
|
-
* display-string vocabulary.
|
|
1445
|
-
*
|
|
1446
|
-
* Single source of truth — replaces the hand-maintained copies that lived in
|
|
1447
|
-
* parse-predecessor-string (code→number), apply-link-operation
|
|
1448
|
-
* (number→code), boundary/backend parseFromBackend (code→number) and
|
|
1449
|
-
* inverses (number→code). The mutual `satisfies Record<…>` constraints make
|
|
1450
|
-
* omitting or typo'ing a key on either side a compile error.
|
|
1451
|
-
*/
|
|
1452
|
-
|
|
1453
|
-
/** Backend/display two-letter link codes. */
|
|
1454
752
|
type LinkTypeCode = 'fs' | 'ss' | 'ff' | 'sf';
|
|
1455
|
-
/** DHTMLX numeric kind → backend/display code. */
|
|
1456
753
|
declare const LINK_TYPE_CODE: {
|
|
1457
754
|
readonly "0": "fs";
|
|
1458
755
|
readonly "1": "ss";
|
|
1459
756
|
readonly "2": "ff";
|
|
1460
757
|
readonly "3": "sf";
|
|
1461
758
|
};
|
|
1462
|
-
/** Backend/display code → DHTMLX numeric kind (inverse of LINK_TYPE_CODE). */
|
|
1463
759
|
declare const LINK_CODE_TO_TYPE: {
|
|
1464
760
|
readonly fs: "0";
|
|
1465
761
|
readonly ss: "1";
|
|
@@ -1467,49 +763,10 @@ declare const LINK_CODE_TO_TYPE: {
|
|
|
1467
763
|
readonly sf: "3";
|
|
1468
764
|
};
|
|
1469
765
|
|
|
1470
|
-
/**
|
|
1471
|
-
* Inverse boundary maps (domain → backend vocabulary).
|
|
1472
|
-
*
|
|
1473
|
-
* The forward translations live in `constants.ts` (`CONSTRAINT_LABEL_MAP`)
|
|
1474
|
-
* and `link-display.ts` (`LINK_CODE_TO_NUMBER`). The *serialization*
|
|
1475
|
-
* core → backend is intentionally NOT owned by this package today — it
|
|
1476
|
-
* lives in the consumer bridge (`react_client/gantt.helper.js`,
|
|
1477
|
-
* `from_number_to_code` / `GanttConstraint` reverse lookup) because the
|
|
1478
|
-
* bridge is the source of truth for what the server expects on save.
|
|
1479
|
-
*
|
|
1480
|
-
* These inverses exist so the mapping is documented and testable next to
|
|
1481
|
-
* its forward counterpart, and so a future `core → backend` layer doesn't
|
|
1482
|
-
* re-derive them by hand. **Internal only — not exported in `src/index.ts`.**
|
|
1483
|
-
* See Obsidian `BOUNDARY_TRANSLATIONS.md` §"Mapeos inversos".
|
|
1484
|
-
*/
|
|
1485
|
-
|
|
1486
|
-
/** Inverse of `CONSTRAINT_LABEL_MAP` — internal code → backend label. */
|
|
1487
766
|
declare const CONSTRAINT_TYPE_TO_LABEL: Record<ConstraintType, string>;
|
|
1488
767
|
|
|
1489
|
-
/**
|
|
1490
|
-
* Working-day vocabulary — genuine cross-component primitive (creation
|
|
1491
|
-
* defaults, internal/state context fallbacks, link lag display). The value
|
|
1492
|
-
* is the FALLBACK only; a sector- or calendar-provided hoursPerDay always
|
|
1493
|
-
* takes precedence at every consumer.
|
|
1494
|
-
*/
|
|
1495
768
|
declare const DEFAULT_HOURS_PER_DAY = 8;
|
|
1496
769
|
|
|
1497
|
-
/**
|
|
1498
|
-
* Canonical catalog of `DispatchAction` kinds.
|
|
1499
|
-
*
|
|
1500
|
-
* The discriminated union in `types.ts` remains the source of truth; this
|
|
1501
|
-
* module exposes it as RUNTIME vocabulary so `.js` consumers (bridge
|
|
1502
|
-
* entry-points, guard tests) stop retyping the wire strings. Exhaustiveness
|
|
1503
|
-
* is compile-checked HERE (not in the guard test — `tsconfig.json` excludes
|
|
1504
|
-
* `*.test.ts` from `tsc --noEmit` and vitest does not typecheck):
|
|
1505
|
-
* - `satisfies Record<string, DispatchActionKind>` rejects any entry whose
|
|
1506
|
-
* value is not a union member (catalog ⊆ union);
|
|
1507
|
-
* - `KIND_CATALOG_COVERS_UNION: Record<DispatchActionKind, true>` requires
|
|
1508
|
-
* one entry per union member (union ⊆ catalog) — adding a kind to
|
|
1509
|
-
* `DispatchAction` without updating this module breaks the build.
|
|
1510
|
-
* The string VALUES are a frozen contract (see `constants.guard.test.ts`).
|
|
1511
|
-
*/
|
|
1512
|
-
|
|
1513
770
|
type DispatchActionKind = DispatchAction['kind'];
|
|
1514
771
|
declare const DISPATCH_ACTION_KIND: {
|
|
1515
772
|
readonly PERSISTENCE_ACKNOWLEDGE: "persistence-acknowledge";
|
|
@@ -1533,28 +790,12 @@ declare const DISPATCH_ACTION_KIND: {
|
|
|
1533
790
|
readonly SELECTION_TOGGLE: "selection-toggle";
|
|
1534
791
|
readonly SELECTION_REPLACE: "selection-replace";
|
|
1535
792
|
readonly VISIBILITY_SET: "visibility-set";
|
|
793
|
+
readonly FILTER_SET: "filter-set";
|
|
1536
794
|
readonly SIR_SYNC: "sir-sync";
|
|
1537
795
|
readonly ACTIVITY_LOOKAHEAD_SYNC: "activity-lookahead-sync";
|
|
1538
796
|
};
|
|
1539
797
|
declare const DISPATCH_ACTION_KINDS: ReadonlyArray<DispatchActionKind>;
|
|
1540
798
|
|
|
1541
|
-
/**
|
|
1542
|
-
* Canonical vocabulary of activity-creation triggers.
|
|
1543
|
-
*
|
|
1544
|
-
* The engine's `activity-create` intent does NOT carry this field — these
|
|
1545
|
-
* kinds name the USER trigger the consumer's creation hub routes on before
|
|
1546
|
-
* dispatching (`requestActivityCreation` / `CreateActivityIntent` in
|
|
1547
|
-
* `react_client` core path). The engine owns the vocabulary so the client
|
|
1548
|
-
* and the bridge import ONE canonical source instead of retyping the
|
|
1549
|
-
* literals (CONSTANTES_DECISIONES paso 1). The string VALUES are a frozen
|
|
1550
|
-
* contract — verified verbatim against the client union
|
|
1551
|
-
* (`core/features/createActivity/intents.ts`) on 2026-07-02.
|
|
1552
|
-
*
|
|
1553
|
-
* - `CHILD` — per-row "+" button (runs the lookahead guard).
|
|
1554
|
-
* - `CHILD_CONFIRMED` — lookahead-cleanup modal confirm (guard already passed).
|
|
1555
|
-
* - `LINE` — green bar "add-task-by-line".
|
|
1556
|
-
* - `ROOT` — generic "+" (header / create), no guard.
|
|
1557
|
-
*/
|
|
1558
799
|
declare const CREATION_KIND: {
|
|
1559
800
|
readonly CHILD: "child";
|
|
1560
801
|
readonly CHILD_CONFIRMED: "child-confirmed";
|
|
@@ -1563,16 +804,6 @@ declare const CREATION_KIND: {
|
|
|
1563
804
|
};
|
|
1564
805
|
type CreationKind = (typeof CREATION_KIND)[keyof typeof CREATION_KIND];
|
|
1565
806
|
|
|
1566
|
-
/**
|
|
1567
|
-
* Canonical catalog of dispatch rejection reasons.
|
|
1568
|
-
*
|
|
1569
|
-
* `DispatchResult.reason` stays `string` on purpose: it is the cross-domain
|
|
1570
|
-
* bag that also carries pipeline gate codes (`ParseErrorCode`,
|
|
1571
|
-
* `ValidationReason`, `EditDenialReason`) and the link-engine rejected
|
|
1572
|
-
* verdicts. This module covers the reasons DISPATCH ITSELF produces, so
|
|
1573
|
-
* producers and tests share one compile-checked source. The string VALUES
|
|
1574
|
-
* are a frozen contract — the bridge matches on them.
|
|
1575
|
-
*/
|
|
1576
807
|
declare const REJECTION_REASON: {
|
|
1577
808
|
readonly CANNOT_EDIT: "cannot_edit";
|
|
1578
809
|
readonly PARSE_ERROR: "parse_error";
|
|
@@ -1596,11 +827,6 @@ declare const REJECTION_REASON: {
|
|
|
1596
827
|
};
|
|
1597
828
|
type DispatchRejectReason = (typeof REJECTION_REASON)[keyof typeof REJECTION_REASON];
|
|
1598
829
|
|
|
1599
|
-
/**
|
|
1600
|
-
* Amplitude event names emitted by the dispatch layer (structure mutations).
|
|
1601
|
-
* Analytics CONTRACT — values must stay byte-identical to production.
|
|
1602
|
-
* Column-level entry events live in `columns/shared/trackingEvents.ts`.
|
|
1603
|
-
*/
|
|
1604
830
|
declare const DISPATCH_TRACK_EVENT: {
|
|
1605
831
|
readonly ACTIVITY_CREATION: "schedule_activity_creation";
|
|
1606
832
|
readonly ACTIVITY_DELETION: "schedule_activity_deletion";
|
|
@@ -1610,4 +836,4 @@ declare const DISPATCH_TRACK_EVENT: {
|
|
|
1610
836
|
};
|
|
1611
837
|
type DispatchTrackEvent = (typeof DISPATCH_TRACK_EVENT)[keyof typeof DISPATCH_TRACK_EVENT];
|
|
1612
838
|
|
|
1613
|
-
export { ACTIVITY_TYPE, type ActivityCreter, type ActivityId, type ActivityType, type BackendActivityInput, type BackendCalendarInput, type BackendLinkInput, type BackendScheduleInput, type BackendSectorInput, type BaselinePoint, type BaselineVersion, CALENDAR_UNIT, COLUMN, CONSTRAINT_TYPE, CONSTRAINT_TYPE_TO_LABEL, CREATION_KIND, type Calendar, type CalendarId, type CalendarUnit, type CalendarWorktime, type ChangeSet, type ColumnName, type ConstraintType, type ConstraintWarning, type CoreActivity, type CreationKind, DEFAULT_HOURS_PER_DAY, DISPATCH_ACTION_KIND, DISPATCH_ACTION_KINDS, DISPATCH_TRACK_EVENT, type DispatchAction, type DispatchActionKind, type DispatchOptions, type DispatchRejectReason, type DispatchResult, type DispatchTrackEvent, type EntityChange, LINK_CODE_TO_TYPE, LINK_TYPE, LINK_TYPE_CODE, type Link, type LinkId, type LinkType, type LinkTypeCode, type LinksBatchOperation, NEW_ACTIVITY_DEFAULTS, type ParsedInput, type PastedActivityInput, type PastedLinkInput, type PendingRequest, type PersistedEntityIdentity, REJECTION_REASON, ROOT_PARENT_ID, ScheduleCore, type ScheduleCoreInput, type ScheduleCoreReporter, type ScheduleCoreStatus, type ScheduleEffect, type SectorMetadata, type StatusCriteria, type TrackingEvent, WORK_TIME_DIRECTION, type WorkTimeDirection, checkNoUpdatedLinks, computeExpectedProgress, expectedProgressFromBaseline, getActiveBaseline, getUnsavedActivities, isRootParent, normalizeParentKey, parseFromBackend, willRunCriticalPath, yieldToBrowser };
|
|
839
|
+
export { ACTIVITY_TYPE, type ActivityCreter, type ActivityId, type ActivityType, type BackendActivityInput, type BackendCalendarInput, type BackendLinkInput, type BackendScheduleInput, type BackendSectorInput, type BaselinePoint, type BaselineVersion, CALENDAR_UNIT, COLUMN, CONSTRAINT_TYPE, CONSTRAINT_TYPE_TO_LABEL, CREATION_KIND, type Calendar, type CalendarId, type CalendarUnit, type CalendarWorktime, type ChangeSet, type ColumnName, type ConstraintType, type ConstraintWarning, type CoreActivity, type CreationKind, DEFAULT_HOURS_PER_DAY, DISPATCH_ACTION_KIND, DISPATCH_ACTION_KINDS, DISPATCH_TRACK_EVENT, type DispatchAction, type DispatchActionKind, type DispatchOptions, type DispatchRejectReason, type DispatchResult, type DispatchTrackEvent, type EntityChange, type FilterCriterion, type FilterDateRange, type FilterField, type FilterState, LINK_CODE_TO_TYPE, LINK_TYPE, LINK_TYPE_CODE, type Link, type LinkId, type LinkType, type LinkTypeCode, type LinksBatchOperation, NEW_ACTIVITY_DEFAULTS, type ParsedInput, type PastedActivityInput, type PastedLinkInput, type PendingRequest, type PersistedEntityIdentity, REJECTION_REASON, ROOT_PARENT_ID, ScheduleCore, type ScheduleCoreInput, type ScheduleCoreReporter, type ScheduleCoreStatus, type ScheduleEffect, type SectorMetadata, type StatusCriteria, type TrackingEvent, WORK_TIME_DIRECTION, type WorkTimeDirection, checkNoUpdatedLinks, computeExpectedProgress, expectedProgressFromBaseline, getActiveBaseline, getUnsavedActivities, isRootParent, normalizeParentKey, parseFromBackend, willRunCriticalPath, yieldToBrowser };
|