@outbuild-company/schedule-core 1.35.2 → 1.36.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/build-fingerprint.json +2 -2
- package/dist/cdn/schedule-core.global.js +1 -1
- package/dist/cdn/schedule-core.global.js.map +1 -1
- package/dist/index.cjs +53 -63
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -7
- package/dist/index.d.ts +17 -7
- package/dist/index.js +53 -63
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -685,9 +685,9 @@ interface GroupLevelWindow {
|
|
|
685
685
|
readonly depth: number;
|
|
686
686
|
}
|
|
687
687
|
/**
|
|
688
|
-
* One grouping level
|
|
689
|
-
*
|
|
690
|
-
*
|
|
688
|
+
* One grouping level: the attribute to band by, the window of its outline levels
|
|
689
|
+
* that becomes bands, and the band order. The primary level lives on `GroupState`
|
|
690
|
+
* itself; every further level is chained through `GroupState.nested`.
|
|
691
691
|
*/
|
|
692
692
|
interface GroupCriterion extends GroupLevelWindow {
|
|
693
693
|
readonly attributeKey: string;
|
|
@@ -704,11 +704,15 @@ interface GroupCriterion extends GroupLevelWindow {
|
|
|
704
704
|
type WbsDepth = number | null;
|
|
705
705
|
/** The depth that leaves no WBS row on screen. */
|
|
706
706
|
declare const FLAT_WBS_DEPTH = 0;
|
|
707
|
-
/**
|
|
707
|
+
/**
|
|
708
|
+
* Runtime grouping configuration active on a schedule. The interface itself is
|
|
709
|
+
* the primary criterion; `nested` holds the criteria chained below it, in order,
|
|
710
|
+
* so a schedule can band by several attributes at once.
|
|
711
|
+
*/
|
|
708
712
|
interface GroupState extends GroupCriterion {
|
|
709
713
|
readonly includeWbs: boolean;
|
|
710
714
|
readonly collapsedIds: ReadonlySet<string>;
|
|
711
|
-
readonly
|
|
715
|
+
readonly nested: ReadonlyArray<GroupCriterion>;
|
|
712
716
|
}
|
|
713
717
|
/**
|
|
714
718
|
* JSON-friendly criterion. `startLevel` is optional so views persisted before
|
|
@@ -721,11 +725,17 @@ interface GroupCriterionInput {
|
|
|
721
725
|
readonly depth: number;
|
|
722
726
|
readonly direction: OrderDirection;
|
|
723
727
|
}
|
|
724
|
-
/**
|
|
728
|
+
/**
|
|
729
|
+
* JSON-friendly grouping command accepted by `group-set`. `nested` carries the
|
|
730
|
+
* levels chained below the primary, in order; `secondary` is the legacy
|
|
731
|
+
* single-nested-level field kept so views persisted before chaining still
|
|
732
|
+
* deserialize, and it is read only when `nested` is absent.
|
|
733
|
+
*/
|
|
725
734
|
interface GroupStateInput extends GroupCriterionInput {
|
|
726
735
|
readonly includeWbs: boolean;
|
|
727
736
|
readonly collapsedIds: ReadonlyArray<string>;
|
|
728
737
|
readonly secondary?: GroupCriterionInput | null;
|
|
738
|
+
readonly nested?: ReadonlyArray<GroupCriterionInput>;
|
|
729
739
|
}
|
|
730
740
|
/** A single display row: either a synthetic group band or a real activity. */
|
|
731
741
|
type VisualRow = {
|
|
@@ -743,7 +753,7 @@ type VisualRow = {
|
|
|
743
753
|
declare function buildGroupRowId(attributeKey: string, valueId: string): string;
|
|
744
754
|
/**
|
|
745
755
|
* Extends a band id with a nested level. The parent path has to stay in the id
|
|
746
|
-
* because the same
|
|
756
|
+
* because the same nested value shows up under several parent bands, and
|
|
747
757
|
* consumers key rows (and persisted collapse state) by this id.
|
|
748
758
|
*/
|
|
749
759
|
declare function appendGroupRowId(parentRowId: string, attributeKey: string, valueId: string): string;
|
package/dist/index.d.ts
CHANGED
|
@@ -685,9 +685,9 @@ interface GroupLevelWindow {
|
|
|
685
685
|
readonly depth: number;
|
|
686
686
|
}
|
|
687
687
|
/**
|
|
688
|
-
* One grouping level
|
|
689
|
-
*
|
|
690
|
-
*
|
|
688
|
+
* One grouping level: the attribute to band by, the window of its outline levels
|
|
689
|
+
* that becomes bands, and the band order. The primary level lives on `GroupState`
|
|
690
|
+
* itself; every further level is chained through `GroupState.nested`.
|
|
691
691
|
*/
|
|
692
692
|
interface GroupCriterion extends GroupLevelWindow {
|
|
693
693
|
readonly attributeKey: string;
|
|
@@ -704,11 +704,15 @@ interface GroupCriterion extends GroupLevelWindow {
|
|
|
704
704
|
type WbsDepth = number | null;
|
|
705
705
|
/** The depth that leaves no WBS row on screen. */
|
|
706
706
|
declare const FLAT_WBS_DEPTH = 0;
|
|
707
|
-
/**
|
|
707
|
+
/**
|
|
708
|
+
* Runtime grouping configuration active on a schedule. The interface itself is
|
|
709
|
+
* the primary criterion; `nested` holds the criteria chained below it, in order,
|
|
710
|
+
* so a schedule can band by several attributes at once.
|
|
711
|
+
*/
|
|
708
712
|
interface GroupState extends GroupCriterion {
|
|
709
713
|
readonly includeWbs: boolean;
|
|
710
714
|
readonly collapsedIds: ReadonlySet<string>;
|
|
711
|
-
readonly
|
|
715
|
+
readonly nested: ReadonlyArray<GroupCriterion>;
|
|
712
716
|
}
|
|
713
717
|
/**
|
|
714
718
|
* JSON-friendly criterion. `startLevel` is optional so views persisted before
|
|
@@ -721,11 +725,17 @@ interface GroupCriterionInput {
|
|
|
721
725
|
readonly depth: number;
|
|
722
726
|
readonly direction: OrderDirection;
|
|
723
727
|
}
|
|
724
|
-
/**
|
|
728
|
+
/**
|
|
729
|
+
* JSON-friendly grouping command accepted by `group-set`. `nested` carries the
|
|
730
|
+
* levels chained below the primary, in order; `secondary` is the legacy
|
|
731
|
+
* single-nested-level field kept so views persisted before chaining still
|
|
732
|
+
* deserialize, and it is read only when `nested` is absent.
|
|
733
|
+
*/
|
|
725
734
|
interface GroupStateInput extends GroupCriterionInput {
|
|
726
735
|
readonly includeWbs: boolean;
|
|
727
736
|
readonly collapsedIds: ReadonlyArray<string>;
|
|
728
737
|
readonly secondary?: GroupCriterionInput | null;
|
|
738
|
+
readonly nested?: ReadonlyArray<GroupCriterionInput>;
|
|
729
739
|
}
|
|
730
740
|
/** A single display row: either a synthetic group band or a real activity. */
|
|
731
741
|
type VisualRow = {
|
|
@@ -743,7 +753,7 @@ type VisualRow = {
|
|
|
743
753
|
declare function buildGroupRowId(attributeKey: string, valueId: string): string;
|
|
744
754
|
/**
|
|
745
755
|
* Extends a band id with a nested level. The parent path has to stay in the id
|
|
746
|
-
* because the same
|
|
756
|
+
* because the same nested value shows up under several parent bands, and
|
|
747
757
|
* consumers key rows (and persisted collapse state) by this id.
|
|
748
758
|
*/
|
|
749
759
|
declare function appendGroupRowId(parentRowId: string, attributeKey: string, valueId: string): string;
|
package/dist/index.js
CHANGED
|
@@ -2304,24 +2304,37 @@ function toLevelWindow(input) {
|
|
|
2304
2304
|
return { startLevel, depth: input.depth };
|
|
2305
2305
|
}
|
|
2306
2306
|
var INVALID_CRITERION = /* @__PURE__ */ Symbol("invalid-group-criterion");
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
if (
|
|
2310
|
-
if (typeof
|
|
2311
|
-
if (typeof secondary.attributeKey !== "string" || secondary.attributeKey.length === 0) {
|
|
2307
|
+
var MAX_NESTED_GROUP_CRITERIA = 3;
|
|
2308
|
+
function toNestedCriterion(input, usedKeys) {
|
|
2309
|
+
if (typeof input !== "object" || input === null) return INVALID_CRITERION;
|
|
2310
|
+
if (typeof input.attributeKey !== "string" || input.attributeKey.length === 0) {
|
|
2312
2311
|
return INVALID_CRITERION;
|
|
2313
2312
|
}
|
|
2314
|
-
if (
|
|
2315
|
-
const window2 = toLevelWindow(
|
|
2313
|
+
if (usedKeys.has(input.attributeKey)) return INVALID_CRITERION;
|
|
2314
|
+
const window2 = toLevelWindow(input);
|
|
2316
2315
|
if (window2 === null) return INVALID_CRITERION;
|
|
2317
|
-
if (!isValidDirection(
|
|
2316
|
+
if (!isValidDirection(input.direction)) return INVALID_CRITERION;
|
|
2318
2317
|
return {
|
|
2319
|
-
attributeKey:
|
|
2318
|
+
attributeKey: input.attributeKey,
|
|
2320
2319
|
startLevel: window2.startLevel,
|
|
2321
2320
|
depth: window2.depth,
|
|
2322
|
-
direction:
|
|
2321
|
+
direction: input.direction
|
|
2323
2322
|
};
|
|
2324
2323
|
}
|
|
2324
|
+
function toNestedCriteria(input, primaryKey) {
|
|
2325
|
+
const rawNested = input.nested ?? (input.secondary == null ? [] : [input.secondary]);
|
|
2326
|
+
if (!Array.isArray(rawNested)) return INVALID_CRITERION;
|
|
2327
|
+
if (rawNested.length > MAX_NESTED_GROUP_CRITERIA) return INVALID_CRITERION;
|
|
2328
|
+
const usedKeys = /* @__PURE__ */ new Set([primaryKey]);
|
|
2329
|
+
const nested = [];
|
|
2330
|
+
for (const rawCriterion of rawNested) {
|
|
2331
|
+
const criterion = toNestedCriterion(rawCriterion, usedKeys);
|
|
2332
|
+
if (criterion === INVALID_CRITERION) return INVALID_CRITERION;
|
|
2333
|
+
usedKeys.add(criterion.attributeKey);
|
|
2334
|
+
nested.push(criterion);
|
|
2335
|
+
}
|
|
2336
|
+
return nested;
|
|
2337
|
+
}
|
|
2325
2338
|
function toGroupState(input) {
|
|
2326
2339
|
if (typeof input.attributeKey !== "string" || input.attributeKey.length === 0) {
|
|
2327
2340
|
return null;
|
|
@@ -2335,8 +2348,8 @@ function toGroupState(input) {
|
|
|
2335
2348
|
if (!Array.isArray(input.collapsedIds) || input.collapsedIds.some((id) => typeof id !== "string")) {
|
|
2336
2349
|
return null;
|
|
2337
2350
|
}
|
|
2338
|
-
const
|
|
2339
|
-
if (
|
|
2351
|
+
const nested = toNestedCriteria(input, input.attributeKey);
|
|
2352
|
+
if (nested === INVALID_CRITERION) return null;
|
|
2340
2353
|
return {
|
|
2341
2354
|
attributeKey: input.attributeKey,
|
|
2342
2355
|
startLevel: window2.startLevel,
|
|
@@ -2344,7 +2357,7 @@ function toGroupState(input) {
|
|
|
2344
2357
|
direction: input.direction,
|
|
2345
2358
|
includeWbs: input.includeWbs,
|
|
2346
2359
|
collapsedIds: new Set(input.collapsedIds),
|
|
2347
|
-
|
|
2360
|
+
nested
|
|
2348
2361
|
};
|
|
2349
2362
|
}
|
|
2350
2363
|
function emptyViewChanges(action) {
|
|
@@ -13025,7 +13038,7 @@ function resolveDataDateProgressButton(activity, progress, progressChanges, deps
|
|
|
13025
13038
|
);
|
|
13026
13039
|
}
|
|
13027
13040
|
function resolveDataDateFieldChanges(activity, changes, deps, column, confirmations, progressRouting, editedStart = null) {
|
|
13028
|
-
const
|
|
13041
|
+
const routed = routeGenericColumnEdit(
|
|
13029
13042
|
activity,
|
|
13030
13043
|
routeConstraintTypeEdit(activity, changes, column),
|
|
13031
13044
|
deps,
|
|
@@ -13034,9 +13047,8 @@ function resolveDataDateFieldChanges(activity, changes, deps, column, confirmati
|
|
|
13034
13047
|
progressRouting,
|
|
13035
13048
|
editedStart
|
|
13036
13049
|
);
|
|
13037
|
-
if (
|
|
13038
|
-
if ("accepted" in
|
|
13039
|
-
const routed = limitTransitionActuals(activity, generic, deps, column);
|
|
13050
|
+
if (routed === null) return rejected(REJECTION_REASON.INVALID_VALUE);
|
|
13051
|
+
if ("accepted" in routed) return routed;
|
|
13040
13052
|
if (routed.dataDatePatch === void 0) return accepted(routed);
|
|
13041
13053
|
if (activity.p6 === void 0 || deps.dataDateCapability === null) {
|
|
13042
13054
|
return rejected(REJECTION_REASON.INVALID_VALUE);
|
|
@@ -13096,32 +13108,6 @@ function withMirroredProgress(activity, changes, next, deps, column) {
|
|
|
13096
13108
|
}
|
|
13097
13109
|
return { ...changes, patch: { ...changes.patch, progress: percent } };
|
|
13098
13110
|
}
|
|
13099
|
-
var EXECUTION_TRANSITION_COLUMNS = /* @__PURE__ */ new Set([
|
|
13100
|
-
COLUMN.PROGRESS,
|
|
13101
|
-
COLUMN.EXECUTION_STATUS,
|
|
13102
|
-
COLUMN.PHYSICAL_PERCENT_COMPLETE
|
|
13103
|
-
]);
|
|
13104
|
-
function limitTransitionActuals(activity, changes, deps, column) {
|
|
13105
|
-
const dataDate = deps.dataDateSettings?.dataDate ?? null;
|
|
13106
|
-
if (!EXECUTION_TRANSITION_COLUMNS.has(column) || dataDate === null || changes.dataDatePatch === void 0 || !hasActiveDataDate(deps.dataDateSettings, deps.dataDateEnabled)) {
|
|
13107
|
-
return changes;
|
|
13108
|
-
}
|
|
13109
|
-
const calendar = deps.ctx.calendars.getCalendar(activity.calendarId);
|
|
13110
|
-
const limit = calendar === null ? { start: dataDate, finish: dataDate } : completionActualsLimit(dataDate, calendar);
|
|
13111
|
-
const recordedStart = activity.p6?.actualStart ?? null;
|
|
13112
|
-
const floor = recordedStart !== null && recordedStart <= dataDate ? recordedStart : null;
|
|
13113
|
-
const alternative = changes.confirmationAlternative;
|
|
13114
|
-
return {
|
|
13115
|
-
...changes,
|
|
13116
|
-
dataDatePatch: capActualDates(changes.dataDatePatch, floor, limit),
|
|
13117
|
-
...alternative === void 0 ? {} : {
|
|
13118
|
-
confirmationAlternative: {
|
|
13119
|
-
...alternative,
|
|
13120
|
-
effects: capActualDates(alternative.effects, floor, limit)
|
|
13121
|
-
}
|
|
13122
|
-
}
|
|
13123
|
-
};
|
|
13124
|
-
}
|
|
13125
13111
|
function accepted(changes) {
|
|
13126
13112
|
return { accepted: true, changes };
|
|
13127
13113
|
}
|
|
@@ -25913,7 +25899,7 @@ function emitActivities(node, context) {
|
|
|
25913
25899
|
});
|
|
25914
25900
|
}
|
|
25915
25901
|
}
|
|
25916
|
-
function emitNode(node, childDirection,
|
|
25902
|
+
function emitNode(node, childDirection, nextNestedIndex, context) {
|
|
25917
25903
|
const { group, rows } = context;
|
|
25918
25904
|
rows.push({
|
|
25919
25905
|
kind: VISUAL_ROW_KIND.GROUP,
|
|
@@ -25925,20 +25911,24 @@ function emitNode(node, childDirection, allowSecondary, context) {
|
|
|
25925
25911
|
});
|
|
25926
25912
|
if (group.collapsedIds.has(node.id)) return;
|
|
25927
25913
|
for (const child of sortedChildNodes(node, childDirection)) {
|
|
25928
|
-
emitNode(child, childDirection,
|
|
25914
|
+
emitNode(child, childDirection, nextNestedIndex, context);
|
|
25929
25915
|
}
|
|
25930
25916
|
if (node.activities.length === 0) return;
|
|
25931
|
-
const
|
|
25932
|
-
|
|
25933
|
-
|
|
25917
|
+
const nestedCriterion = group.nested[nextNestedIndex];
|
|
25918
|
+
const nestedCatalog = context.nestedCatalogs[nextNestedIndex] ?? null;
|
|
25919
|
+
if (nestedCriterion != null && nestedCatalog != null) {
|
|
25920
|
+
const nestedRoot = buildGroupTree(
|
|
25934
25921
|
node.activities,
|
|
25935
|
-
|
|
25936
|
-
|
|
25922
|
+
nestedCriterion,
|
|
25923
|
+
nestedCatalog,
|
|
25937
25924
|
createNode(node.id, "", "", null, node.level, 0),
|
|
25938
25925
|
true
|
|
25939
25926
|
);
|
|
25940
|
-
for (const child of sortedChildNodes(
|
|
25941
|
-
|
|
25927
|
+
for (const child of sortedChildNodes(
|
|
25928
|
+
nestedRoot,
|
|
25929
|
+
nestedCriterion.direction
|
|
25930
|
+
)) {
|
|
25931
|
+
emitNode(child, nestedCriterion.direction, nextNestedIndex + 1, context);
|
|
25942
25932
|
}
|
|
25943
25933
|
return;
|
|
25944
25934
|
}
|
|
@@ -25981,11 +25971,11 @@ function projectVisualRows(input) {
|
|
|
25981
25971
|
comparator: input.comparator,
|
|
25982
25972
|
orderMode: input.orderMode,
|
|
25983
25973
|
wbsDepth: input.wbsDepth,
|
|
25984
|
-
|
|
25974
|
+
nestedCatalogs: input.nestedCatalogs,
|
|
25985
25975
|
rows
|
|
25986
25976
|
};
|
|
25987
25977
|
for (const child of sortedChildNodes(root, group.direction)) {
|
|
25988
|
-
emitNode(child, group.direction,
|
|
25978
|
+
emitNode(child, group.direction, 0, context);
|
|
25989
25979
|
}
|
|
25990
25980
|
return rows;
|
|
25991
25981
|
}
|
|
@@ -26391,7 +26381,9 @@ var ScheduleState = class _ScheduleState {
|
|
|
26391
26381
|
if (this._cache.visualRows) return this._cache.visualRows;
|
|
26392
26382
|
const group = this._viewAttributes.getGroup();
|
|
26393
26383
|
const catalog = group === null ? null : this._viewAttributes.getCatalog(group.attributeKey);
|
|
26394
|
-
const
|
|
26384
|
+
const nestedCatalogs = group === null ? [] : group.nested.map(
|
|
26385
|
+
(criterion) => this._viewAttributes.getCatalog(criterion.attributeKey)
|
|
26386
|
+
);
|
|
26395
26387
|
const activitiesInVisualOrder = [];
|
|
26396
26388
|
for (const activityId of this.getVisualOrderIds()) {
|
|
26397
26389
|
const activity = this.getActivity(activityId);
|
|
@@ -26404,7 +26396,7 @@ var ScheduleState = class _ScheduleState {
|
|
|
26404
26396
|
hasChildren: (activityId) => this.hasChildren(activityId),
|
|
26405
26397
|
group,
|
|
26406
26398
|
catalog,
|
|
26407
|
-
|
|
26399
|
+
nestedCatalogs,
|
|
26408
26400
|
comparator: this.getOrderComparator(),
|
|
26409
26401
|
orderMode: this.getOrderMode(),
|
|
26410
26402
|
wbsDepth: this._viewAttributes.getWbsDepth()
|
|
@@ -31160,13 +31152,11 @@ function prepareDataDateSettingsUpdate(current, patch) {
|
|
|
31160
31152
|
};
|
|
31161
31153
|
}
|
|
31162
31154
|
function prepareDataDateActivityUpdate(current, patch, primaryConstraint) {
|
|
31163
|
-
const
|
|
31155
|
+
const synchronized = synchronizeNotStartedDurations(current, patch);
|
|
31156
|
+
const percentRouted = routeActivityPercentComplete(current, synchronized);
|
|
31164
31157
|
validateActivityInputPatch(percentRouted);
|
|
31165
31158
|
validateSecondaryConstraint(percentRouted, primaryConstraint);
|
|
31166
|
-
const routed =
|
|
31167
|
-
current,
|
|
31168
|
-
gatePhysicalPercentInput(current, percentRouted)
|
|
31169
|
-
);
|
|
31159
|
+
const routed = gatePhysicalPercentInput(current, percentRouted);
|
|
31170
31160
|
const next = cloneDomainValue({
|
|
31171
31161
|
...current,
|
|
31172
31162
|
...routed,
|
|
@@ -31179,7 +31169,7 @@ function prepareDataDateActivityUpdate(current, patch, primaryConstraint) {
|
|
|
31179
31169
|
};
|
|
31180
31170
|
}
|
|
31181
31171
|
function synchronizeNotStartedDurations(current, patch) {
|
|
31182
|
-
if (current.executionStatus !== P6_EXECUTION_STATUS.NOT_STARTED || patch.remainingDurationHours === void 0 || patch.originalDurationHours !== void 0) {
|
|
31172
|
+
if (current.executionStatus !== P6_EXECUTION_STATUS.NOT_STARTED || patch.actualStart != null || patch.activityPercentComplete !== void 0 || patch.remainingDurationHours === void 0 || patch.originalDurationHours !== void 0) {
|
|
31183
31173
|
return patch;
|
|
31184
31174
|
}
|
|
31185
31175
|
return {
|
|
@@ -31224,7 +31214,7 @@ function routeActivityPercentComplete(current, patch) {
|
|
|
31224
31214
|
case P6_PERCENT_COMPLETE_TYPE.DURATION:
|
|
31225
31215
|
return {
|
|
31226
31216
|
...rest,
|
|
31227
|
-
remainingDurationHours: current.originalDurationHours * (1 - activityPercentComplete / FULL_PERCENT)
|
|
31217
|
+
remainingDurationHours: (rest.originalDurationHours ?? current.originalDurationHours) * (1 - activityPercentComplete / FULL_PERCENT)
|
|
31228
31218
|
};
|
|
31229
31219
|
case P6_PERCENT_COMPLETE_TYPE.UNITS:
|
|
31230
31220
|
throw new Error(
|