@letpeoplework/lighthouse-client 1.10.0 → 1.12.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 +228 -34
- package/dist/index.d.cts +158 -11
- package/dist/index.d.ts +158 -11
- package/dist/index.js +211 -35
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -36,6 +36,20 @@ const PROCESS_BEHAVIOR_CHART_ROUTES = {
|
|
|
36
36
|
const isProcessBehaviorMetricType = (value) => Object.hasOwn(PROCESS_BEHAVIOR_CHART_ROUTES, value);
|
|
37
37
|
//#endregion
|
|
38
38
|
//#region src/usageData.ts
|
|
39
|
+
const reportTemplateWeDisclose = { "then-and-now": "ThenAndNow" };
|
|
40
|
+
/**
|
|
41
|
+
* The opening of a report Lighthouse sent: its type and nothing else about it. A refused read, or a report of a
|
|
42
|
+
* type this version does not know, counts nothing.
|
|
43
|
+
*/
|
|
44
|
+
const reportOpenedOccurrencesOf = (answered) => {
|
|
45
|
+
if (!answered.ok || !isRecord$1(answered.value)) return [];
|
|
46
|
+
const { templateKey } = answered.value;
|
|
47
|
+
const reportTemplate = Object.entries(reportTemplateWeDisclose).find(([key]) => key === templateKey)?.[1];
|
|
48
|
+
return reportTemplate === void 0 ? [] : [{
|
|
49
|
+
name: "ReportOpened",
|
|
50
|
+
reportTemplate
|
|
51
|
+
}];
|
|
52
|
+
};
|
|
39
53
|
/**
|
|
40
54
|
* When a vote was cast, from Lighthouse's answer rather than this machine's clock: Lighthouse counts days in
|
|
41
55
|
* the instance's time zone and knows which cadence days are blacked out. The web counts it the same way.
|
|
@@ -241,13 +255,26 @@ const textOf = (value) => typeof value === "string" && value.length > 0 ? value
|
|
|
241
255
|
const isDay = (value) => isText(value) && formatCalendarDay(value) !== null;
|
|
242
256
|
/** The calendar day as a person reads it, or the text exactly as sent when it is not one. */
|
|
243
257
|
const dayOf = (wire) => formatCalendarDay(wire) ?? wire;
|
|
244
|
-
/** The
|
|
245
|
-
const
|
|
258
|
+
/** The chance a list gives for one probability, or undefined when it holds none for it. */
|
|
259
|
+
const chanceAt = (chances, probability) => {
|
|
246
260
|
if (!Array.isArray(chances)) return;
|
|
247
261
|
const chance = chances.find((entry) => isRecord(entry) && entry.probability === probability);
|
|
248
|
-
return isRecord(chance) ?
|
|
262
|
+
return isRecord(chance) ? chance : void 0;
|
|
249
263
|
};
|
|
250
264
|
//#endregion
|
|
265
|
+
//#region src/forecastPercentileText.ts
|
|
266
|
+
/**
|
|
267
|
+
* The years of the horizon a percentile lies beyond, or undefined when its date is the forecast. Keyed on
|
|
268
|
+
* the flag itself, never on the server's version: an older Lighthouse never sends it.
|
|
269
|
+
*/
|
|
270
|
+
const yearsBeyondHorizon = (percentile) => isRecord(percentile) && percentile.beyondHorizon === true && isNumber(percentile.horizonYears) ? percentile.horizonYears : void 0;
|
|
271
|
+
/** The words shown in place of a date for a percentile too few simulated runs reached. */
|
|
272
|
+
const moreThanYearsText = (horizonYears) => `More than ${horizonYears} years`;
|
|
273
|
+
/** A percentile's day as a person reads it, or "More than 5 years" when it lies beyond that horizon. */
|
|
274
|
+
const describePercentileDay = (expectedDate, horizonYearsBeyond) => horizonYearsBeyond === void 0 ? dayOf(expectedDate) : moreThanYearsText(horizonYearsBeyond);
|
|
275
|
+
/** One percentile as text: its day, or the words when it lies beyond the horizon. */
|
|
276
|
+
const describePercentileDate = (percentile) => describePercentileDay(percentile.expectedDate, yearsBeyondHorizon(percentile));
|
|
277
|
+
//#endregion
|
|
251
278
|
//#region src/ownerWording.ts
|
|
252
279
|
/** A mark for a cell Lighthouse sent nothing for. */
|
|
253
280
|
const NOT_SENT = "—";
|
|
@@ -407,9 +434,11 @@ const startOf = (value) => {
|
|
|
407
434
|
observedOn: void 0,
|
|
408
435
|
likelyBy: void 0
|
|
409
436
|
};
|
|
437
|
+
const chance = chanceAt(value.percentiles, LISTED_CHANCE$1);
|
|
410
438
|
return {
|
|
411
439
|
observedOn: value.source === "Observed" ? textOf(value.observedDate) : void 0,
|
|
412
|
-
likelyBy:
|
|
440
|
+
likelyBy: textOf(chance?.expectedDate),
|
|
441
|
+
likelyByBeyondHorizonYears: yearsBeyondHorizon(chance)
|
|
413
442
|
};
|
|
414
443
|
};
|
|
415
444
|
const readFeatureListItem = (value) => {
|
|
@@ -419,6 +448,7 @@ const readFeatureListItem = (value) => {
|
|
|
419
448
|
const state = textOf(value.state);
|
|
420
449
|
const totalWork = workOf(value.totalWork);
|
|
421
450
|
const remainingWork = workOf(value.remainingWork);
|
|
451
|
+
const completion = chanceAt(value.forecasts, LISTED_CHANCE$1);
|
|
422
452
|
if (referenceId === void 0 || name === void 0 || state === void 0 || totalWork === null || remainingWork === null) return null;
|
|
423
453
|
return {
|
|
424
454
|
referenceId,
|
|
@@ -428,7 +458,8 @@ const readFeatureListItem = (value) => {
|
|
|
428
458
|
remainingWork,
|
|
429
459
|
cannotBeForecast: Array.isArray(value.teamsWithoutForecast) && value.teamsWithoutForecast.length > 0,
|
|
430
460
|
start: startOf(value.startForecast),
|
|
431
|
-
likelyBy:
|
|
461
|
+
likelyBy: textOf(completion?.expectedDate),
|
|
462
|
+
likelyByBeyondHorizonYears: yearsBeyondHorizon(completion)
|
|
432
463
|
};
|
|
433
464
|
};
|
|
434
465
|
/**
|
|
@@ -464,12 +495,15 @@ const describeFeatureProgress = (feature, terms) => `${feature.totalWork - featu
|
|
|
464
495
|
const describeFeatureStart = (feature) => {
|
|
465
496
|
if (feature.start.observedOn !== void 0) return dayOf(feature.start.observedOn);
|
|
466
497
|
if (feature.cannotBeForecast) return CANNOT_FORECAST_SHORT;
|
|
467
|
-
return feature.start.likelyBy === void 0 ? "—" :
|
|
498
|
+
return feature.start.likelyBy === void 0 ? "—" : describePercentileDay(feature.start.likelyBy, feature.start.likelyByBeyondHorizonYears);
|
|
468
499
|
};
|
|
469
|
-
/**
|
|
500
|
+
/**
|
|
501
|
+
* The day the Feature is 85% likely to be done by, "More than 5 years" when that lies beyond the simulation
|
|
502
|
+
* horizon, "Cannot forecast", or the mark when none was sent.
|
|
503
|
+
*/
|
|
470
504
|
const describeFeatureCompletion = (feature) => {
|
|
471
505
|
if (feature.cannotBeForecast) return CANNOT_FORECAST_SHORT;
|
|
472
|
-
return feature.likelyBy === void 0 ? "—" :
|
|
506
|
+
return feature.likelyBy === void 0 ? "—" : describePercentileDay(feature.likelyBy, feature.likelyByBeyondHorizonYears);
|
|
473
507
|
};
|
|
474
508
|
/** One Feature as a row of the list, in the order of its headings. */
|
|
475
509
|
const describeFeatureRow = (feature, terms) => [
|
|
@@ -632,6 +666,7 @@ const readDeliveryListItem = (value) => {
|
|
|
632
666
|
const name = textOf(value.name);
|
|
633
667
|
const date = textOf(value.date);
|
|
634
668
|
if (name === void 0 || date === void 0) return null;
|
|
669
|
+
const likely = chanceAt(value.completionDates, LISTED_CHANCE);
|
|
635
670
|
return {
|
|
636
671
|
id: value.id,
|
|
637
672
|
name,
|
|
@@ -643,7 +678,8 @@ const readDeliveryListItem = (value) => {
|
|
|
643
678
|
cannotBeForecast: teamsWithoutForecastIn(value),
|
|
644
679
|
hasSufficientData: flagOf(value.hasSufficientData),
|
|
645
680
|
isOverdue: flagOf(value.isOverdue),
|
|
646
|
-
likelyBy:
|
|
681
|
+
likelyBy: textOf(likely?.expectedDate),
|
|
682
|
+
likelyByBeyondHorizonYears: yearsBeyondHorizon(likely)
|
|
647
683
|
};
|
|
648
684
|
};
|
|
649
685
|
/**
|
|
@@ -727,7 +763,7 @@ const describeDeliveryRow = (delivery, terms) => [
|
|
|
727
763
|
delivery.featureCount === void 0 ? "—" : String(delivery.featureCount),
|
|
728
764
|
describeDeliveryDone(delivery, terms),
|
|
729
765
|
describeDeliveryLikelihood(delivery),
|
|
730
|
-
delivery.likelyBy === void 0 ? "—" :
|
|
766
|
+
delivery.likelyBy === void 0 ? "—" : describePercentileDay(delivery.likelyBy, delivery.likelyByBeyondHorizonYears)
|
|
731
767
|
];
|
|
732
768
|
/** What heads the archived Deliveries, below the active ones: "Archived Deliveries". */
|
|
733
769
|
const describeArchivedDeliveriesTitle = (terms) => `Archived ${terms.deliveries}`;
|
|
@@ -830,18 +866,23 @@ const describeDeliveryFeatureRow = (feature) => [
|
|
|
830
866
|
];
|
|
831
867
|
/** The forecast distribution's column headings. */
|
|
832
868
|
const describeDeliveryChanceHeadings = () => ["Chance", "Done by"];
|
|
833
|
-
/** One chance of the day's forecast: "85%" and the day it is that likely to be done by. */
|
|
834
|
-
const describeDeliveryChanceRow = (chance) => [`${chance.probability}%`,
|
|
869
|
+
/** One chance of the day's forecast: "85%" and the day it is that likely to be done by, or "More than 5 years". */
|
|
870
|
+
const describeDeliveryChanceRow = (chance) => [`${chance.probability}%`, describePercentileDate(chance)];
|
|
835
871
|
//#endregion
|
|
836
872
|
//#region src/forecastWording.ts
|
|
837
|
-
const optionalBoolean = (value) => {
|
|
873
|
+
const optionalBoolean$1 = (value) => {
|
|
838
874
|
if (value === void 0 || typeof value === "boolean") return value;
|
|
839
875
|
return null;
|
|
840
876
|
};
|
|
841
|
-
const readChanceByDay = (value) =>
|
|
842
|
-
probability
|
|
843
|
-
|
|
844
|
-
|
|
877
|
+
const readChanceByDay = (value) => {
|
|
878
|
+
if (!isRecord(value) || !isNumber(value.probability) || !isDay(value.expectedDate)) return null;
|
|
879
|
+
return {
|
|
880
|
+
probability: value.probability,
|
|
881
|
+
expectedDate: value.expectedDate,
|
|
882
|
+
...typeof value.beyondHorizon === "boolean" ? { beyondHorizon: value.beyondHorizon } : {},
|
|
883
|
+
...isNumber(value.horizonYears) ? { horizonYears: value.horizonYears } : {}
|
|
884
|
+
};
|
|
885
|
+
};
|
|
845
886
|
const readChanceOfCount = (value) => isRecord(value) && isNumber(value.probability) && isNumber(value.value) ? {
|
|
846
887
|
probability: value.probability,
|
|
847
888
|
value: value.value
|
|
@@ -857,8 +898,8 @@ const readManualForecast = (value) => {
|
|
|
857
898
|
const { remainingItems, targetDate, likelihood } = value;
|
|
858
899
|
const whenForecasts = readEvery$1(value.whenForecasts, readChanceByDay);
|
|
859
900
|
const howManyForecasts = readEvery$1(value.howManyForecasts, readChanceOfCount);
|
|
860
|
-
const filterApplied = optionalBoolean(value.filterApplied);
|
|
861
|
-
const hasSufficientData = optionalBoolean(value.hasSufficientData);
|
|
901
|
+
const filterApplied = optionalBoolean$1(value.filterApplied);
|
|
902
|
+
const hasSufficientData = optionalBoolean$1(value.hasSufficientData);
|
|
862
903
|
if (!isNumber(remainingItems) || !(targetDate === null || isDay(targetDate)) || !(likelihood === null || isNumber(likelihood)) || whenForecasts === null || howManyForecasts === null || filterApplied === null || hasSufficientData === null) return null;
|
|
863
904
|
return {
|
|
864
905
|
remainingItems,
|
|
@@ -1145,13 +1186,28 @@ const readRunChart = (value, range) => {
|
|
|
1145
1186
|
const optionalText = (value) => isText(value) ? value : void 0;
|
|
1146
1187
|
const optionalNumber = (value) => isNumber(value) ? value : void 0;
|
|
1147
1188
|
const optionalDay = (value) => isDay(value) ? value : void 0;
|
|
1189
|
+
const optionalBoolean = (value) => typeof value === "boolean" ? value : void 0;
|
|
1190
|
+
const STALE_REASON_KINDS = [
|
|
1191
|
+
"TimeInState",
|
|
1192
|
+
"BlockedDuration",
|
|
1193
|
+
"TimeInStateWhileBlocked"
|
|
1194
|
+
];
|
|
1195
|
+
const isStaleReasonKind = (value) => STALE_REASON_KINDS.some((kind) => kind === value);
|
|
1196
|
+
const readStaleReason = (value) => isRecord(value) && isStaleReasonKind(value.kind) && isNumber(value.days) ? {
|
|
1197
|
+
kind: value.kind,
|
|
1198
|
+
days: value.days,
|
|
1199
|
+
stateName: optionalText(value.stateName)
|
|
1200
|
+
} : null;
|
|
1201
|
+
const optionalStaleReasons = (value) => Array.isArray(value) ? value.map(readStaleReason).filter((reason) => reason !== null) : void 0;
|
|
1148
1202
|
const readInProgressItem = (value) => isRecord(value) && (value.isBlocked === void 0 || typeof value.isBlocked === "boolean") ? {
|
|
1149
1203
|
isBlocked: value.isBlocked,
|
|
1150
1204
|
referenceId: optionalText(value.referenceId),
|
|
1151
1205
|
name: optionalText(value.name),
|
|
1152
1206
|
state: optionalText(value.state),
|
|
1153
1207
|
workItemAge: optionalNumber(value.workItemAge),
|
|
1154
|
-
blockedSince: optionalDay(value.blockedSince)
|
|
1208
|
+
blockedSince: optionalDay(value.blockedSince),
|
|
1209
|
+
isStale: optionalBoolean(value.isStale),
|
|
1210
|
+
staleReasons: optionalStaleReasons(value.staleReasons)
|
|
1155
1211
|
} : null;
|
|
1156
1212
|
const readInProgressNow = (value) => {
|
|
1157
1213
|
if (!isRecord(value) || !isDay(value.asOfDate) || !isNumber(value.count)) return null;
|
|
@@ -1350,6 +1406,7 @@ const metricsHeadlineLabel = (part, scope, terms) => {
|
|
|
1350
1406
|
throughput: `Total ${terms.throughput}`,
|
|
1351
1407
|
arrivals: "Total Arrivals",
|
|
1352
1408
|
blocked: `${terms.blocked} ${counted.many}`,
|
|
1409
|
+
stale: `Stale ${counted.many}`,
|
|
1353
1410
|
totalWorkItemAge: `Total ${terms.workItemAge}`,
|
|
1354
1411
|
predictabilityScore: "Predictability Score",
|
|
1355
1412
|
cycleTimePercentiles: `${terms.cycleTime} percentiles`,
|
|
@@ -1393,27 +1450,31 @@ const describeInProgressNow = (now, scope, terms, systemWipLimit) => ({
|
|
|
1393
1450
|
value: String(now.count),
|
|
1394
1451
|
detail: systemWipLimit === void 0 ? "" : wipLimitOf(systemWipLimit, scope, terms)
|
|
1395
1452
|
});
|
|
1453
|
+
const blockedFlag = (item) => item.isBlocked;
|
|
1454
|
+
const staleFlag = (item) => item.isStale;
|
|
1455
|
+
const saysWhichAre = (now, flag) => now.items.some((item) => flag(item) !== void 0);
|
|
1456
|
+
const countFlaggedNow = (part, flag, now, scope, terms) => saysWhichAre(now, flag) ? {
|
|
1457
|
+
label: metricsHeadlineLabel(part, scope, terms),
|
|
1458
|
+
value: String(now.items.filter((item) => flag(item) === true).length),
|
|
1459
|
+
detail: ""
|
|
1460
|
+
} : null;
|
|
1396
1461
|
/** "Blocked Work Items 2", or null when Lighthouse does not say which items are blocked. */
|
|
1397
|
-
const describeBlockedNow = (now, scope, terms) =>
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
return {
|
|
1401
|
-
label: metricsHeadlineLabel("blocked", scope, terms),
|
|
1402
|
-
value: String(blocked),
|
|
1403
|
-
detail: ""
|
|
1404
|
-
};
|
|
1405
|
-
};
|
|
1462
|
+
const describeBlockedNow = (now, scope, terms) => countFlaggedNow("blocked", blockedFlag, now, scope, terms);
|
|
1463
|
+
/** "Stale Work Items 2", or null when Lighthouse does not say which items are stale. */
|
|
1464
|
+
const describeStaleNow = (now, scope, terms) => countFlaggedNow("stale", staleFlag, now, scope, terms);
|
|
1406
1465
|
/**
|
|
1407
1466
|
* The sentences that stand in for what a WIP answer cannot show: no System WIP Limit, a Lighthouse that does
|
|
1408
|
-
* not say which Work Items are Blocked (which is not the same as none being
|
|
1409
|
-
* A limit of null means the Team or Portfolio could not be read; it may well have one, so nothing
|
|
1467
|
+
* not say which Work Items are Blocked or Stale (which is not the same as none being so), and nothing in
|
|
1468
|
+
* progress. A limit of null means the Team or Portfolio could not be read; it may well have one, so nothing
|
|
1469
|
+
* is said.
|
|
1410
1470
|
*/
|
|
1411
1471
|
const describeWhatWipLeavesUnsaid = (now, scope, terms, systemWipLimit) => {
|
|
1412
1472
|
const counted = countedOf(scope, terms);
|
|
1413
|
-
const
|
|
1473
|
+
const silentOn = (flag) => now.items.length > 0 && !saysWhichAre(now, flag);
|
|
1414
1474
|
return [
|
|
1415
1475
|
...systemWipLimit === void 0 ? [`No System ${terms.wip} Limit is set.`] : [],
|
|
1416
|
-
...
|
|
1476
|
+
...silentOn(blockedFlag) ? [`Lighthouse does not say which ${counted.many} are ${terms.blocked}.`] : [],
|
|
1477
|
+
...silentOn(staleFlag) ? [`Lighthouse does not say which ${counted.many} are Stale.`] : [],
|
|
1417
1478
|
...now.items.length === 0 ? [`No ${counted.many} are in progress.`] : []
|
|
1418
1479
|
];
|
|
1419
1480
|
};
|
|
@@ -2117,6 +2178,114 @@ const readNameOfMyVote = async (client, teamId, workItem, voterKey) => {
|
|
|
2117
2178
|
return log.ok ? nameOfMyVote(log.value) : null;
|
|
2118
2179
|
};
|
|
2119
2180
|
//#endregion
|
|
2181
|
+
//#region src/reportWording.ts
|
|
2182
|
+
const readWindow = (value) => isRecord(value) && isDay(value.start) && isDay(value.end) ? {
|
|
2183
|
+
start: value.start,
|
|
2184
|
+
end: value.end
|
|
2185
|
+
} : null;
|
|
2186
|
+
/** The report's name and windows, or null when the answer does not carry all three. */
|
|
2187
|
+
const readReport = (value) => {
|
|
2188
|
+
if (!isRecord(value) || !isRecord(value.thenAndNow)) return null;
|
|
2189
|
+
const name = textOf(value.name);
|
|
2190
|
+
const thenWindow = readWindow(value.thenAndNow.thenWindow);
|
|
2191
|
+
const nowWindow = readWindow(value.thenAndNow.nowWindow);
|
|
2192
|
+
if (name === void 0 || thenWindow === null || nowWindow === null) return null;
|
|
2193
|
+
return {
|
|
2194
|
+
name,
|
|
2195
|
+
thenWindow,
|
|
2196
|
+
nowWindow
|
|
2197
|
+
};
|
|
2198
|
+
};
|
|
2199
|
+
const readReportListItem = (value) => {
|
|
2200
|
+
if (!isRecord(value) || typeof value.id !== "number") return null;
|
|
2201
|
+
const name = textOf(value.name);
|
|
2202
|
+
if (name === void 0) return null;
|
|
2203
|
+
return {
|
|
2204
|
+
id: value.id,
|
|
2205
|
+
name,
|
|
2206
|
+
templateKey: textOf(value.templateKey),
|
|
2207
|
+
createdOn: textOf(value.createdOn)
|
|
2208
|
+
};
|
|
2209
|
+
};
|
|
2210
|
+
/**
|
|
2211
|
+
* Every report in the list, or null when the answer holds no list or any one report comes without its id or
|
|
2212
|
+
* name: a row that cannot say which report it is would misname the whole list.
|
|
2213
|
+
*/
|
|
2214
|
+
const readReportList = (value) => {
|
|
2215
|
+
if (!isRecord(value) || !Array.isArray(value.reports)) return null;
|
|
2216
|
+
const items = value.reports.map(readReportListItem);
|
|
2217
|
+
return items.every((item) => item !== null) ? items : null;
|
|
2218
|
+
};
|
|
2219
|
+
const ownerTerm$1 = (kind, terms) => kind === "team" ? terms.team : terms.portfolio;
|
|
2220
|
+
/** The owner as the instance names it, "Team Lightspeed", or by its id when its name could not be read. */
|
|
2221
|
+
const describeReportOwner = (kind, id, owner, terms) => {
|
|
2222
|
+
const term = ownerTerm$1(kind, terms);
|
|
2223
|
+
const name = isRecord(owner) ? textOf(owner.name) : void 0;
|
|
2224
|
+
return name === void 0 ? `${term} [id: ${id}]` : `${term} ${name}`;
|
|
2225
|
+
};
|
|
2226
|
+
const describeWindow = (label, window) => `${label} ${dayOf(window.start)} – ${dayOf(window.end)}`;
|
|
2227
|
+
/** The report's name, its owner and its two windows, one to a line. */
|
|
2228
|
+
const describeReportSummary = (report, owner) => [
|
|
2229
|
+
report.name,
|
|
2230
|
+
owner,
|
|
2231
|
+
`${describeWindow("Then", report.thenWindow)} · ${describeWindow("Now", report.nowWindow)}`
|
|
2232
|
+
].join("\n");
|
|
2233
|
+
const describeReportCount = (count) => {
|
|
2234
|
+
if (count === 0) return "No reports";
|
|
2235
|
+
return count === 1 ? "1 report" : `${count} reports`;
|
|
2236
|
+
};
|
|
2237
|
+
const describeReportListItem = (item) => [
|
|
2238
|
+
`${item.name} [id: ${item.id}]`,
|
|
2239
|
+
item.templateKey,
|
|
2240
|
+
item.createdOn === void 0 ? void 0 : `created ${dayOf(item.createdOn)}`
|
|
2241
|
+
].filter((part) => part !== void 0).join(" · ");
|
|
2242
|
+
/** How many reports the owner has, then each report's name, type and created day. */
|
|
2243
|
+
const describeReportListSummary = (reports, owner) => [`${owner} · ${describeReportCount(reports.length)}`, ...reports.map(describeReportListItem)].join("\n");
|
|
2244
|
+
const summariseReport = (value, owner) => {
|
|
2245
|
+
const report = readReport(value);
|
|
2246
|
+
return report === null ? null : describeReportSummary(report, owner);
|
|
2247
|
+
};
|
|
2248
|
+
const summariseReportList = (value, owner) => {
|
|
2249
|
+
const reports = readReportList(value);
|
|
2250
|
+
return reports === null ? null : describeReportListSummary(reports, owner);
|
|
2251
|
+
};
|
|
2252
|
+
const FORBIDDEN = 403;
|
|
2253
|
+
const NOT_FOUND = 404;
|
|
2254
|
+
const NOTHING_THERE = {
|
|
2255
|
+
list: (owner) => `There is no such ${owner}.`,
|
|
2256
|
+
report: (owner) => `There is no such report for that ${owner}.`
|
|
2257
|
+
};
|
|
2258
|
+
/**
|
|
2259
|
+
* Why a report or a list could not be read, in words the reader can act on: the web's sentence where it has
|
|
2260
|
+
* one. Any other refusal, the client's own "upgrade Lighthouse" among them, keeps its category and reason.
|
|
2261
|
+
*/
|
|
2262
|
+
const describeReportRefusal = (error, kind, read, terms) => {
|
|
2263
|
+
if (error.statusCode === FORBIDDEN) return `You have no access to that ${ownerTerm$1(kind, terms)}'s reports.`;
|
|
2264
|
+
if (error.problemCode === "template-not-supported") return "This report was made by a newer version of Lighthouse and can't be shown here.";
|
|
2265
|
+
if (error.statusCode === NOT_FOUND) return NOTHING_THERE[read](ownerTerm$1(kind, terms));
|
|
2266
|
+
return `${error.category}: ${error.reason}`;
|
|
2267
|
+
};
|
|
2268
|
+
/**
|
|
2269
|
+
* {@link describeReportRefusal} in the instance's own words. A refusal the client made before asking, as for a
|
|
2270
|
+
* Lighthouse too old for reports, asks that Lighthouse nothing more, not even its words.
|
|
2271
|
+
*/
|
|
2272
|
+
const readReportRefusal = async (source, error, kind, read) => describeReportRefusal(error, kind, read, error.statusCode === void 0 ? SEEDED_TERMS : await readTerms(source));
|
|
2273
|
+
//#endregion
|
|
2274
|
+
//#region src/reportReads.ts
|
|
2275
|
+
/** The owner's list of reports, exactly as Lighthouse answers it. */
|
|
2276
|
+
const readOwnersReports = (reads, owner) => owner.kind === "team" ? reads.getTeamReports(owner.id) : reads.getPortfolioReports(owner.id);
|
|
2277
|
+
/** One of the owner's reports, exactly as Lighthouse answers it. */
|
|
2278
|
+
const readOwnersReport = (reads, owner, reportId) => owner.kind === "team" ? reads.getTeamReport(owner.id, reportId) : reads.getPortfolioReport(owner.id, reportId);
|
|
2279
|
+
/**
|
|
2280
|
+
* {@link describeReportOwner} for an owner read from Lighthouse. Its name only labels a summary, so an owner that
|
|
2281
|
+
* cannot be read is named by its id instead, and this never fails.
|
|
2282
|
+
*/
|
|
2283
|
+
const readReportOwner = async (source, owner) => {
|
|
2284
|
+
const read = owner.kind === "team" ? source.getTeam(owner.id) : source.getPortfolio(owner.id);
|
|
2285
|
+
const [terms, named] = await Promise.all([readTerms(source), read.then((answer) => answer.ok ? answer.value : void 0, () => void 0)]);
|
|
2286
|
+
return describeReportOwner(owner.kind, owner.id, named, terms);
|
|
2287
|
+
};
|
|
2288
|
+
//#endregion
|
|
2120
2289
|
//#region src/usageDataReporter.ts
|
|
2121
2290
|
/** A command's own answer never waits on usage data for longer than this, whatever Lighthouse does. */
|
|
2122
2291
|
const USAGE_DATA_BUDGET_MS = 1e3;
|
|
@@ -3158,7 +3327,9 @@ const FEATURE_REQUIRES_SERVER_NEWER_THAN = {
|
|
|
3158
3327
|
deliveryMetricsHistory: "v26.5.29.5",
|
|
3159
3328
|
sleRisk: "v26.9.19.10",
|
|
3160
3329
|
teamRefinement: "v26.10.3.6",
|
|
3161
|
-
refinementVotes: "v26.10.3.6"
|
|
3330
|
+
refinementVotes: "v26.10.3.6",
|
|
3331
|
+
staleness: "v26.10.16.6",
|
|
3332
|
+
reports: "v26.10.10.1"
|
|
3162
3333
|
};
|
|
3163
3334
|
/**
|
|
3164
3335
|
* Parses a Lighthouse version string ("v26.5.24.10", "26.5.24") into numeric
|
|
@@ -3220,6 +3391,7 @@ const createLighthouseClient = (configuration, dependencies = {}) => {
|
|
|
3220
3391
|
}
|
|
3221
3392
|
};
|
|
3222
3393
|
};
|
|
3394
|
+
const readReports = async (route) => await ensureServerSupports("reports") ?? requestJson(configuration, dependencies, route, { method: "GET" });
|
|
3223
3395
|
return {
|
|
3224
3396
|
checkConnectivity: async () => {
|
|
3225
3397
|
const fetchDependency = getFetchDependency(dependencies);
|
|
@@ -3296,6 +3468,10 @@ const createLighthouseClient = (configuration, dependencies = {}) => {
|
|
|
3296
3468
|
headers: voterKeyHeaders(options?.voterKey)
|
|
3297
3469
|
});
|
|
3298
3470
|
},
|
|
3471
|
+
getTeamReports: async (teamId) => readReports(`/v1/teams/${teamId}/reports`),
|
|
3472
|
+
getTeamReport: async (teamId, reportId) => readReports(`/v1/teams/${teamId}/reports/${reportId}`),
|
|
3473
|
+
getPortfolioReports: async (portfolioId) => readReports(`/v1/portfolios/${portfolioId}/reports`),
|
|
3474
|
+
getPortfolioReport: async (portfolioId, reportId) => readReports(`/v1/portfolios/${portfolioId}/reports/${reportId}`),
|
|
3299
3475
|
getTerminology: async () => requestJson(configuration, dependencies, "/v1/terminology/all", { method: "GET" }),
|
|
3300
3476
|
listPortfolios: async () => requestJson(configuration, dependencies, "/v1/portfolios", { method: "GET" }),
|
|
3301
3477
|
getPortfolio: async (portfolioId) => requestJson(configuration, dependencies, `/v1/portfolios/${portfolioId}`, { method: "GET" }),
|
|
@@ -3615,4 +3791,4 @@ const usageDataCalls = (configuration, dependencies) => {
|
|
|
3615
3791
|
};
|
|
3616
3792
|
};
|
|
3617
3793
|
//#endregion
|
|
3618
|
-
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, 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, 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 };
|
|
3794
|
+
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, describeReportListSummary, describeReportOwner, describeReportRefusal, describeReportSummary, 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, readOwnersReport, readOwnersReports, readPercentilesOverTime, readPortfolio, readPortfolioDeliveries, readPredictabilityScore, readProcessBehaviorChart, readProcessBehaviorOverTime, readRefinementTerms, readRefinementWording, readReport, readReportList, readReportOwner, readReportRefusal, readRunChart, readServiceLevelExpectation, readSleRisk, readStoredUsageDataAnswer, readSystemWipLimit, readTeam, readTerms, readThroughput, readTimeInStateBar, readTimeInStateContributors, readTotalWorkItemAge, readUsageDataState, readVoteRefusal, readWip, readWorkItemAge, readWorkItemAgePercentiles, readWorkTrackingConnection, readWorkTrackingConnections, readWrittenBlackoutRule, readWrittenOwner, refinementDayVerdictOf, reportOpenedOccurrencesOf, resolveTerms, settleUsageDataStep, sizingMomentOf, startCliAuthSession, summariseDeliveryMetricsHistory, summariseReport, summariseReportList, switchUsageDataOn, timeInStateItemCount, usageDataStoreFor, validateLighthouseConnectivity, voterKeyStoreFor, withdrawUsageData, yearsBeyondHorizon };
|