@letpeoplework/lighthouse-client 1.9.0 → 1.11.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/index.cjs +180 -36
- package/dist/index.d.cts +88 -11
- package/dist/index.d.ts +88 -11
- package/dist/index.js +171 -37
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -242,13 +242,26 @@ const textOf = (value) => typeof value === "string" && value.length > 0 ? value
|
|
|
242
242
|
const isDay = (value) => isText(value) && formatCalendarDay(value) !== null;
|
|
243
243
|
/** The calendar day as a person reads it, or the text exactly as sent when it is not one. */
|
|
244
244
|
const dayOf = (wire) => formatCalendarDay(wire) ?? wire;
|
|
245
|
-
/** The
|
|
246
|
-
const
|
|
245
|
+
/** The chance a list gives for one probability, or undefined when it holds none for it. */
|
|
246
|
+
const chanceAt = (chances, probability) => {
|
|
247
247
|
if (!Array.isArray(chances)) return;
|
|
248
248
|
const chance = chances.find((entry) => isRecord(entry) && entry.probability === probability);
|
|
249
|
-
return isRecord(chance) ?
|
|
249
|
+
return isRecord(chance) ? chance : void 0;
|
|
250
250
|
};
|
|
251
251
|
//#endregion
|
|
252
|
+
//#region src/forecastPercentileText.ts
|
|
253
|
+
/**
|
|
254
|
+
* The years of the horizon a percentile lies beyond, or undefined when its date is the forecast. Keyed on
|
|
255
|
+
* the flag itself, never on the server's version: an older Lighthouse never sends it.
|
|
256
|
+
*/
|
|
257
|
+
const yearsBeyondHorizon = (percentile) => isRecord(percentile) && percentile.beyondHorizon === true && isNumber(percentile.horizonYears) ? percentile.horizonYears : void 0;
|
|
258
|
+
/** The words shown in place of a date for a percentile too few simulated runs reached. */
|
|
259
|
+
const moreThanYearsText = (horizonYears) => `More than ${horizonYears} years`;
|
|
260
|
+
/** A percentile's day as a person reads it, or "More than 5 years" when it lies beyond that horizon. */
|
|
261
|
+
const describePercentileDay = (expectedDate, horizonYearsBeyond) => horizonYearsBeyond === void 0 ? dayOf(expectedDate) : moreThanYearsText(horizonYearsBeyond);
|
|
262
|
+
/** One percentile as text: its day, or the words when it lies beyond the horizon. */
|
|
263
|
+
const describePercentileDate = (percentile) => describePercentileDay(percentile.expectedDate, yearsBeyondHorizon(percentile));
|
|
264
|
+
//#endregion
|
|
252
265
|
//#region src/ownerWording.ts
|
|
253
266
|
/** A mark for a cell Lighthouse sent nothing for. */
|
|
254
267
|
const NOT_SENT = "—";
|
|
@@ -408,9 +421,11 @@ const startOf = (value) => {
|
|
|
408
421
|
observedOn: void 0,
|
|
409
422
|
likelyBy: void 0
|
|
410
423
|
};
|
|
424
|
+
const chance = chanceAt(value.percentiles, LISTED_CHANCE$1);
|
|
411
425
|
return {
|
|
412
426
|
observedOn: value.source === "Observed" ? textOf(value.observedDate) : void 0,
|
|
413
|
-
likelyBy:
|
|
427
|
+
likelyBy: textOf(chance?.expectedDate),
|
|
428
|
+
likelyByBeyondHorizonYears: yearsBeyondHorizon(chance)
|
|
414
429
|
};
|
|
415
430
|
};
|
|
416
431
|
const readFeatureListItem = (value) => {
|
|
@@ -420,6 +435,7 @@ const readFeatureListItem = (value) => {
|
|
|
420
435
|
const state = textOf(value.state);
|
|
421
436
|
const totalWork = workOf(value.totalWork);
|
|
422
437
|
const remainingWork = workOf(value.remainingWork);
|
|
438
|
+
const completion = chanceAt(value.forecasts, LISTED_CHANCE$1);
|
|
423
439
|
if (referenceId === void 0 || name === void 0 || state === void 0 || totalWork === null || remainingWork === null) return null;
|
|
424
440
|
return {
|
|
425
441
|
referenceId,
|
|
@@ -429,7 +445,8 @@ const readFeatureListItem = (value) => {
|
|
|
429
445
|
remainingWork,
|
|
430
446
|
cannotBeForecast: Array.isArray(value.teamsWithoutForecast) && value.teamsWithoutForecast.length > 0,
|
|
431
447
|
start: startOf(value.startForecast),
|
|
432
|
-
likelyBy:
|
|
448
|
+
likelyBy: textOf(completion?.expectedDate),
|
|
449
|
+
likelyByBeyondHorizonYears: yearsBeyondHorizon(completion)
|
|
433
450
|
};
|
|
434
451
|
};
|
|
435
452
|
/**
|
|
@@ -465,12 +482,15 @@ const describeFeatureProgress = (feature, terms) => `${feature.totalWork - featu
|
|
|
465
482
|
const describeFeatureStart = (feature) => {
|
|
466
483
|
if (feature.start.observedOn !== void 0) return dayOf(feature.start.observedOn);
|
|
467
484
|
if (feature.cannotBeForecast) return CANNOT_FORECAST_SHORT;
|
|
468
|
-
return feature.start.likelyBy === void 0 ? "—" :
|
|
485
|
+
return feature.start.likelyBy === void 0 ? "—" : describePercentileDay(feature.start.likelyBy, feature.start.likelyByBeyondHorizonYears);
|
|
469
486
|
};
|
|
470
|
-
/**
|
|
487
|
+
/**
|
|
488
|
+
* The day the Feature is 85% likely to be done by, "More than 5 years" when that lies beyond the simulation
|
|
489
|
+
* horizon, "Cannot forecast", or the mark when none was sent.
|
|
490
|
+
*/
|
|
471
491
|
const describeFeatureCompletion = (feature) => {
|
|
472
492
|
if (feature.cannotBeForecast) return CANNOT_FORECAST_SHORT;
|
|
473
|
-
return feature.likelyBy === void 0 ? "—" :
|
|
493
|
+
return feature.likelyBy === void 0 ? "—" : describePercentileDay(feature.likelyBy, feature.likelyByBeyondHorizonYears);
|
|
474
494
|
};
|
|
475
495
|
/** One Feature as a row of the list, in the order of its headings. */
|
|
476
496
|
const describeFeatureRow = (feature, terms) => [
|
|
@@ -627,11 +647,13 @@ const readFeatureWording = (source, featureId) => readAnswerWording(source, {
|
|
|
627
647
|
//#region src/deliveryWording.ts
|
|
628
648
|
const LISTED_CHANCE = 85;
|
|
629
649
|
const flagOf = (value) => typeof value === "boolean" ? value : void 0;
|
|
650
|
+
const teamsWithoutForecastIn = (value) => Array.isArray(value.teamsWithoutForecast) && value.teamsWithoutForecast.length > 0;
|
|
630
651
|
const readDeliveryListItem = (value) => {
|
|
631
652
|
if (!isRecord(value) || typeof value.id !== "number" || typeof value.totalWork !== "number" || typeof value.remainingWork !== "number") return null;
|
|
632
653
|
const name = textOf(value.name);
|
|
633
654
|
const date = textOf(value.date);
|
|
634
655
|
if (name === void 0 || date === void 0) return null;
|
|
656
|
+
const likely = chanceAt(value.completionDates, LISTED_CHANCE);
|
|
635
657
|
return {
|
|
636
658
|
id: value.id,
|
|
637
659
|
name,
|
|
@@ -640,10 +662,11 @@ const readDeliveryListItem = (value) => {
|
|
|
640
662
|
totalWork: value.totalWork,
|
|
641
663
|
remainingWork: value.remainingWork,
|
|
642
664
|
likelihood: typeof value.likelihoodPercentage === "number" ? value.likelihoodPercentage : null,
|
|
643
|
-
cannotBeForecast:
|
|
665
|
+
cannotBeForecast: teamsWithoutForecastIn(value),
|
|
644
666
|
hasSufficientData: flagOf(value.hasSufficientData),
|
|
645
667
|
isOverdue: flagOf(value.isOverdue),
|
|
646
|
-
likelyBy:
|
|
668
|
+
likelyBy: textOf(likely?.expectedDate),
|
|
669
|
+
likelyByBeyondHorizonYears: yearsBeyondHorizon(likely)
|
|
647
670
|
};
|
|
648
671
|
};
|
|
649
672
|
/**
|
|
@@ -655,6 +678,40 @@ const readDeliveryList = (value) => {
|
|
|
655
678
|
const items = value.map(readDeliveryListItem);
|
|
656
679
|
return items.every((item) => item !== null) ? items : null;
|
|
657
680
|
};
|
|
681
|
+
const doneWorkOf = (value) => {
|
|
682
|
+
if (typeof value.doneWork === "number") return value.doneWork;
|
|
683
|
+
return typeof value.totalWork === "number" && typeof value.remainingWork === "number" ? value.totalWork - value.remainingWork : void 0;
|
|
684
|
+
};
|
|
685
|
+
/** One archived Delivery, or null when it comes without its id, name, dates or work. */
|
|
686
|
+
const readArchivedDeliveryItem = (value) => {
|
|
687
|
+
if (!isRecord(value) || typeof value.id !== "number" || typeof value.totalWork !== "number") return null;
|
|
688
|
+
const name = textOf(value.name);
|
|
689
|
+
const date = textOf(value.date);
|
|
690
|
+
const archivedOn = textOf(value.archivedOn);
|
|
691
|
+
const doneWork = doneWorkOf(value);
|
|
692
|
+
if (name === void 0 || date === void 0 || archivedOn === void 0 || doneWork === void 0) return null;
|
|
693
|
+
return {
|
|
694
|
+
id: value.id,
|
|
695
|
+
name,
|
|
696
|
+
date,
|
|
697
|
+
archivedOn,
|
|
698
|
+
totalWork: value.totalWork,
|
|
699
|
+
doneWork,
|
|
700
|
+
likelihood: typeof value.likelihoodPercentage === "number" ? value.likelihoodPercentage : null,
|
|
701
|
+
cannotBeForecast: teamsWithoutForecastIn(value),
|
|
702
|
+
hasSufficientData: flagOf(value.hasSufficientData)
|
|
703
|
+
};
|
|
704
|
+
};
|
|
705
|
+
/** A Portfolio's active and archived Deliveries, or null when either list or any row in it cannot be read. */
|
|
706
|
+
const readPortfolioDeliveries = (value) => {
|
|
707
|
+
if (!isRecord(value) || !Array.isArray(value.archived)) return null;
|
|
708
|
+
const active = readDeliveryList(value.active);
|
|
709
|
+
const archived = value.archived.map(readArchivedDeliveryItem);
|
|
710
|
+
return active !== null && archived.every((item) => item !== null) ? {
|
|
711
|
+
active,
|
|
712
|
+
archived
|
|
713
|
+
} : null;
|
|
714
|
+
};
|
|
658
715
|
/** "Ocean Explorer · Deliveries", or the Portfolio by its id when its name could not be read. */
|
|
659
716
|
const describeDeliveryListTitle = (owner, terms) => {
|
|
660
717
|
return `${owner.name === void 0 ? `${terms.portfolio} [id: ${owner.id}]` : owner.name} · ${terms.deliveries}`;
|
|
@@ -693,8 +750,38 @@ const describeDeliveryRow = (delivery, terms) => [
|
|
|
693
750
|
delivery.featureCount === void 0 ? "—" : String(delivery.featureCount),
|
|
694
751
|
describeDeliveryDone(delivery, terms),
|
|
695
752
|
describeDeliveryLikelihood(delivery),
|
|
696
|
-
delivery.likelyBy === void 0 ? "—" :
|
|
753
|
+
delivery.likelyBy === void 0 ? "—" : describePercentileDay(delivery.likelyBy, delivery.likelyByBeyondHorizonYears)
|
|
754
|
+
];
|
|
755
|
+
/** What heads the archived Deliveries, below the active ones: "Archived Deliveries". */
|
|
756
|
+
const describeArchivedDeliveriesTitle = (terms) => `Archived ${terms.deliveries}`;
|
|
757
|
+
/** The archived table's column headings: when it was due, when it closed, and what it reached. */
|
|
758
|
+
const describeArchivedDeliveryHeadings = (terms) => [
|
|
759
|
+
"Name",
|
|
760
|
+
`${terms.delivery} Date`,
|
|
761
|
+
"Archived On",
|
|
762
|
+
"Done",
|
|
763
|
+
"Likelihood"
|
|
697
764
|
];
|
|
765
|
+
/** One archived Delivery as a row of its table, in the order of its headings. */
|
|
766
|
+
const describeArchivedDeliveryRow = (delivery, terms) => {
|
|
767
|
+
const remainingWork = delivery.totalWork - delivery.doneWork;
|
|
768
|
+
return [
|
|
769
|
+
describeOwnerName(delivery),
|
|
770
|
+
dayOf(delivery.date),
|
|
771
|
+
dayOf(delivery.archivedOn),
|
|
772
|
+
describeDeliveryDone({
|
|
773
|
+
totalWork: delivery.totalWork,
|
|
774
|
+
remainingWork
|
|
775
|
+
}, terms),
|
|
776
|
+
likelihoodAnswer({
|
|
777
|
+
likelihood: delivery.likelihood,
|
|
778
|
+
cannotBeForecast: delivery.cannotBeForecast,
|
|
779
|
+
hasRemainingWork: remainingWork > 0,
|
|
780
|
+
hasSufficientData: delivery.hasSufficientData,
|
|
781
|
+
precision: "round"
|
|
782
|
+
})
|
|
783
|
+
];
|
|
784
|
+
};
|
|
698
785
|
const isNullableNumber = (value) => value === null || typeof value === "number";
|
|
699
786
|
const isFeatureMetric = (value) => isRecord(value) && typeof value.referenceId === "string" && typeof value.name === "string" && typeof value.completion === "number" && isNullableNumber(value.likelihood);
|
|
700
787
|
const isChance = (value) => isRecord(value) && typeof value.probability === "number" && textOf(value.expectedDate) !== void 0;
|
|
@@ -766,18 +853,23 @@ const describeDeliveryFeatureRow = (feature) => [
|
|
|
766
853
|
];
|
|
767
854
|
/** The forecast distribution's column headings. */
|
|
768
855
|
const describeDeliveryChanceHeadings = () => ["Chance", "Done by"];
|
|
769
|
-
/** One chance of the day's forecast: "85%" and the day it is that likely to be done by. */
|
|
770
|
-
const describeDeliveryChanceRow = (chance) => [`${chance.probability}%`,
|
|
856
|
+
/** One chance of the day's forecast: "85%" and the day it is that likely to be done by, or "More than 5 years". */
|
|
857
|
+
const describeDeliveryChanceRow = (chance) => [`${chance.probability}%`, describePercentileDate(chance)];
|
|
771
858
|
//#endregion
|
|
772
859
|
//#region src/forecastWording.ts
|
|
773
|
-
const optionalBoolean = (value) => {
|
|
860
|
+
const optionalBoolean$1 = (value) => {
|
|
774
861
|
if (value === void 0 || typeof value === "boolean") return value;
|
|
775
862
|
return null;
|
|
776
863
|
};
|
|
777
|
-
const readChanceByDay = (value) =>
|
|
778
|
-
probability
|
|
779
|
-
|
|
780
|
-
|
|
864
|
+
const readChanceByDay = (value) => {
|
|
865
|
+
if (!isRecord(value) || !isNumber(value.probability) || !isDay(value.expectedDate)) return null;
|
|
866
|
+
return {
|
|
867
|
+
probability: value.probability,
|
|
868
|
+
expectedDate: value.expectedDate,
|
|
869
|
+
...typeof value.beyondHorizon === "boolean" ? { beyondHorizon: value.beyondHorizon } : {},
|
|
870
|
+
...isNumber(value.horizonYears) ? { horizonYears: value.horizonYears } : {}
|
|
871
|
+
};
|
|
872
|
+
};
|
|
781
873
|
const readChanceOfCount = (value) => isRecord(value) && isNumber(value.probability) && isNumber(value.value) ? {
|
|
782
874
|
probability: value.probability,
|
|
783
875
|
value: value.value
|
|
@@ -793,8 +885,8 @@ const readManualForecast = (value) => {
|
|
|
793
885
|
const { remainingItems, targetDate, likelihood } = value;
|
|
794
886
|
const whenForecasts = readEvery$1(value.whenForecasts, readChanceByDay);
|
|
795
887
|
const howManyForecasts = readEvery$1(value.howManyForecasts, readChanceOfCount);
|
|
796
|
-
const filterApplied = optionalBoolean(value.filterApplied);
|
|
797
|
-
const hasSufficientData = optionalBoolean(value.hasSufficientData);
|
|
888
|
+
const filterApplied = optionalBoolean$1(value.filterApplied);
|
|
889
|
+
const hasSufficientData = optionalBoolean$1(value.hasSufficientData);
|
|
798
890
|
if (!isNumber(remainingItems) || !(targetDate === null || isDay(targetDate)) || !(likelihood === null || isNumber(likelihood)) || whenForecasts === null || howManyForecasts === null || filterApplied === null || hasSufficientData === null) return null;
|
|
799
891
|
return {
|
|
800
892
|
remainingItems,
|
|
@@ -1081,13 +1173,28 @@ const readRunChart = (value, range) => {
|
|
|
1081
1173
|
const optionalText = (value) => isText(value) ? value : void 0;
|
|
1082
1174
|
const optionalNumber = (value) => isNumber(value) ? value : void 0;
|
|
1083
1175
|
const optionalDay = (value) => isDay(value) ? value : void 0;
|
|
1176
|
+
const optionalBoolean = (value) => typeof value === "boolean" ? value : void 0;
|
|
1177
|
+
const STALE_REASON_KINDS = [
|
|
1178
|
+
"TimeInState",
|
|
1179
|
+
"BlockedDuration",
|
|
1180
|
+
"TimeInStateWhileBlocked"
|
|
1181
|
+
];
|
|
1182
|
+
const isStaleReasonKind = (value) => STALE_REASON_KINDS.some((kind) => kind === value);
|
|
1183
|
+
const readStaleReason = (value) => isRecord(value) && isStaleReasonKind(value.kind) && isNumber(value.days) ? {
|
|
1184
|
+
kind: value.kind,
|
|
1185
|
+
days: value.days,
|
|
1186
|
+
stateName: optionalText(value.stateName)
|
|
1187
|
+
} : null;
|
|
1188
|
+
const optionalStaleReasons = (value) => Array.isArray(value) ? value.map(readStaleReason).filter((reason) => reason !== null) : void 0;
|
|
1084
1189
|
const readInProgressItem = (value) => isRecord(value) && (value.isBlocked === void 0 || typeof value.isBlocked === "boolean") ? {
|
|
1085
1190
|
isBlocked: value.isBlocked,
|
|
1086
1191
|
referenceId: optionalText(value.referenceId),
|
|
1087
1192
|
name: optionalText(value.name),
|
|
1088
1193
|
state: optionalText(value.state),
|
|
1089
1194
|
workItemAge: optionalNumber(value.workItemAge),
|
|
1090
|
-
blockedSince: optionalDay(value.blockedSince)
|
|
1195
|
+
blockedSince: optionalDay(value.blockedSince),
|
|
1196
|
+
isStale: optionalBoolean(value.isStale),
|
|
1197
|
+
staleReasons: optionalStaleReasons(value.staleReasons)
|
|
1091
1198
|
} : null;
|
|
1092
1199
|
const readInProgressNow = (value) => {
|
|
1093
1200
|
if (!isRecord(value) || !isDay(value.asOfDate) || !isNumber(value.count)) return null;
|
|
@@ -1286,6 +1393,7 @@ const metricsHeadlineLabel = (part, scope, terms) => {
|
|
|
1286
1393
|
throughput: `Total ${terms.throughput}`,
|
|
1287
1394
|
arrivals: "Total Arrivals",
|
|
1288
1395
|
blocked: `${terms.blocked} ${counted.many}`,
|
|
1396
|
+
stale: `Stale ${counted.many}`,
|
|
1289
1397
|
totalWorkItemAge: `Total ${terms.workItemAge}`,
|
|
1290
1398
|
predictabilityScore: "Predictability Score",
|
|
1291
1399
|
cycleTimePercentiles: `${terms.cycleTime} percentiles`,
|
|
@@ -1329,27 +1437,31 @@ const describeInProgressNow = (now, scope, terms, systemWipLimit) => ({
|
|
|
1329
1437
|
value: String(now.count),
|
|
1330
1438
|
detail: systemWipLimit === void 0 ? "" : wipLimitOf(systemWipLimit, scope, terms)
|
|
1331
1439
|
});
|
|
1440
|
+
const blockedFlag = (item) => item.isBlocked;
|
|
1441
|
+
const staleFlag = (item) => item.isStale;
|
|
1442
|
+
const saysWhichAre = (now, flag) => now.items.some((item) => flag(item) !== void 0);
|
|
1443
|
+
const countFlaggedNow = (part, flag, now, scope, terms) => saysWhichAre(now, flag) ? {
|
|
1444
|
+
label: metricsHeadlineLabel(part, scope, terms),
|
|
1445
|
+
value: String(now.items.filter((item) => flag(item) === true).length),
|
|
1446
|
+
detail: ""
|
|
1447
|
+
} : null;
|
|
1332
1448
|
/** "Blocked Work Items 2", or null when Lighthouse does not say which items are blocked. */
|
|
1333
|
-
const describeBlockedNow = (now, scope, terms) =>
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
return {
|
|
1337
|
-
label: metricsHeadlineLabel("blocked", scope, terms),
|
|
1338
|
-
value: String(blocked),
|
|
1339
|
-
detail: ""
|
|
1340
|
-
};
|
|
1341
|
-
};
|
|
1449
|
+
const describeBlockedNow = (now, scope, terms) => countFlaggedNow("blocked", blockedFlag, now, scope, terms);
|
|
1450
|
+
/** "Stale Work Items 2", or null when Lighthouse does not say which items are stale. */
|
|
1451
|
+
const describeStaleNow = (now, scope, terms) => countFlaggedNow("stale", staleFlag, now, scope, terms);
|
|
1342
1452
|
/**
|
|
1343
1453
|
* The sentences that stand in for what a WIP answer cannot show: no System WIP Limit, a Lighthouse that does
|
|
1344
|
-
* not say which Work Items are Blocked (which is not the same as none being
|
|
1345
|
-
* A limit of null means the Team or Portfolio could not be read; it may well have one, so nothing
|
|
1454
|
+
* not say which Work Items are Blocked or Stale (which is not the same as none being so), and nothing in
|
|
1455
|
+
* progress. A limit of null means the Team or Portfolio could not be read; it may well have one, so nothing
|
|
1456
|
+
* is said.
|
|
1346
1457
|
*/
|
|
1347
1458
|
const describeWhatWipLeavesUnsaid = (now, scope, terms, systemWipLimit) => {
|
|
1348
1459
|
const counted = countedOf(scope, terms);
|
|
1349
|
-
const
|
|
1460
|
+
const silentOn = (flag) => now.items.length > 0 && !saysWhichAre(now, flag);
|
|
1350
1461
|
return [
|
|
1351
1462
|
...systemWipLimit === void 0 ? [`No System ${terms.wip} Limit is set.`] : [],
|
|
1352
|
-
...
|
|
1463
|
+
...silentOn(blockedFlag) ? [`Lighthouse does not say which ${counted.many} are ${terms.blocked}.`] : [],
|
|
1464
|
+
...silentOn(staleFlag) ? [`Lighthouse does not say which ${counted.many} are Stale.`] : [],
|
|
1353
1465
|
...now.items.length === 0 ? [`No ${counted.many} are in progress.`] : []
|
|
1354
1466
|
];
|
|
1355
1467
|
};
|
|
@@ -2796,6 +2908,16 @@ const pollCliAuthSession = async (endpointUrl, sessionId, dependencies) => {
|
|
|
2796
2908
|
return { status: "expired" };
|
|
2797
2909
|
}
|
|
2798
2910
|
};
|
|
2911
|
+
const toPortfolioDeliveries = (value) => {
|
|
2912
|
+
if (Array.isArray(value)) return {
|
|
2913
|
+
active: value,
|
|
2914
|
+
archived: []
|
|
2915
|
+
};
|
|
2916
|
+
return isObjectRecord(value) && Array.isArray(value.active) && Array.isArray(value.archived) ? {
|
|
2917
|
+
active: value.active,
|
|
2918
|
+
archived: value.archived
|
|
2919
|
+
} : null;
|
|
2920
|
+
};
|
|
2799
2921
|
const getDefaultMetricsDateRange = () => {
|
|
2800
2922
|
const end = /* @__PURE__ */ new Date();
|
|
2801
2923
|
const start = /* @__PURE__ */ new Date();
|
|
@@ -3084,7 +3206,8 @@ const FEATURE_REQUIRES_SERVER_NEWER_THAN = {
|
|
|
3084
3206
|
deliveryMetricsHistory: "v26.5.29.5",
|
|
3085
3207
|
sleRisk: "v26.9.19.10",
|
|
3086
3208
|
teamRefinement: "v26.10.3.6",
|
|
3087
|
-
refinementVotes: "v26.10.3.6"
|
|
3209
|
+
refinementVotes: "v26.10.3.6",
|
|
3210
|
+
staleness: "v26.10.16.6"
|
|
3088
3211
|
};
|
|
3089
3212
|
/**
|
|
3090
3213
|
* Parses a Lighthouse version string ("v26.5.24.10", "26.5.24") into numeric
|
|
@@ -3431,7 +3554,18 @@ const createLighthouseClient = (configuration, dependencies = {}) => {
|
|
|
3431
3554
|
return requestJson(configuration, dependencies, `/v1/features/references?${queryString}`, { method: "GET" });
|
|
3432
3555
|
},
|
|
3433
3556
|
getFeatureWorkItems: async (featureId) => requestJson(configuration, dependencies, `/v1/features/${featureId}/workitems`, { method: "GET" }),
|
|
3434
|
-
listDeliveries: async (portfolioId) =>
|
|
3557
|
+
listDeliveries: async (portfolioId) => {
|
|
3558
|
+
const result = await requestJson(configuration, dependencies, `/v1/deliveries/portfolio/${portfolioId}`, { method: "GET" });
|
|
3559
|
+
if (!result.ok) return result;
|
|
3560
|
+
const deliveries = toPortfolioDeliveries(result.value);
|
|
3561
|
+
return deliveries === null ? getErrorResult({
|
|
3562
|
+
category: "unexpected",
|
|
3563
|
+
reason: "Lighthouse's list of Deliveries is not readable."
|
|
3564
|
+
}) : {
|
|
3565
|
+
ok: true,
|
|
3566
|
+
value: deliveries
|
|
3567
|
+
};
|
|
3568
|
+
},
|
|
3435
3569
|
createDelivery: async (portfolioId, payload) => requestJson(configuration, dependencies, `/v1/deliveries/portfolio/${portfolioId}`, {
|
|
3436
3570
|
method: "POST",
|
|
3437
3571
|
body: payload
|
|
@@ -3561,6 +3695,9 @@ exports.createLighthouseClient = createLighthouseClient;
|
|
|
3561
3695
|
exports.daysInRange = daysInRange;
|
|
3562
3696
|
exports.deliveryLikelihoodAnswer = deliveryLikelihoodAnswer;
|
|
3563
3697
|
exports.describeAnswer = describeAnswer;
|
|
3698
|
+
exports.describeArchivedDeliveriesTitle = describeArchivedDeliveriesTitle;
|
|
3699
|
+
exports.describeArchivedDeliveryHeadings = describeArchivedDeliveryHeadings;
|
|
3700
|
+
exports.describeArchivedDeliveryRow = describeArchivedDeliveryRow;
|
|
3564
3701
|
exports.describeArrivalsDays = describeArrivalsDays;
|
|
3565
3702
|
exports.describeAsOfHeading = describeAsOfHeading;
|
|
3566
3703
|
exports.describeBacktestActual = describeBacktestActual;
|
|
@@ -3617,6 +3754,8 @@ exports.describeOwnerListHeadings = describeOwnerListHeadings;
|
|
|
3617
3754
|
exports.describeOwnerListTitle = describeOwnerListTitle;
|
|
3618
3755
|
exports.describeOwnerName = describeOwnerName;
|
|
3619
3756
|
exports.describeOwnerWriteConfirmation = describeOwnerWriteConfirmation;
|
|
3757
|
+
exports.describePercentileDate = describePercentileDate;
|
|
3758
|
+
exports.describePercentileDay = describePercentileDay;
|
|
3620
3759
|
exports.describePercentileRows = describePercentileRows;
|
|
3621
3760
|
exports.describePercentilesOverTime = describePercentilesOverTime;
|
|
3622
3761
|
exports.describePercentilesOverTimeDays = describePercentilesOverTimeDays;
|
|
@@ -3637,6 +3776,7 @@ exports.describeRefinementSummary = describeRefinementSummary;
|
|
|
3637
3776
|
exports.describeRefreshConfirmation = describeRefreshConfirmation;
|
|
3638
3777
|
exports.describeRefusedMetric = describeRefusedMetric;
|
|
3639
3778
|
exports.describeSleRiskNow = describeSleRiskNow;
|
|
3779
|
+
exports.describeStaleNow = describeStaleNow;
|
|
3640
3780
|
exports.describeTags = describeTags;
|
|
3641
3781
|
exports.describeTakenBack = describeTakenBack;
|
|
3642
3782
|
exports.describeTeamSummary = describeTeamSummary;
|
|
@@ -3685,6 +3825,7 @@ exports.likelihoodAnswer = likelihoodAnswer;
|
|
|
3685
3825
|
exports.loadStandaloneDiscoveryContract = loadStandaloneDiscoveryContract;
|
|
3686
3826
|
exports.metricsHeadlineLabel = metricsHeadlineLabel;
|
|
3687
3827
|
exports.mintVoterKey = mintVoterKey;
|
|
3828
|
+
exports.moreThanYearsText = moreThanYearsText;
|
|
3688
3829
|
exports.myVoteOn = myVoteOn;
|
|
3689
3830
|
exports.nameOrFallback = nameOrFallback;
|
|
3690
3831
|
exports.ordinalOf = ordinalOf;
|
|
@@ -3696,6 +3837,7 @@ exports.pollCliAuthSession = pollCliAuthSession;
|
|
|
3696
3837
|
exports.processBehaviorChartTitle = processBehaviorChartTitle;
|
|
3697
3838
|
exports.queryServerAuthMode = queryServerAuthMode;
|
|
3698
3839
|
exports.readAnswerWording = readAnswerWording;
|
|
3840
|
+
exports.readArchivedDeliveryItem = readArchivedDeliveryItem;
|
|
3699
3841
|
exports.readArrivals = readArrivals;
|
|
3700
3842
|
exports.readBacktest = readBacktest;
|
|
3701
3843
|
exports.readBlackoutRules = readBlackoutRules;
|
|
@@ -3717,6 +3859,7 @@ exports.readNameOfMyVote = readNameOfMyVote;
|
|
|
3717
3859
|
exports.readOwnerList = readOwnerList;
|
|
3718
3860
|
exports.readPercentilesOverTime = readPercentilesOverTime;
|
|
3719
3861
|
exports.readPortfolio = readPortfolio;
|
|
3862
|
+
exports.readPortfolioDeliveries = readPortfolioDeliveries;
|
|
3720
3863
|
exports.readPredictabilityScore = readPredictabilityScore;
|
|
3721
3864
|
exports.readProcessBehaviorChart = readProcessBehaviorChart;
|
|
3722
3865
|
exports.readProcessBehaviorOverTime = readProcessBehaviorOverTime;
|
|
@@ -3754,3 +3897,4 @@ exports.usageDataStoreFor = usageDataStoreFor;
|
|
|
3754
3897
|
exports.validateLighthouseConnectivity = validateLighthouseConnectivity;
|
|
3755
3898
|
exports.voterKeyStoreFor = voterKeyStoreFor;
|
|
3756
3899
|
exports.withdrawUsageData = withdrawUsageData;
|
|
3900
|
+
exports.yearsBeyondHorizon = yearsBeyondHorizon;
|
package/dist/index.d.cts
CHANGED
|
@@ -195,6 +195,7 @@ export type DeliveryListItem = {
|
|
|
195
195
|
readonly hasSufficientData: boolean | undefined;
|
|
196
196
|
readonly isOverdue: boolean | undefined;
|
|
197
197
|
readonly likelyBy: string | undefined;
|
|
198
|
+
readonly likelyByBeyondHorizonYears?: number;
|
|
198
199
|
};
|
|
199
200
|
/** The Portfolio whose Deliveries are listed; its name stays undefined when it could not be read. */
|
|
200
201
|
export type DeliveryListOwner = {
|
|
@@ -206,6 +207,25 @@ export type DeliveryListOwner = {
|
|
|
206
207
|
* id, name, date or work: a row that cannot say what it is or when it is due would misstate the list.
|
|
207
208
|
*/
|
|
208
209
|
export declare const readDeliveryList: (value: unknown) => DeliveryListItem[] | null;
|
|
210
|
+
/** One archived Delivery as the archived table states it: the numbers written down the day it closed. */
|
|
211
|
+
export type ArchivedDeliveryItem = {
|
|
212
|
+
readonly id: number;
|
|
213
|
+
readonly name: string;
|
|
214
|
+
readonly date: string;
|
|
215
|
+
readonly archivedOn: string;
|
|
216
|
+
readonly totalWork: number;
|
|
217
|
+
readonly doneWork: number;
|
|
218
|
+
readonly likelihood: number | null;
|
|
219
|
+
readonly cannotBeForecast: boolean;
|
|
220
|
+
readonly hasSufficientData: boolean | undefined;
|
|
221
|
+
};
|
|
222
|
+
/** One archived Delivery, or null when it comes without its id, name, dates or work. */
|
|
223
|
+
export declare const readArchivedDeliveryItem: (value: unknown) => ArchivedDeliveryItem | null;
|
|
224
|
+
/** A Portfolio's active and archived Deliveries, or null when either list or any row in it cannot be read. */
|
|
225
|
+
export declare const readPortfolioDeliveries: (value: unknown) => {
|
|
226
|
+
active: DeliveryListItem[];
|
|
227
|
+
archived: ArchivedDeliveryItem[];
|
|
228
|
+
} | null;
|
|
209
229
|
/** "Ocean Explorer · Deliveries", or the Portfolio by its id when its name could not be read. */
|
|
210
230
|
export declare const describeDeliveryListTitle: (owner: DeliveryListOwner, terms: Terms) => string;
|
|
211
231
|
/** What a Portfolio without any Delivery shows instead of the table. */
|
|
@@ -220,6 +240,12 @@ export declare const describeDeliveryDone: (delivery: Pick<DeliveryListItem, "to
|
|
|
220
240
|
export declare const describeDeliveryLikelihood: (delivery: DeliveryListItem) => string;
|
|
221
241
|
/** One Delivery as a row of the list, in the order of its headings. */
|
|
222
242
|
export declare const describeDeliveryRow: (delivery: DeliveryListItem, terms: Terms) => string[];
|
|
243
|
+
/** What heads the archived Deliveries, below the active ones: "Archived Deliveries". */
|
|
244
|
+
export declare const describeArchivedDeliveriesTitle: (terms: Terms) => string;
|
|
245
|
+
/** The archived table's column headings: when it was due, when it closed, and what it reached. */
|
|
246
|
+
export declare const describeArchivedDeliveryHeadings: (terms: Terms) => string[];
|
|
247
|
+
/** One archived Delivery as a row of its table, in the order of its headings. */
|
|
248
|
+
export declare const describeArchivedDeliveryRow: (delivery: ArchivedDeliveryItem, terms: Terms) => string[];
|
|
223
249
|
/**
|
|
224
250
|
* A Delivery's recorded days, or null when the answer lacks its Delivery Date or any day lacks a fact its
|
|
225
251
|
* row or detail states: a table with a hole in it would misstate the trend.
|
|
@@ -244,7 +270,7 @@ export declare const describeDeliveryFeatureHeadings: (terms: Terms) => string[]
|
|
|
244
270
|
export declare const describeDeliveryFeatureRow: (feature: DeliveryFeatureMetric) => string[];
|
|
245
271
|
/** The forecast distribution's column headings. */
|
|
246
272
|
export declare const describeDeliveryChanceHeadings: () => string[];
|
|
247
|
-
/** One chance of the day's forecast: "85%" and the day it is that likely to be done by. */
|
|
273
|
+
/** One chance of the day's forecast: "85%" and the day it is that likely to be done by, or "More than 5 years". */
|
|
248
274
|
export declare const describeDeliveryChanceRow: (chance: DeliveryWhenDistributionPoint) => string[];
|
|
249
275
|
//#endregion
|
|
250
276
|
//#region src/featureWording.d.ts
|
|
@@ -252,6 +278,7 @@ export declare const describeDeliveryChanceRow: (chance: DeliveryWhenDistributio
|
|
|
252
278
|
export type FeatureStart = {
|
|
253
279
|
readonly observedOn: string | undefined;
|
|
254
280
|
readonly likelyBy: string | undefined;
|
|
281
|
+
readonly likelyByBeyondHorizonYears?: number;
|
|
255
282
|
};
|
|
256
283
|
/** One Feature as a row of the Feature list states it. */
|
|
257
284
|
export type FeatureListItem = {
|
|
@@ -263,6 +290,7 @@ export type FeatureListItem = {
|
|
|
263
290
|
readonly cannotBeForecast: boolean;
|
|
264
291
|
readonly start: FeatureStart;
|
|
265
292
|
readonly likelyBy: string | undefined;
|
|
293
|
+
readonly likelyByBeyondHorizonYears?: number;
|
|
266
294
|
};
|
|
267
295
|
/**
|
|
268
296
|
* Every Feature in the answer, or null when it is not a list or any one of them comes without its
|
|
@@ -280,8 +308,11 @@ export declare const describeFeatureProgress: (feature: Pick<FeatureListItem, "t
|
|
|
280
308
|
* Team without history; that Team only stops anyone saying when work will begin.
|
|
281
309
|
*/
|
|
282
310
|
export declare const describeFeatureStart: (feature: Pick<FeatureListItem, "start" | "cannotBeForecast">) => string;
|
|
283
|
-
/**
|
|
284
|
-
|
|
311
|
+
/**
|
|
312
|
+
* The day the Feature is 85% likely to be done by, "More than 5 years" when that lies beyond the simulation
|
|
313
|
+
* horizon, "Cannot forecast", or the mark when none was sent.
|
|
314
|
+
*/
|
|
315
|
+
export declare const describeFeatureCompletion: (feature: Pick<FeatureListItem, "likelyBy" | "likelyByBeyondHorizonYears" | "cannotBeForecast">) => string;
|
|
285
316
|
/** One Feature as a row of the list, in the order of its headings. */
|
|
286
317
|
export declare const describeFeatureRow: (feature: FeatureListItem, terms: Terms) => string[];
|
|
287
318
|
/** One Work Item of a Feature as the Feature's Work Items list states it. */
|
|
@@ -332,11 +363,33 @@ export declare const deliveryLikelihoodAnswer: (facts: Parameters<typeof likelih
|
|
|
332
363
|
readonly isOverdue?: boolean;
|
|
333
364
|
}) => string;
|
|
334
365
|
//#endregion
|
|
366
|
+
//#region src/forecastPercentileText.d.ts
|
|
367
|
+
/**
|
|
368
|
+
* A forecast percentile as Lighthouse sends it. A percentile too few simulated runs reached carries
|
|
369
|
+
* `beyondHorizon` and the horizon's length in `horizonYears`; its `expectedDate` is then only a stand-in
|
|
370
|
+
* that nothing forecast, kept so an older client still reads a date. An older Lighthouse sends neither.
|
|
371
|
+
*/
|
|
372
|
+
export type ForecastPercentileDate = {
|
|
373
|
+
readonly expectedDate: string;
|
|
374
|
+
readonly beyondHorizon?: boolean;
|
|
375
|
+
readonly horizonYears?: number | null;
|
|
376
|
+
};
|
|
377
|
+
/**
|
|
378
|
+
* The years of the horizon a percentile lies beyond, or undefined when its date is the forecast. Keyed on
|
|
379
|
+
* the flag itself, never on the server's version: an older Lighthouse never sends it.
|
|
380
|
+
*/
|
|
381
|
+
export declare const yearsBeyondHorizon: (percentile: unknown) => number | undefined;
|
|
382
|
+
/** The words shown in place of a date for a percentile too few simulated runs reached. */
|
|
383
|
+
export declare const moreThanYearsText: (horizonYears: number) => string;
|
|
384
|
+
/** A percentile's day as a person reads it, or "More than 5 years" when it lies beyond that horizon. */
|
|
385
|
+
export declare const describePercentileDay: (expectedDate: string, horizonYearsBeyond: number | undefined) => string;
|
|
386
|
+
/** One percentile as text: its day, or the words when it lies beyond the horizon. */
|
|
387
|
+
export declare const describePercentileDate: (percentile: ForecastPercentileDate) => string;
|
|
388
|
+
//#endregion
|
|
335
389
|
//#region src/forecastWording.d.ts
|
|
336
390
|
/** One row of the When table: the chance of being done by a calendar day. */
|
|
337
|
-
export type ForecastChanceByDay = {
|
|
391
|
+
export type ForecastChanceByDay = ForecastPercentileDate & {
|
|
338
392
|
readonly probability: number;
|
|
339
|
-
readonly expectedDate: string;
|
|
340
393
|
};
|
|
341
394
|
/** One row of the How Many table: the chance of getting this many done. */
|
|
342
395
|
export type ForecastChanceOfCount = {
|
|
@@ -507,7 +560,15 @@ export declare const readArrivals: typeof readDailyCountChart;
|
|
|
507
560
|
* range's first day, read as the total and the count of each day. Without a total the days are summed.
|
|
508
561
|
*/
|
|
509
562
|
export declare const readRunChart: (value: unknown, range: MetricsDateRange) => DailyCountChartView | null;
|
|
510
|
-
|
|
563
|
+
declare const STALE_REASON_KINDS: readonly ["TimeInState", "BlockedDuration", "TimeInStateWhileBlocked"];
|
|
564
|
+
type StaleReasonKind = (typeof STALE_REASON_KINDS)[number];
|
|
565
|
+
/** Why Lighthouse marks a Work Item stale, in whole days on the instance's calendar. */
|
|
566
|
+
export type StaleReason = {
|
|
567
|
+
readonly kind: StaleReasonKind;
|
|
568
|
+
readonly days: number;
|
|
569
|
+
readonly stateName?: string;
|
|
570
|
+
};
|
|
571
|
+
/** A Work Item in progress; an older Lighthouse does not say whether it is blocked, or stale. */
|
|
511
572
|
export type InProgressItem = {
|
|
512
573
|
readonly isBlocked: boolean | undefined;
|
|
513
574
|
readonly referenceId?: string;
|
|
@@ -515,6 +576,8 @@ export type InProgressItem = {
|
|
|
515
576
|
readonly state?: string;
|
|
516
577
|
readonly workItemAge?: number;
|
|
517
578
|
readonly blockedSince?: string;
|
|
579
|
+
readonly isStale?: boolean;
|
|
580
|
+
readonly staleReasons?: readonly StaleReason[];
|
|
518
581
|
};
|
|
519
582
|
export type InProgressNowView = {
|
|
520
583
|
readonly asOfDate: string;
|
|
@@ -596,7 +659,7 @@ export declare const PREDICTABILITY_SCORE_EXPLANATION = "The predictability scor
|
|
|
596
659
|
/** What an empty over-time chart says on the web. */
|
|
597
660
|
export declare const OVER_TIME_EMPTY_SENTENCE = "Nothing to show for the selected range. Days appear here as Lighthouse records them.";
|
|
598
661
|
/** Every part of the headline that can be refused or unreadable on its own. */
|
|
599
|
-
export type MetricsHeadlinePart = "wip" | "throughput" | "arrivals" | "blocked" | "totalWorkItemAge" | "predictabilityScore" | "cycleTimePercentiles" | "workItemAgePercentiles" | "workItemAge" | "cumulativeStateTime" | "percentilesOverTime" | "processBehaviorOverTime";
|
|
662
|
+
export type MetricsHeadlinePart = "wip" | "throughput" | "arrivals" | "blocked" | "stale" | "totalWorkItemAge" | "predictabilityScore" | "cycleTimePercentiles" | "workItemAgePercentiles" | "workItemAge" | "cumulativeStateTime" | "percentilesOverTime" | "processBehaviorOverTime";
|
|
600
663
|
/** "1 day", "12 days". */
|
|
601
664
|
export declare const describeDays: (days: number) => string;
|
|
602
665
|
/** The label each part of the headline goes by, in the instance's words. */
|
|
@@ -615,10 +678,13 @@ export declare const describeAsOfHeading: (subject: Pick<MetricsSubject, "endDat
|
|
|
615
678
|
export declare const describeInProgressNow: (now: InProgressNowView, scope: MetricsScope, terms: Terms, systemWipLimit: number | undefined) => MetricLine;
|
|
616
679
|
/** "Blocked Work Items 2", or null when Lighthouse does not say which items are blocked. */
|
|
617
680
|
export declare const describeBlockedNow: (now: InProgressNowView, scope: MetricsScope, terms: Terms) => MetricLine | null;
|
|
681
|
+
/** "Stale Work Items 2", or null when Lighthouse does not say which items are stale. */
|
|
682
|
+
export declare const describeStaleNow: (now: InProgressNowView, scope: MetricsScope, terms: Terms) => MetricLine | null;
|
|
618
683
|
/**
|
|
619
684
|
* The sentences that stand in for what a WIP answer cannot show: no System WIP Limit, a Lighthouse that does
|
|
620
|
-
* not say which Work Items are Blocked (which is not the same as none being
|
|
621
|
-
* A limit of null means the Team or Portfolio could not be read; it may well have one, so nothing
|
|
685
|
+
* not say which Work Items are Blocked or Stale (which is not the same as none being so), and nothing in
|
|
686
|
+
* progress. A limit of null means the Team or Portfolio could not be read; it may well have one, so nothing
|
|
687
|
+
* is said.
|
|
622
688
|
*/
|
|
623
689
|
export declare const describeWhatWipLeavesUnsaid: (now: InProgressNowView, scope: MetricsScope, terms: Terms, systemWipLimit: number | undefined | null) => readonly string[];
|
|
624
690
|
/** "Total Throughput 31 1.0 / day". */
|
|
@@ -1303,6 +1369,11 @@ export type LighthouseApiResult<TValue> = {
|
|
|
1303
1369
|
readonly error: LighthouseApiError;
|
|
1304
1370
|
};
|
|
1305
1371
|
export type LighthouseWritePayload = Readonly<Record<string, unknown>>;
|
|
1372
|
+
/** A Portfolio's Deliveries: the ones still running apart from the archived ones. */
|
|
1373
|
+
export type PortfolioDeliveries = {
|
|
1374
|
+
readonly active: readonly unknown[];
|
|
1375
|
+
readonly archived: readonly unknown[];
|
|
1376
|
+
};
|
|
1306
1377
|
export type MetricsDateRange = {
|
|
1307
1378
|
readonly startDate: string;
|
|
1308
1379
|
readonly endDate: string;
|
|
@@ -1401,6 +1472,10 @@ export type DeliveryFeatureMetric = {
|
|
|
1401
1472
|
export type DeliveryWhenDistributionPoint = {
|
|
1402
1473
|
readonly probability: number;
|
|
1403
1474
|
readonly expectedDate: string;
|
|
1475
|
+
/** True when too few simulated runs reached this chance: `expectedDate` is then only a stand-in. Absent on an older Lighthouse. */
|
|
1476
|
+
readonly beyondHorizon?: boolean;
|
|
1477
|
+
/** The simulation horizon, in years, this chance was forecast with. Absent on an older Lighthouse and on days recorded before it. */
|
|
1478
|
+
readonly horizonYears?: number | null;
|
|
1404
1479
|
};
|
|
1405
1480
|
/** A delivery as it stood on one recorded day. Dates are ISO strings. */
|
|
1406
1481
|
export type DeliveryMetricsHistoryPoint = {
|
|
@@ -1773,7 +1848,7 @@ export type LighthouseClient = {
|
|
|
1773
1848
|
readonly getFeaturesByIds: (ids: readonly number[]) => Promise<LighthouseApiResult<readonly unknown[]>>;
|
|
1774
1849
|
readonly getFeaturesByReferences: (refs: readonly string[]) => Promise<LighthouseApiResult<readonly unknown[]>>;
|
|
1775
1850
|
readonly getFeatureWorkItems: (featureId: number) => Promise<LighthouseApiResult<readonly unknown[]>>;
|
|
1776
|
-
readonly listDeliveries: (portfolioId: number) => Promise<LighthouseApiResult<
|
|
1851
|
+
readonly listDeliveries: (portfolioId: number) => Promise<LighthouseApiResult<PortfolioDeliveries>>;
|
|
1777
1852
|
readonly createDelivery: (portfolioId: number, payload: LighthouseWritePayload) => Promise<LighthouseApiResult<unknown>>;
|
|
1778
1853
|
readonly updateDelivery: (deliveryId: number, payload: LighthouseWritePayload) => Promise<LighthouseApiResult<unknown>>;
|
|
1779
1854
|
readonly deleteDelivery: (deliveryId: number) => Promise<LighthouseApiResult<undefined>>;
|
|
@@ -1821,6 +1896,7 @@ export declare const FEATURE_REQUIRES_SERVER_NEWER_THAN: {
|
|
|
1821
1896
|
readonly sleRisk: "v26.9.19.10";
|
|
1822
1897
|
readonly teamRefinement: "v26.10.3.6";
|
|
1823
1898
|
readonly refinementVotes: "v26.10.3.6";
|
|
1899
|
+
readonly staleness: "v26.10.16.6";
|
|
1824
1900
|
};
|
|
1825
1901
|
/**
|
|
1826
1902
|
* Returns true when `candidate` is strictly newer than `baseline`, false when
|
|
@@ -1831,4 +1907,5 @@ export declare const isServerVersionNewerThan: (candidate: string, baseline: str
|
|
|
1831
1907
|
/** The header a client sends its voter key in, so Lighthouse can tell its votes from anyone else's. */
|
|
1832
1908
|
export declare const VOTER_KEY_HEADER = "X-Lighthouse-Voter-Key";
|
|
1833
1909
|
export declare const createLighthouseClient: (configuration: LighthouseClientConfiguration, dependencies?: LighthouseClientDependencies) => LighthouseClient;
|
|
1834
|
-
//#endregion
|
|
1910
|
+
//#endregion
|
|
1911
|
+
export {};
|
package/dist/index.d.ts
CHANGED
|
@@ -195,6 +195,7 @@ export type DeliveryListItem = {
|
|
|
195
195
|
readonly hasSufficientData: boolean | undefined;
|
|
196
196
|
readonly isOverdue: boolean | undefined;
|
|
197
197
|
readonly likelyBy: string | undefined;
|
|
198
|
+
readonly likelyByBeyondHorizonYears?: number;
|
|
198
199
|
};
|
|
199
200
|
/** The Portfolio whose Deliveries are listed; its name stays undefined when it could not be read. */
|
|
200
201
|
export type DeliveryListOwner = {
|
|
@@ -206,6 +207,25 @@ export type DeliveryListOwner = {
|
|
|
206
207
|
* id, name, date or work: a row that cannot say what it is or when it is due would misstate the list.
|
|
207
208
|
*/
|
|
208
209
|
export declare const readDeliveryList: (value: unknown) => DeliveryListItem[] | null;
|
|
210
|
+
/** One archived Delivery as the archived table states it: the numbers written down the day it closed. */
|
|
211
|
+
export type ArchivedDeliveryItem = {
|
|
212
|
+
readonly id: number;
|
|
213
|
+
readonly name: string;
|
|
214
|
+
readonly date: string;
|
|
215
|
+
readonly archivedOn: string;
|
|
216
|
+
readonly totalWork: number;
|
|
217
|
+
readonly doneWork: number;
|
|
218
|
+
readonly likelihood: number | null;
|
|
219
|
+
readonly cannotBeForecast: boolean;
|
|
220
|
+
readonly hasSufficientData: boolean | undefined;
|
|
221
|
+
};
|
|
222
|
+
/** One archived Delivery, or null when it comes without its id, name, dates or work. */
|
|
223
|
+
export declare const readArchivedDeliveryItem: (value: unknown) => ArchivedDeliveryItem | null;
|
|
224
|
+
/** A Portfolio's active and archived Deliveries, or null when either list or any row in it cannot be read. */
|
|
225
|
+
export declare const readPortfolioDeliveries: (value: unknown) => {
|
|
226
|
+
active: DeliveryListItem[];
|
|
227
|
+
archived: ArchivedDeliveryItem[];
|
|
228
|
+
} | null;
|
|
209
229
|
/** "Ocean Explorer · Deliveries", or the Portfolio by its id when its name could not be read. */
|
|
210
230
|
export declare const describeDeliveryListTitle: (owner: DeliveryListOwner, terms: Terms) => string;
|
|
211
231
|
/** What a Portfolio without any Delivery shows instead of the table. */
|
|
@@ -220,6 +240,12 @@ export declare const describeDeliveryDone: (delivery: Pick<DeliveryListItem, "to
|
|
|
220
240
|
export declare const describeDeliveryLikelihood: (delivery: DeliveryListItem) => string;
|
|
221
241
|
/** One Delivery as a row of the list, in the order of its headings. */
|
|
222
242
|
export declare const describeDeliveryRow: (delivery: DeliveryListItem, terms: Terms) => string[];
|
|
243
|
+
/** What heads the archived Deliveries, below the active ones: "Archived Deliveries". */
|
|
244
|
+
export declare const describeArchivedDeliveriesTitle: (terms: Terms) => string;
|
|
245
|
+
/** The archived table's column headings: when it was due, when it closed, and what it reached. */
|
|
246
|
+
export declare const describeArchivedDeliveryHeadings: (terms: Terms) => string[];
|
|
247
|
+
/** One archived Delivery as a row of its table, in the order of its headings. */
|
|
248
|
+
export declare const describeArchivedDeliveryRow: (delivery: ArchivedDeliveryItem, terms: Terms) => string[];
|
|
223
249
|
/**
|
|
224
250
|
* A Delivery's recorded days, or null when the answer lacks its Delivery Date or any day lacks a fact its
|
|
225
251
|
* row or detail states: a table with a hole in it would misstate the trend.
|
|
@@ -244,7 +270,7 @@ export declare const describeDeliveryFeatureHeadings: (terms: Terms) => string[]
|
|
|
244
270
|
export declare const describeDeliveryFeatureRow: (feature: DeliveryFeatureMetric) => string[];
|
|
245
271
|
/** The forecast distribution's column headings. */
|
|
246
272
|
export declare const describeDeliveryChanceHeadings: () => string[];
|
|
247
|
-
/** One chance of the day's forecast: "85%" and the day it is that likely to be done by. */
|
|
273
|
+
/** One chance of the day's forecast: "85%" and the day it is that likely to be done by, or "More than 5 years". */
|
|
248
274
|
export declare const describeDeliveryChanceRow: (chance: DeliveryWhenDistributionPoint) => string[];
|
|
249
275
|
//#endregion
|
|
250
276
|
//#region src/featureWording.d.ts
|
|
@@ -252,6 +278,7 @@ export declare const describeDeliveryChanceRow: (chance: DeliveryWhenDistributio
|
|
|
252
278
|
export type FeatureStart = {
|
|
253
279
|
readonly observedOn: string | undefined;
|
|
254
280
|
readonly likelyBy: string | undefined;
|
|
281
|
+
readonly likelyByBeyondHorizonYears?: number;
|
|
255
282
|
};
|
|
256
283
|
/** One Feature as a row of the Feature list states it. */
|
|
257
284
|
export type FeatureListItem = {
|
|
@@ -263,6 +290,7 @@ export type FeatureListItem = {
|
|
|
263
290
|
readonly cannotBeForecast: boolean;
|
|
264
291
|
readonly start: FeatureStart;
|
|
265
292
|
readonly likelyBy: string | undefined;
|
|
293
|
+
readonly likelyByBeyondHorizonYears?: number;
|
|
266
294
|
};
|
|
267
295
|
/**
|
|
268
296
|
* Every Feature in the answer, or null when it is not a list or any one of them comes without its
|
|
@@ -280,8 +308,11 @@ export declare const describeFeatureProgress: (feature: Pick<FeatureListItem, "t
|
|
|
280
308
|
* Team without history; that Team only stops anyone saying when work will begin.
|
|
281
309
|
*/
|
|
282
310
|
export declare const describeFeatureStart: (feature: Pick<FeatureListItem, "start" | "cannotBeForecast">) => string;
|
|
283
|
-
/**
|
|
284
|
-
|
|
311
|
+
/**
|
|
312
|
+
* The day the Feature is 85% likely to be done by, "More than 5 years" when that lies beyond the simulation
|
|
313
|
+
* horizon, "Cannot forecast", or the mark when none was sent.
|
|
314
|
+
*/
|
|
315
|
+
export declare const describeFeatureCompletion: (feature: Pick<FeatureListItem, "likelyBy" | "likelyByBeyondHorizonYears" | "cannotBeForecast">) => string;
|
|
285
316
|
/** One Feature as a row of the list, in the order of its headings. */
|
|
286
317
|
export declare const describeFeatureRow: (feature: FeatureListItem, terms: Terms) => string[];
|
|
287
318
|
/** One Work Item of a Feature as the Feature's Work Items list states it. */
|
|
@@ -332,11 +363,33 @@ export declare const deliveryLikelihoodAnswer: (facts: Parameters<typeof likelih
|
|
|
332
363
|
readonly isOverdue?: boolean;
|
|
333
364
|
}) => string;
|
|
334
365
|
//#endregion
|
|
366
|
+
//#region src/forecastPercentileText.d.ts
|
|
367
|
+
/**
|
|
368
|
+
* A forecast percentile as Lighthouse sends it. A percentile too few simulated runs reached carries
|
|
369
|
+
* `beyondHorizon` and the horizon's length in `horizonYears`; its `expectedDate` is then only a stand-in
|
|
370
|
+
* that nothing forecast, kept so an older client still reads a date. An older Lighthouse sends neither.
|
|
371
|
+
*/
|
|
372
|
+
export type ForecastPercentileDate = {
|
|
373
|
+
readonly expectedDate: string;
|
|
374
|
+
readonly beyondHorizon?: boolean;
|
|
375
|
+
readonly horizonYears?: number | null;
|
|
376
|
+
};
|
|
377
|
+
/**
|
|
378
|
+
* The years of the horizon a percentile lies beyond, or undefined when its date is the forecast. Keyed on
|
|
379
|
+
* the flag itself, never on the server's version: an older Lighthouse never sends it.
|
|
380
|
+
*/
|
|
381
|
+
export declare const yearsBeyondHorizon: (percentile: unknown) => number | undefined;
|
|
382
|
+
/** The words shown in place of a date for a percentile too few simulated runs reached. */
|
|
383
|
+
export declare const moreThanYearsText: (horizonYears: number) => string;
|
|
384
|
+
/** A percentile's day as a person reads it, or "More than 5 years" when it lies beyond that horizon. */
|
|
385
|
+
export declare const describePercentileDay: (expectedDate: string, horizonYearsBeyond: number | undefined) => string;
|
|
386
|
+
/** One percentile as text: its day, or the words when it lies beyond the horizon. */
|
|
387
|
+
export declare const describePercentileDate: (percentile: ForecastPercentileDate) => string;
|
|
388
|
+
//#endregion
|
|
335
389
|
//#region src/forecastWording.d.ts
|
|
336
390
|
/** One row of the When table: the chance of being done by a calendar day. */
|
|
337
|
-
export type ForecastChanceByDay = {
|
|
391
|
+
export type ForecastChanceByDay = ForecastPercentileDate & {
|
|
338
392
|
readonly probability: number;
|
|
339
|
-
readonly expectedDate: string;
|
|
340
393
|
};
|
|
341
394
|
/** One row of the How Many table: the chance of getting this many done. */
|
|
342
395
|
export type ForecastChanceOfCount = {
|
|
@@ -507,7 +560,15 @@ export declare const readArrivals: typeof readDailyCountChart;
|
|
|
507
560
|
* range's first day, read as the total and the count of each day. Without a total the days are summed.
|
|
508
561
|
*/
|
|
509
562
|
export declare const readRunChart: (value: unknown, range: MetricsDateRange) => DailyCountChartView | null;
|
|
510
|
-
|
|
563
|
+
declare const STALE_REASON_KINDS: readonly ["TimeInState", "BlockedDuration", "TimeInStateWhileBlocked"];
|
|
564
|
+
type StaleReasonKind = (typeof STALE_REASON_KINDS)[number];
|
|
565
|
+
/** Why Lighthouse marks a Work Item stale, in whole days on the instance's calendar. */
|
|
566
|
+
export type StaleReason = {
|
|
567
|
+
readonly kind: StaleReasonKind;
|
|
568
|
+
readonly days: number;
|
|
569
|
+
readonly stateName?: string;
|
|
570
|
+
};
|
|
571
|
+
/** A Work Item in progress; an older Lighthouse does not say whether it is blocked, or stale. */
|
|
511
572
|
export type InProgressItem = {
|
|
512
573
|
readonly isBlocked: boolean | undefined;
|
|
513
574
|
readonly referenceId?: string;
|
|
@@ -515,6 +576,8 @@ export type InProgressItem = {
|
|
|
515
576
|
readonly state?: string;
|
|
516
577
|
readonly workItemAge?: number;
|
|
517
578
|
readonly blockedSince?: string;
|
|
579
|
+
readonly isStale?: boolean;
|
|
580
|
+
readonly staleReasons?: readonly StaleReason[];
|
|
518
581
|
};
|
|
519
582
|
export type InProgressNowView = {
|
|
520
583
|
readonly asOfDate: string;
|
|
@@ -596,7 +659,7 @@ export declare const PREDICTABILITY_SCORE_EXPLANATION = "The predictability scor
|
|
|
596
659
|
/** What an empty over-time chart says on the web. */
|
|
597
660
|
export declare const OVER_TIME_EMPTY_SENTENCE = "Nothing to show for the selected range. Days appear here as Lighthouse records them.";
|
|
598
661
|
/** Every part of the headline that can be refused or unreadable on its own. */
|
|
599
|
-
export type MetricsHeadlinePart = "wip" | "throughput" | "arrivals" | "blocked" | "totalWorkItemAge" | "predictabilityScore" | "cycleTimePercentiles" | "workItemAgePercentiles" | "workItemAge" | "cumulativeStateTime" | "percentilesOverTime" | "processBehaviorOverTime";
|
|
662
|
+
export type MetricsHeadlinePart = "wip" | "throughput" | "arrivals" | "blocked" | "stale" | "totalWorkItemAge" | "predictabilityScore" | "cycleTimePercentiles" | "workItemAgePercentiles" | "workItemAge" | "cumulativeStateTime" | "percentilesOverTime" | "processBehaviorOverTime";
|
|
600
663
|
/** "1 day", "12 days". */
|
|
601
664
|
export declare const describeDays: (days: number) => string;
|
|
602
665
|
/** The label each part of the headline goes by, in the instance's words. */
|
|
@@ -615,10 +678,13 @@ export declare const describeAsOfHeading: (subject: Pick<MetricsSubject, "endDat
|
|
|
615
678
|
export declare const describeInProgressNow: (now: InProgressNowView, scope: MetricsScope, terms: Terms, systemWipLimit: number | undefined) => MetricLine;
|
|
616
679
|
/** "Blocked Work Items 2", or null when Lighthouse does not say which items are blocked. */
|
|
617
680
|
export declare const describeBlockedNow: (now: InProgressNowView, scope: MetricsScope, terms: Terms) => MetricLine | null;
|
|
681
|
+
/** "Stale Work Items 2", or null when Lighthouse does not say which items are stale. */
|
|
682
|
+
export declare const describeStaleNow: (now: InProgressNowView, scope: MetricsScope, terms: Terms) => MetricLine | null;
|
|
618
683
|
/**
|
|
619
684
|
* The sentences that stand in for what a WIP answer cannot show: no System WIP Limit, a Lighthouse that does
|
|
620
|
-
* not say which Work Items are Blocked (which is not the same as none being
|
|
621
|
-
* A limit of null means the Team or Portfolio could not be read; it may well have one, so nothing
|
|
685
|
+
* not say which Work Items are Blocked or Stale (which is not the same as none being so), and nothing in
|
|
686
|
+
* progress. A limit of null means the Team or Portfolio could not be read; it may well have one, so nothing
|
|
687
|
+
* is said.
|
|
622
688
|
*/
|
|
623
689
|
export declare const describeWhatWipLeavesUnsaid: (now: InProgressNowView, scope: MetricsScope, terms: Terms, systemWipLimit: number | undefined | null) => readonly string[];
|
|
624
690
|
/** "Total Throughput 31 1.0 / day". */
|
|
@@ -1303,6 +1369,11 @@ export type LighthouseApiResult<TValue> = {
|
|
|
1303
1369
|
readonly error: LighthouseApiError;
|
|
1304
1370
|
};
|
|
1305
1371
|
export type LighthouseWritePayload = Readonly<Record<string, unknown>>;
|
|
1372
|
+
/** A Portfolio's Deliveries: the ones still running apart from the archived ones. */
|
|
1373
|
+
export type PortfolioDeliveries = {
|
|
1374
|
+
readonly active: readonly unknown[];
|
|
1375
|
+
readonly archived: readonly unknown[];
|
|
1376
|
+
};
|
|
1306
1377
|
export type MetricsDateRange = {
|
|
1307
1378
|
readonly startDate: string;
|
|
1308
1379
|
readonly endDate: string;
|
|
@@ -1401,6 +1472,10 @@ export type DeliveryFeatureMetric = {
|
|
|
1401
1472
|
export type DeliveryWhenDistributionPoint = {
|
|
1402
1473
|
readonly probability: number;
|
|
1403
1474
|
readonly expectedDate: string;
|
|
1475
|
+
/** True when too few simulated runs reached this chance: `expectedDate` is then only a stand-in. Absent on an older Lighthouse. */
|
|
1476
|
+
readonly beyondHorizon?: boolean;
|
|
1477
|
+
/** The simulation horizon, in years, this chance was forecast with. Absent on an older Lighthouse and on days recorded before it. */
|
|
1478
|
+
readonly horizonYears?: number | null;
|
|
1404
1479
|
};
|
|
1405
1480
|
/** A delivery as it stood on one recorded day. Dates are ISO strings. */
|
|
1406
1481
|
export type DeliveryMetricsHistoryPoint = {
|
|
@@ -1773,7 +1848,7 @@ export type LighthouseClient = {
|
|
|
1773
1848
|
readonly getFeaturesByIds: (ids: readonly number[]) => Promise<LighthouseApiResult<readonly unknown[]>>;
|
|
1774
1849
|
readonly getFeaturesByReferences: (refs: readonly string[]) => Promise<LighthouseApiResult<readonly unknown[]>>;
|
|
1775
1850
|
readonly getFeatureWorkItems: (featureId: number) => Promise<LighthouseApiResult<readonly unknown[]>>;
|
|
1776
|
-
readonly listDeliveries: (portfolioId: number) => Promise<LighthouseApiResult<
|
|
1851
|
+
readonly listDeliveries: (portfolioId: number) => Promise<LighthouseApiResult<PortfolioDeliveries>>;
|
|
1777
1852
|
readonly createDelivery: (portfolioId: number, payload: LighthouseWritePayload) => Promise<LighthouseApiResult<unknown>>;
|
|
1778
1853
|
readonly updateDelivery: (deliveryId: number, payload: LighthouseWritePayload) => Promise<LighthouseApiResult<unknown>>;
|
|
1779
1854
|
readonly deleteDelivery: (deliveryId: number) => Promise<LighthouseApiResult<undefined>>;
|
|
@@ -1821,6 +1896,7 @@ export declare const FEATURE_REQUIRES_SERVER_NEWER_THAN: {
|
|
|
1821
1896
|
readonly sleRisk: "v26.9.19.10";
|
|
1822
1897
|
readonly teamRefinement: "v26.10.3.6";
|
|
1823
1898
|
readonly refinementVotes: "v26.10.3.6";
|
|
1899
|
+
readonly staleness: "v26.10.16.6";
|
|
1824
1900
|
};
|
|
1825
1901
|
/**
|
|
1826
1902
|
* Returns true when `candidate` is strictly newer than `baseline`, false when
|
|
@@ -1831,4 +1907,5 @@ export declare const isServerVersionNewerThan: (candidate: string, baseline: str
|
|
|
1831
1907
|
/** The header a client sends its voter key in, so Lighthouse can tell its votes from anyone else's. */
|
|
1832
1908
|
export declare const VOTER_KEY_HEADER = "X-Lighthouse-Voter-Key";
|
|
1833
1909
|
export declare const createLighthouseClient: (configuration: LighthouseClientConfiguration, dependencies?: LighthouseClientDependencies) => LighthouseClient;
|
|
1834
|
-
//#endregion
|
|
1910
|
+
//#endregion
|
|
1911
|
+
export {};
|
package/dist/index.js
CHANGED
|
@@ -241,13 +241,26 @@ const textOf = (value) => typeof value === "string" && value.length > 0 ? value
|
|
|
241
241
|
const isDay = (value) => isText(value) && formatCalendarDay(value) !== null;
|
|
242
242
|
/** The calendar day as a person reads it, or the text exactly as sent when it is not one. */
|
|
243
243
|
const dayOf = (wire) => formatCalendarDay(wire) ?? wire;
|
|
244
|
-
/** The
|
|
245
|
-
const
|
|
244
|
+
/** The chance a list gives for one probability, or undefined when it holds none for it. */
|
|
245
|
+
const chanceAt = (chances, probability) => {
|
|
246
246
|
if (!Array.isArray(chances)) return;
|
|
247
247
|
const chance = chances.find((entry) => isRecord(entry) && entry.probability === probability);
|
|
248
|
-
return isRecord(chance) ?
|
|
248
|
+
return isRecord(chance) ? chance : void 0;
|
|
249
249
|
};
|
|
250
250
|
//#endregion
|
|
251
|
+
//#region src/forecastPercentileText.ts
|
|
252
|
+
/**
|
|
253
|
+
* The years of the horizon a percentile lies beyond, or undefined when its date is the forecast. Keyed on
|
|
254
|
+
* the flag itself, never on the server's version: an older Lighthouse never sends it.
|
|
255
|
+
*/
|
|
256
|
+
const yearsBeyondHorizon = (percentile) => isRecord(percentile) && percentile.beyondHorizon === true && isNumber(percentile.horizonYears) ? percentile.horizonYears : void 0;
|
|
257
|
+
/** The words shown in place of a date for a percentile too few simulated runs reached. */
|
|
258
|
+
const moreThanYearsText = (horizonYears) => `More than ${horizonYears} years`;
|
|
259
|
+
/** A percentile's day as a person reads it, or "More than 5 years" when it lies beyond that horizon. */
|
|
260
|
+
const describePercentileDay = (expectedDate, horizonYearsBeyond) => horizonYearsBeyond === void 0 ? dayOf(expectedDate) : moreThanYearsText(horizonYearsBeyond);
|
|
261
|
+
/** One percentile as text: its day, or the words when it lies beyond the horizon. */
|
|
262
|
+
const describePercentileDate = (percentile) => describePercentileDay(percentile.expectedDate, yearsBeyondHorizon(percentile));
|
|
263
|
+
//#endregion
|
|
251
264
|
//#region src/ownerWording.ts
|
|
252
265
|
/** A mark for a cell Lighthouse sent nothing for. */
|
|
253
266
|
const NOT_SENT = "—";
|
|
@@ -407,9 +420,11 @@ const startOf = (value) => {
|
|
|
407
420
|
observedOn: void 0,
|
|
408
421
|
likelyBy: void 0
|
|
409
422
|
};
|
|
423
|
+
const chance = chanceAt(value.percentiles, LISTED_CHANCE$1);
|
|
410
424
|
return {
|
|
411
425
|
observedOn: value.source === "Observed" ? textOf(value.observedDate) : void 0,
|
|
412
|
-
likelyBy:
|
|
426
|
+
likelyBy: textOf(chance?.expectedDate),
|
|
427
|
+
likelyByBeyondHorizonYears: yearsBeyondHorizon(chance)
|
|
413
428
|
};
|
|
414
429
|
};
|
|
415
430
|
const readFeatureListItem = (value) => {
|
|
@@ -419,6 +434,7 @@ const readFeatureListItem = (value) => {
|
|
|
419
434
|
const state = textOf(value.state);
|
|
420
435
|
const totalWork = workOf(value.totalWork);
|
|
421
436
|
const remainingWork = workOf(value.remainingWork);
|
|
437
|
+
const completion = chanceAt(value.forecasts, LISTED_CHANCE$1);
|
|
422
438
|
if (referenceId === void 0 || name === void 0 || state === void 0 || totalWork === null || remainingWork === null) return null;
|
|
423
439
|
return {
|
|
424
440
|
referenceId,
|
|
@@ -428,7 +444,8 @@ const readFeatureListItem = (value) => {
|
|
|
428
444
|
remainingWork,
|
|
429
445
|
cannotBeForecast: Array.isArray(value.teamsWithoutForecast) && value.teamsWithoutForecast.length > 0,
|
|
430
446
|
start: startOf(value.startForecast),
|
|
431
|
-
likelyBy:
|
|
447
|
+
likelyBy: textOf(completion?.expectedDate),
|
|
448
|
+
likelyByBeyondHorizonYears: yearsBeyondHorizon(completion)
|
|
432
449
|
};
|
|
433
450
|
};
|
|
434
451
|
/**
|
|
@@ -464,12 +481,15 @@ const describeFeatureProgress = (feature, terms) => `${feature.totalWork - featu
|
|
|
464
481
|
const describeFeatureStart = (feature) => {
|
|
465
482
|
if (feature.start.observedOn !== void 0) return dayOf(feature.start.observedOn);
|
|
466
483
|
if (feature.cannotBeForecast) return CANNOT_FORECAST_SHORT;
|
|
467
|
-
return feature.start.likelyBy === void 0 ? "—" :
|
|
484
|
+
return feature.start.likelyBy === void 0 ? "—" : describePercentileDay(feature.start.likelyBy, feature.start.likelyByBeyondHorizonYears);
|
|
468
485
|
};
|
|
469
|
-
/**
|
|
486
|
+
/**
|
|
487
|
+
* The day the Feature is 85% likely to be done by, "More than 5 years" when that lies beyond the simulation
|
|
488
|
+
* horizon, "Cannot forecast", or the mark when none was sent.
|
|
489
|
+
*/
|
|
470
490
|
const describeFeatureCompletion = (feature) => {
|
|
471
491
|
if (feature.cannotBeForecast) return CANNOT_FORECAST_SHORT;
|
|
472
|
-
return feature.likelyBy === void 0 ? "—" :
|
|
492
|
+
return feature.likelyBy === void 0 ? "—" : describePercentileDay(feature.likelyBy, feature.likelyByBeyondHorizonYears);
|
|
473
493
|
};
|
|
474
494
|
/** One Feature as a row of the list, in the order of its headings. */
|
|
475
495
|
const describeFeatureRow = (feature, terms) => [
|
|
@@ -626,11 +646,13 @@ const readFeatureWording = (source, featureId) => readAnswerWording(source, {
|
|
|
626
646
|
//#region src/deliveryWording.ts
|
|
627
647
|
const LISTED_CHANCE = 85;
|
|
628
648
|
const flagOf = (value) => typeof value === "boolean" ? value : void 0;
|
|
649
|
+
const teamsWithoutForecastIn = (value) => Array.isArray(value.teamsWithoutForecast) && value.teamsWithoutForecast.length > 0;
|
|
629
650
|
const readDeliveryListItem = (value) => {
|
|
630
651
|
if (!isRecord(value) || typeof value.id !== "number" || typeof value.totalWork !== "number" || typeof value.remainingWork !== "number") return null;
|
|
631
652
|
const name = textOf(value.name);
|
|
632
653
|
const date = textOf(value.date);
|
|
633
654
|
if (name === void 0 || date === void 0) return null;
|
|
655
|
+
const likely = chanceAt(value.completionDates, LISTED_CHANCE);
|
|
634
656
|
return {
|
|
635
657
|
id: value.id,
|
|
636
658
|
name,
|
|
@@ -639,10 +661,11 @@ const readDeliveryListItem = (value) => {
|
|
|
639
661
|
totalWork: value.totalWork,
|
|
640
662
|
remainingWork: value.remainingWork,
|
|
641
663
|
likelihood: typeof value.likelihoodPercentage === "number" ? value.likelihoodPercentage : null,
|
|
642
|
-
cannotBeForecast:
|
|
664
|
+
cannotBeForecast: teamsWithoutForecastIn(value),
|
|
643
665
|
hasSufficientData: flagOf(value.hasSufficientData),
|
|
644
666
|
isOverdue: flagOf(value.isOverdue),
|
|
645
|
-
likelyBy:
|
|
667
|
+
likelyBy: textOf(likely?.expectedDate),
|
|
668
|
+
likelyByBeyondHorizonYears: yearsBeyondHorizon(likely)
|
|
646
669
|
};
|
|
647
670
|
};
|
|
648
671
|
/**
|
|
@@ -654,6 +677,40 @@ const readDeliveryList = (value) => {
|
|
|
654
677
|
const items = value.map(readDeliveryListItem);
|
|
655
678
|
return items.every((item) => item !== null) ? items : null;
|
|
656
679
|
};
|
|
680
|
+
const doneWorkOf = (value) => {
|
|
681
|
+
if (typeof value.doneWork === "number") return value.doneWork;
|
|
682
|
+
return typeof value.totalWork === "number" && typeof value.remainingWork === "number" ? value.totalWork - value.remainingWork : void 0;
|
|
683
|
+
};
|
|
684
|
+
/** One archived Delivery, or null when it comes without its id, name, dates or work. */
|
|
685
|
+
const readArchivedDeliveryItem = (value) => {
|
|
686
|
+
if (!isRecord(value) || typeof value.id !== "number" || typeof value.totalWork !== "number") return null;
|
|
687
|
+
const name = textOf(value.name);
|
|
688
|
+
const date = textOf(value.date);
|
|
689
|
+
const archivedOn = textOf(value.archivedOn);
|
|
690
|
+
const doneWork = doneWorkOf(value);
|
|
691
|
+
if (name === void 0 || date === void 0 || archivedOn === void 0 || doneWork === void 0) return null;
|
|
692
|
+
return {
|
|
693
|
+
id: value.id,
|
|
694
|
+
name,
|
|
695
|
+
date,
|
|
696
|
+
archivedOn,
|
|
697
|
+
totalWork: value.totalWork,
|
|
698
|
+
doneWork,
|
|
699
|
+
likelihood: typeof value.likelihoodPercentage === "number" ? value.likelihoodPercentage : null,
|
|
700
|
+
cannotBeForecast: teamsWithoutForecastIn(value),
|
|
701
|
+
hasSufficientData: flagOf(value.hasSufficientData)
|
|
702
|
+
};
|
|
703
|
+
};
|
|
704
|
+
/** A Portfolio's active and archived Deliveries, or null when either list or any row in it cannot be read. */
|
|
705
|
+
const readPortfolioDeliveries = (value) => {
|
|
706
|
+
if (!isRecord(value) || !Array.isArray(value.archived)) return null;
|
|
707
|
+
const active = readDeliveryList(value.active);
|
|
708
|
+
const archived = value.archived.map(readArchivedDeliveryItem);
|
|
709
|
+
return active !== null && archived.every((item) => item !== null) ? {
|
|
710
|
+
active,
|
|
711
|
+
archived
|
|
712
|
+
} : null;
|
|
713
|
+
};
|
|
657
714
|
/** "Ocean Explorer · Deliveries", or the Portfolio by its id when its name could not be read. */
|
|
658
715
|
const describeDeliveryListTitle = (owner, terms) => {
|
|
659
716
|
return `${owner.name === void 0 ? `${terms.portfolio} [id: ${owner.id}]` : owner.name} · ${terms.deliveries}`;
|
|
@@ -692,8 +749,38 @@ const describeDeliveryRow = (delivery, terms) => [
|
|
|
692
749
|
delivery.featureCount === void 0 ? "—" : String(delivery.featureCount),
|
|
693
750
|
describeDeliveryDone(delivery, terms),
|
|
694
751
|
describeDeliveryLikelihood(delivery),
|
|
695
|
-
delivery.likelyBy === void 0 ? "—" :
|
|
752
|
+
delivery.likelyBy === void 0 ? "—" : describePercentileDay(delivery.likelyBy, delivery.likelyByBeyondHorizonYears)
|
|
753
|
+
];
|
|
754
|
+
/** What heads the archived Deliveries, below the active ones: "Archived Deliveries". */
|
|
755
|
+
const describeArchivedDeliveriesTitle = (terms) => `Archived ${terms.deliveries}`;
|
|
756
|
+
/** The archived table's column headings: when it was due, when it closed, and what it reached. */
|
|
757
|
+
const describeArchivedDeliveryHeadings = (terms) => [
|
|
758
|
+
"Name",
|
|
759
|
+
`${terms.delivery} Date`,
|
|
760
|
+
"Archived On",
|
|
761
|
+
"Done",
|
|
762
|
+
"Likelihood"
|
|
696
763
|
];
|
|
764
|
+
/** One archived Delivery as a row of its table, in the order of its headings. */
|
|
765
|
+
const describeArchivedDeliveryRow = (delivery, terms) => {
|
|
766
|
+
const remainingWork = delivery.totalWork - delivery.doneWork;
|
|
767
|
+
return [
|
|
768
|
+
describeOwnerName(delivery),
|
|
769
|
+
dayOf(delivery.date),
|
|
770
|
+
dayOf(delivery.archivedOn),
|
|
771
|
+
describeDeliveryDone({
|
|
772
|
+
totalWork: delivery.totalWork,
|
|
773
|
+
remainingWork
|
|
774
|
+
}, terms),
|
|
775
|
+
likelihoodAnswer({
|
|
776
|
+
likelihood: delivery.likelihood,
|
|
777
|
+
cannotBeForecast: delivery.cannotBeForecast,
|
|
778
|
+
hasRemainingWork: remainingWork > 0,
|
|
779
|
+
hasSufficientData: delivery.hasSufficientData,
|
|
780
|
+
precision: "round"
|
|
781
|
+
})
|
|
782
|
+
];
|
|
783
|
+
};
|
|
697
784
|
const isNullableNumber = (value) => value === null || typeof value === "number";
|
|
698
785
|
const isFeatureMetric = (value) => isRecord(value) && typeof value.referenceId === "string" && typeof value.name === "string" && typeof value.completion === "number" && isNullableNumber(value.likelihood);
|
|
699
786
|
const isChance = (value) => isRecord(value) && typeof value.probability === "number" && textOf(value.expectedDate) !== void 0;
|
|
@@ -765,18 +852,23 @@ const describeDeliveryFeatureRow = (feature) => [
|
|
|
765
852
|
];
|
|
766
853
|
/** The forecast distribution's column headings. */
|
|
767
854
|
const describeDeliveryChanceHeadings = () => ["Chance", "Done by"];
|
|
768
|
-
/** One chance of the day's forecast: "85%" and the day it is that likely to be done by. */
|
|
769
|
-
const describeDeliveryChanceRow = (chance) => [`${chance.probability}%`,
|
|
855
|
+
/** One chance of the day's forecast: "85%" and the day it is that likely to be done by, or "More than 5 years". */
|
|
856
|
+
const describeDeliveryChanceRow = (chance) => [`${chance.probability}%`, describePercentileDate(chance)];
|
|
770
857
|
//#endregion
|
|
771
858
|
//#region src/forecastWording.ts
|
|
772
|
-
const optionalBoolean = (value) => {
|
|
859
|
+
const optionalBoolean$1 = (value) => {
|
|
773
860
|
if (value === void 0 || typeof value === "boolean") return value;
|
|
774
861
|
return null;
|
|
775
862
|
};
|
|
776
|
-
const readChanceByDay = (value) =>
|
|
777
|
-
probability
|
|
778
|
-
|
|
779
|
-
|
|
863
|
+
const readChanceByDay = (value) => {
|
|
864
|
+
if (!isRecord(value) || !isNumber(value.probability) || !isDay(value.expectedDate)) return null;
|
|
865
|
+
return {
|
|
866
|
+
probability: value.probability,
|
|
867
|
+
expectedDate: value.expectedDate,
|
|
868
|
+
...typeof value.beyondHorizon === "boolean" ? { beyondHorizon: value.beyondHorizon } : {},
|
|
869
|
+
...isNumber(value.horizonYears) ? { horizonYears: value.horizonYears } : {}
|
|
870
|
+
};
|
|
871
|
+
};
|
|
780
872
|
const readChanceOfCount = (value) => isRecord(value) && isNumber(value.probability) && isNumber(value.value) ? {
|
|
781
873
|
probability: value.probability,
|
|
782
874
|
value: value.value
|
|
@@ -792,8 +884,8 @@ const readManualForecast = (value) => {
|
|
|
792
884
|
const { remainingItems, targetDate, likelihood } = value;
|
|
793
885
|
const whenForecasts = readEvery$1(value.whenForecasts, readChanceByDay);
|
|
794
886
|
const howManyForecasts = readEvery$1(value.howManyForecasts, readChanceOfCount);
|
|
795
|
-
const filterApplied = optionalBoolean(value.filterApplied);
|
|
796
|
-
const hasSufficientData = optionalBoolean(value.hasSufficientData);
|
|
887
|
+
const filterApplied = optionalBoolean$1(value.filterApplied);
|
|
888
|
+
const hasSufficientData = optionalBoolean$1(value.hasSufficientData);
|
|
797
889
|
if (!isNumber(remainingItems) || !(targetDate === null || isDay(targetDate)) || !(likelihood === null || isNumber(likelihood)) || whenForecasts === null || howManyForecasts === null || filterApplied === null || hasSufficientData === null) return null;
|
|
798
890
|
return {
|
|
799
891
|
remainingItems,
|
|
@@ -1080,13 +1172,28 @@ const readRunChart = (value, range) => {
|
|
|
1080
1172
|
const optionalText = (value) => isText(value) ? value : void 0;
|
|
1081
1173
|
const optionalNumber = (value) => isNumber(value) ? value : void 0;
|
|
1082
1174
|
const optionalDay = (value) => isDay(value) ? value : void 0;
|
|
1175
|
+
const optionalBoolean = (value) => typeof value === "boolean" ? value : void 0;
|
|
1176
|
+
const STALE_REASON_KINDS = [
|
|
1177
|
+
"TimeInState",
|
|
1178
|
+
"BlockedDuration",
|
|
1179
|
+
"TimeInStateWhileBlocked"
|
|
1180
|
+
];
|
|
1181
|
+
const isStaleReasonKind = (value) => STALE_REASON_KINDS.some((kind) => kind === value);
|
|
1182
|
+
const readStaleReason = (value) => isRecord(value) && isStaleReasonKind(value.kind) && isNumber(value.days) ? {
|
|
1183
|
+
kind: value.kind,
|
|
1184
|
+
days: value.days,
|
|
1185
|
+
stateName: optionalText(value.stateName)
|
|
1186
|
+
} : null;
|
|
1187
|
+
const optionalStaleReasons = (value) => Array.isArray(value) ? value.map(readStaleReason).filter((reason) => reason !== null) : void 0;
|
|
1083
1188
|
const readInProgressItem = (value) => isRecord(value) && (value.isBlocked === void 0 || typeof value.isBlocked === "boolean") ? {
|
|
1084
1189
|
isBlocked: value.isBlocked,
|
|
1085
1190
|
referenceId: optionalText(value.referenceId),
|
|
1086
1191
|
name: optionalText(value.name),
|
|
1087
1192
|
state: optionalText(value.state),
|
|
1088
1193
|
workItemAge: optionalNumber(value.workItemAge),
|
|
1089
|
-
blockedSince: optionalDay(value.blockedSince)
|
|
1194
|
+
blockedSince: optionalDay(value.blockedSince),
|
|
1195
|
+
isStale: optionalBoolean(value.isStale),
|
|
1196
|
+
staleReasons: optionalStaleReasons(value.staleReasons)
|
|
1090
1197
|
} : null;
|
|
1091
1198
|
const readInProgressNow = (value) => {
|
|
1092
1199
|
if (!isRecord(value) || !isDay(value.asOfDate) || !isNumber(value.count)) return null;
|
|
@@ -1285,6 +1392,7 @@ const metricsHeadlineLabel = (part, scope, terms) => {
|
|
|
1285
1392
|
throughput: `Total ${terms.throughput}`,
|
|
1286
1393
|
arrivals: "Total Arrivals",
|
|
1287
1394
|
blocked: `${terms.blocked} ${counted.many}`,
|
|
1395
|
+
stale: `Stale ${counted.many}`,
|
|
1288
1396
|
totalWorkItemAge: `Total ${terms.workItemAge}`,
|
|
1289
1397
|
predictabilityScore: "Predictability Score",
|
|
1290
1398
|
cycleTimePercentiles: `${terms.cycleTime} percentiles`,
|
|
@@ -1328,27 +1436,31 @@ const describeInProgressNow = (now, scope, terms, systemWipLimit) => ({
|
|
|
1328
1436
|
value: String(now.count),
|
|
1329
1437
|
detail: systemWipLimit === void 0 ? "" : wipLimitOf(systemWipLimit, scope, terms)
|
|
1330
1438
|
});
|
|
1439
|
+
const blockedFlag = (item) => item.isBlocked;
|
|
1440
|
+
const staleFlag = (item) => item.isStale;
|
|
1441
|
+
const saysWhichAre = (now, flag) => now.items.some((item) => flag(item) !== void 0);
|
|
1442
|
+
const countFlaggedNow = (part, flag, now, scope, terms) => saysWhichAre(now, flag) ? {
|
|
1443
|
+
label: metricsHeadlineLabel(part, scope, terms),
|
|
1444
|
+
value: String(now.items.filter((item) => flag(item) === true).length),
|
|
1445
|
+
detail: ""
|
|
1446
|
+
} : null;
|
|
1331
1447
|
/** "Blocked Work Items 2", or null when Lighthouse does not say which items are blocked. */
|
|
1332
|
-
const describeBlockedNow = (now, scope, terms) =>
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
return {
|
|
1336
|
-
label: metricsHeadlineLabel("blocked", scope, terms),
|
|
1337
|
-
value: String(blocked),
|
|
1338
|
-
detail: ""
|
|
1339
|
-
};
|
|
1340
|
-
};
|
|
1448
|
+
const describeBlockedNow = (now, scope, terms) => countFlaggedNow("blocked", blockedFlag, now, scope, terms);
|
|
1449
|
+
/** "Stale Work Items 2", or null when Lighthouse does not say which items are stale. */
|
|
1450
|
+
const describeStaleNow = (now, scope, terms) => countFlaggedNow("stale", staleFlag, now, scope, terms);
|
|
1341
1451
|
/**
|
|
1342
1452
|
* The sentences that stand in for what a WIP answer cannot show: no System WIP Limit, a Lighthouse that does
|
|
1343
|
-
* not say which Work Items are Blocked (which is not the same as none being
|
|
1344
|
-
* A limit of null means the Team or Portfolio could not be read; it may well have one, so nothing
|
|
1453
|
+
* not say which Work Items are Blocked or Stale (which is not the same as none being so), and nothing in
|
|
1454
|
+
* progress. A limit of null means the Team or Portfolio could not be read; it may well have one, so nothing
|
|
1455
|
+
* is said.
|
|
1345
1456
|
*/
|
|
1346
1457
|
const describeWhatWipLeavesUnsaid = (now, scope, terms, systemWipLimit) => {
|
|
1347
1458
|
const counted = countedOf(scope, terms);
|
|
1348
|
-
const
|
|
1459
|
+
const silentOn = (flag) => now.items.length > 0 && !saysWhichAre(now, flag);
|
|
1349
1460
|
return [
|
|
1350
1461
|
...systemWipLimit === void 0 ? [`No System ${terms.wip} Limit is set.`] : [],
|
|
1351
|
-
...
|
|
1462
|
+
...silentOn(blockedFlag) ? [`Lighthouse does not say which ${counted.many} are ${terms.blocked}.`] : [],
|
|
1463
|
+
...silentOn(staleFlag) ? [`Lighthouse does not say which ${counted.many} are Stale.`] : [],
|
|
1352
1464
|
...now.items.length === 0 ? [`No ${counted.many} are in progress.`] : []
|
|
1353
1465
|
];
|
|
1354
1466
|
};
|
|
@@ -2795,6 +2907,16 @@ const pollCliAuthSession = async (endpointUrl, sessionId, dependencies) => {
|
|
|
2795
2907
|
return { status: "expired" };
|
|
2796
2908
|
}
|
|
2797
2909
|
};
|
|
2910
|
+
const toPortfolioDeliveries = (value) => {
|
|
2911
|
+
if (Array.isArray(value)) return {
|
|
2912
|
+
active: value,
|
|
2913
|
+
archived: []
|
|
2914
|
+
};
|
|
2915
|
+
return isObjectRecord(value) && Array.isArray(value.active) && Array.isArray(value.archived) ? {
|
|
2916
|
+
active: value.active,
|
|
2917
|
+
archived: value.archived
|
|
2918
|
+
} : null;
|
|
2919
|
+
};
|
|
2798
2920
|
const getDefaultMetricsDateRange = () => {
|
|
2799
2921
|
const end = /* @__PURE__ */ new Date();
|
|
2800
2922
|
const start = /* @__PURE__ */ new Date();
|
|
@@ -3083,7 +3205,8 @@ const FEATURE_REQUIRES_SERVER_NEWER_THAN = {
|
|
|
3083
3205
|
deliveryMetricsHistory: "v26.5.29.5",
|
|
3084
3206
|
sleRisk: "v26.9.19.10",
|
|
3085
3207
|
teamRefinement: "v26.10.3.6",
|
|
3086
|
-
refinementVotes: "v26.10.3.6"
|
|
3208
|
+
refinementVotes: "v26.10.3.6",
|
|
3209
|
+
staleness: "v26.10.16.6"
|
|
3087
3210
|
};
|
|
3088
3211
|
/**
|
|
3089
3212
|
* Parses a Lighthouse version string ("v26.5.24.10", "26.5.24") into numeric
|
|
@@ -3430,7 +3553,18 @@ const createLighthouseClient = (configuration, dependencies = {}) => {
|
|
|
3430
3553
|
return requestJson(configuration, dependencies, `/v1/features/references?${queryString}`, { method: "GET" });
|
|
3431
3554
|
},
|
|
3432
3555
|
getFeatureWorkItems: async (featureId) => requestJson(configuration, dependencies, `/v1/features/${featureId}/workitems`, { method: "GET" }),
|
|
3433
|
-
listDeliveries: async (portfolioId) =>
|
|
3556
|
+
listDeliveries: async (portfolioId) => {
|
|
3557
|
+
const result = await requestJson(configuration, dependencies, `/v1/deliveries/portfolio/${portfolioId}`, { method: "GET" });
|
|
3558
|
+
if (!result.ok) return result;
|
|
3559
|
+
const deliveries = toPortfolioDeliveries(result.value);
|
|
3560
|
+
return deliveries === null ? getErrorResult({
|
|
3561
|
+
category: "unexpected",
|
|
3562
|
+
reason: "Lighthouse's list of Deliveries is not readable."
|
|
3563
|
+
}) : {
|
|
3564
|
+
ok: true,
|
|
3565
|
+
value: deliveries
|
|
3566
|
+
};
|
|
3567
|
+
},
|
|
3434
3568
|
createDelivery: async (portfolioId, payload) => requestJson(configuration, dependencies, `/v1/deliveries/portfolio/${portfolioId}`, {
|
|
3435
3569
|
method: "POST",
|
|
3436
3570
|
body: payload
|
|
@@ -3529,4 +3663,4 @@ const usageDataCalls = (configuration, dependencies) => {
|
|
|
3529
3663
|
};
|
|
3530
3664
|
};
|
|
3531
3665
|
//#endregion
|
|
3532
|
-
export { BLACKOUT_RULE_LIST_HEADINGS, BLACKOUT_RULE_LIST_TITLE, CANNOT_FORECAST_SHORT, FEATURE_REQUIRES_SERVER_NEWER_THAN, INSUFFICIENT_FORECAST_DATA_SENTENCE, INSUFFICIENT_FORECAST_DATA_SHORT, LIGHTHOUSE_IS_REACHABLE, NOT_SENT, NOT_SET, NO_DATA_YET, OVERDUE_SHORT, OVER_TIME_EMPTY_SENTENCE, PREDICTABILITY_SCORE_EXPLANATION, REFINEMENT_ANSWERS, SECRET_NOT_SHOWN, SEEDED_TERMS, SLE_RISK_AT_RISK_FROM, STANDALONE_VOTER_KEY_SCOPE, UNKNOWN_SHAPE_NOTE, USAGE_DATA_BUDGET_MS, VOTER_KEY_HEADER, WORK_TRACKING_CONNECTION_LIST_HEADINGS, WORK_TRACKING_OPTION_HEADINGS, countNumberedRows, createFileUsageDataStore, createFileVoterKeyStore, createLighthouseAuthContext, createLighthouseClient, daysInRange, deliveryLikelihoodAnswer, describeAnswer, describeArrivalsDays, describeAsOfHeading, describeBacktestActual, describeBacktestPeriod, describeBacktestSummary, describeBlackoutRuleCount, describeBlackoutRuleSchedule, describeBlackoutRuleWriteConfirmation, describeBlockedDays, describeBlockedNow, describeBlockedOverTime, describeConnectionName, describeConnectionSummary, describeConnectionType, describeCycleTimeDays, describeDays, describeDeliveryChanceHeadings, describeDeliveryChanceRow, describeDeliveryCount, describeDeliveryDone, describeDeliveryFeatureHeadings, describeDeliveryFeatureRow, describeDeliveryLikelihood, describeDeliveryListHeadings, describeDeliveryListTitle, describeDeliveryMetricsHeading, describeDeliveryRow, describeFeatureCompletion, describeFeatureCount, describeFeatureListCount, describeFeatureListHeadings, describeFeatureProgress, describeFeatureRow, describeFeatureStart, describeFeatureTitle, describeFeatureWorkItemHeadings, describeFeatureWorkItemRow, describeFeatureWorkItemsHeading, describeHowManyTitle, describeInProgressNow, describeLastUpdated, describeManualForecastLikelihood, describeManualForecastSummary, describeMetricSummary, describeMetricsHeading, describeMissingCondition, describeNoBlackoutRules, describeNoDeliveries, describeNothingToTakeBack, describeOptionValue, describeOverTimeHeading, describeOwnerCount, describeOwnerListHeadings, describeOwnerListTitle, describeOwnerName, describeOwnerWriteConfirmation, describePercentileRows, describePercentilesOverTime, describePercentilesOverTimeDays, describePortfolioSummary, describePredictabilityScore, describePredictabilityScoreDays, describeProcessBehaviorChart, describeProcessBehaviorOverTime, describeProcessBehaviorOverTimeDays, describeReachable, describeReadiness, describeRecordedComment, describeRecordedDayHeadings, describeRecordedDayRow, describeRecordedDayTitle, describeRecordedVote, describeRefinementSummary, describeRefreshConfirmation, describeRefusedMetric, describeSleRiskNow, describeTags, describeTakenBack, describeTeamSummary, describeThroughputDays, describeTimeInState, describeTimeInStateContributorDays, describeTimeInStateDays, describeTotalArrivals, describeTotalThroughput, describeTotalWorkItemAge, describeTotalWorkItemAgeDays, describeUnknownMetric, describeVersion, describeVoteRefusal, describeVotes, describeWarnings, describeWhatWipLeavesUnsaid, describeWhenTitle, describeWipDays, describeWorkItemAgeDays, describeWorkItemAgePercentiles, describeWorkTrackingSystemCount, formatCalendarDay, formatLikelihood, formatTimestamp, getClientPackageContract, getDefaultMetricsDateRange, getStandaloneDiscoveryLockfilePath, getUsageDataStorePath, getVoterKeyScope, getVoterKeyStorePath, hideConnectionSecrets, isAPersonAtTheTerminal, isAtRiskOfMissingTheSle, isCalendarDay, isDoNotTrackSet, isMetricRefusal, isMissingItsCondition, isProcessBehaviorMetricType, isRefinementAnswer, isServerVersionNewerThan, keepVoterKey, latestRecordedDay, levelOf, likelihoodAnswer, loadStandaloneDiscoveryContract, metricsHeadlineLabel, mintVoterKey, myVoteOn, nameOrFallback, ordinalOf, parseStandaloneDiscoveryContract, placeActualAmongPercentiles, placeEnoughForLine, planUsageDataStep, pollCliAuthSession, processBehaviorChartTitle, queryServerAuthMode, readAnswerWording, readArrivals, readBacktest, readBlackoutRules, readBlocked, readCumulativeStateTime, readCycleTime, readCycleTimeDefinitionName, readCycleTimePercentiles, readDeliveryList, readDeliveryMetricsHistory, readFeatureList, readFeatureWording, readFeatureWorkItems, readInProgressItems, readManualForecast, readMetricAnswer, readMetricsSubject, readNameOfMyVote, readOwnerList, readPercentilesOverTime, readPortfolio, readPredictabilityScore, readProcessBehaviorChart, readProcessBehaviorOverTime, readRefinementTerms, readRefinementWording, readRunChart, readServiceLevelExpectation, readSleRisk, readStoredUsageDataAnswer, readSystemWipLimit, readTeam, readTerms, readThroughput, readTimeInStateBar, readTimeInStateContributors, readTotalWorkItemAge, readUsageDataState, readVoteRefusal, readWip, readWorkItemAge, readWorkItemAgePercentiles, readWorkTrackingConnection, readWorkTrackingConnections, readWrittenBlackoutRule, readWrittenOwner, refinementDayVerdictOf, resolveTerms, settleUsageDataStep, sizingMomentOf, startCliAuthSession, summariseDeliveryMetricsHistory, switchUsageDataOn, timeInStateItemCount, usageDataStoreFor, validateLighthouseConnectivity, voterKeyStoreFor, withdrawUsageData };
|
|
3666
|
+
export { BLACKOUT_RULE_LIST_HEADINGS, BLACKOUT_RULE_LIST_TITLE, CANNOT_FORECAST_SHORT, FEATURE_REQUIRES_SERVER_NEWER_THAN, INSUFFICIENT_FORECAST_DATA_SENTENCE, INSUFFICIENT_FORECAST_DATA_SHORT, LIGHTHOUSE_IS_REACHABLE, NOT_SENT, NOT_SET, NO_DATA_YET, OVERDUE_SHORT, OVER_TIME_EMPTY_SENTENCE, PREDICTABILITY_SCORE_EXPLANATION, REFINEMENT_ANSWERS, SECRET_NOT_SHOWN, SEEDED_TERMS, SLE_RISK_AT_RISK_FROM, STANDALONE_VOTER_KEY_SCOPE, UNKNOWN_SHAPE_NOTE, USAGE_DATA_BUDGET_MS, VOTER_KEY_HEADER, WORK_TRACKING_CONNECTION_LIST_HEADINGS, WORK_TRACKING_OPTION_HEADINGS, countNumberedRows, createFileUsageDataStore, createFileVoterKeyStore, createLighthouseAuthContext, createLighthouseClient, daysInRange, deliveryLikelihoodAnswer, describeAnswer, describeArchivedDeliveriesTitle, describeArchivedDeliveryHeadings, describeArchivedDeliveryRow, describeArrivalsDays, describeAsOfHeading, describeBacktestActual, describeBacktestPeriod, describeBacktestSummary, describeBlackoutRuleCount, describeBlackoutRuleSchedule, describeBlackoutRuleWriteConfirmation, describeBlockedDays, describeBlockedNow, describeBlockedOverTime, describeConnectionName, describeConnectionSummary, describeConnectionType, describeCycleTimeDays, describeDays, describeDeliveryChanceHeadings, describeDeliveryChanceRow, describeDeliveryCount, describeDeliveryDone, describeDeliveryFeatureHeadings, describeDeliveryFeatureRow, describeDeliveryLikelihood, describeDeliveryListHeadings, describeDeliveryListTitle, describeDeliveryMetricsHeading, describeDeliveryRow, describeFeatureCompletion, describeFeatureCount, describeFeatureListCount, describeFeatureListHeadings, describeFeatureProgress, describeFeatureRow, describeFeatureStart, describeFeatureTitle, describeFeatureWorkItemHeadings, describeFeatureWorkItemRow, describeFeatureWorkItemsHeading, describeHowManyTitle, describeInProgressNow, describeLastUpdated, describeManualForecastLikelihood, describeManualForecastSummary, describeMetricSummary, describeMetricsHeading, describeMissingCondition, describeNoBlackoutRules, describeNoDeliveries, describeNothingToTakeBack, describeOptionValue, describeOverTimeHeading, describeOwnerCount, describeOwnerListHeadings, describeOwnerListTitle, describeOwnerName, describeOwnerWriteConfirmation, describePercentileDate, describePercentileDay, describePercentileRows, describePercentilesOverTime, describePercentilesOverTimeDays, describePortfolioSummary, describePredictabilityScore, describePredictabilityScoreDays, describeProcessBehaviorChart, describeProcessBehaviorOverTime, describeProcessBehaviorOverTimeDays, describeReachable, describeReadiness, describeRecordedComment, describeRecordedDayHeadings, describeRecordedDayRow, describeRecordedDayTitle, describeRecordedVote, describeRefinementSummary, describeRefreshConfirmation, describeRefusedMetric, describeSleRiskNow, describeStaleNow, describeTags, describeTakenBack, describeTeamSummary, describeThroughputDays, describeTimeInState, describeTimeInStateContributorDays, describeTimeInStateDays, describeTotalArrivals, describeTotalThroughput, describeTotalWorkItemAge, describeTotalWorkItemAgeDays, describeUnknownMetric, describeVersion, describeVoteRefusal, describeVotes, describeWarnings, describeWhatWipLeavesUnsaid, describeWhenTitle, describeWipDays, describeWorkItemAgeDays, describeWorkItemAgePercentiles, describeWorkTrackingSystemCount, formatCalendarDay, formatLikelihood, formatTimestamp, getClientPackageContract, getDefaultMetricsDateRange, getStandaloneDiscoveryLockfilePath, getUsageDataStorePath, getVoterKeyScope, getVoterKeyStorePath, hideConnectionSecrets, isAPersonAtTheTerminal, isAtRiskOfMissingTheSle, isCalendarDay, isDoNotTrackSet, isMetricRefusal, isMissingItsCondition, isProcessBehaviorMetricType, isRefinementAnswer, isServerVersionNewerThan, keepVoterKey, latestRecordedDay, levelOf, likelihoodAnswer, loadStandaloneDiscoveryContract, metricsHeadlineLabel, mintVoterKey, moreThanYearsText, myVoteOn, nameOrFallback, ordinalOf, parseStandaloneDiscoveryContract, placeActualAmongPercentiles, placeEnoughForLine, planUsageDataStep, pollCliAuthSession, processBehaviorChartTitle, queryServerAuthMode, readAnswerWording, readArchivedDeliveryItem, readArrivals, readBacktest, readBlackoutRules, readBlocked, readCumulativeStateTime, readCycleTime, readCycleTimeDefinitionName, readCycleTimePercentiles, readDeliveryList, readDeliveryMetricsHistory, readFeatureList, readFeatureWording, readFeatureWorkItems, readInProgressItems, readManualForecast, readMetricAnswer, readMetricsSubject, readNameOfMyVote, readOwnerList, readPercentilesOverTime, readPortfolio, readPortfolioDeliveries, readPredictabilityScore, readProcessBehaviorChart, readProcessBehaviorOverTime, readRefinementTerms, readRefinementWording, readRunChart, readServiceLevelExpectation, readSleRisk, readStoredUsageDataAnswer, readSystemWipLimit, readTeam, readTerms, readThroughput, readTimeInStateBar, readTimeInStateContributors, readTotalWorkItemAge, readUsageDataState, readVoteRefusal, readWip, readWorkItemAge, readWorkItemAgePercentiles, readWorkTrackingConnection, readWorkTrackingConnections, readWrittenBlackoutRule, readWrittenOwner, refinementDayVerdictOf, resolveTerms, settleUsageDataStep, sizingMomentOf, startCliAuthSession, summariseDeliveryMetricsHistory, switchUsageDataOn, timeInStateItemCount, usageDataStoreFor, validateLighthouseConnectivity, voterKeyStoreFor, withdrawUsageData, yearsBeyondHorizon };
|