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