@bakers-build/addon-bakers-ui 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -23,13 +23,20 @@ export interface StatisticFilter {
|
|
|
23
23
|
value: string;
|
|
24
24
|
options: StatisticFilterOption[];
|
|
25
25
|
}
|
|
26
|
+
declare const GROUPINGS: readonly ["day", "week", "month", "quarter"];
|
|
27
|
+
declare const WIDGETS: readonly ["matrix", "line", "grouped_horizontal_bars", "bars", "tiles", "flow", "table"];
|
|
26
28
|
export interface StatisticFigure {
|
|
27
29
|
id: string;
|
|
28
30
|
label: string;
|
|
29
31
|
description: string;
|
|
30
|
-
|
|
32
|
+
/** `tiles`, `flow`, `table` and `bars` render through the bars fallback. */
|
|
33
|
+
widget: (typeof WIDGETS)[number];
|
|
31
34
|
generated: string;
|
|
32
35
|
filters: Record<string, StatisticFilter>;
|
|
36
|
+
/** Bucket size of the selected period; absent on `windows` figures. */
|
|
37
|
+
period?: {
|
|
38
|
+
grouping: (typeof GROUPINGS)[number];
|
|
39
|
+
};
|
|
33
40
|
categories: StatisticCategory[];
|
|
34
41
|
measurements: StatisticMeasurement[];
|
|
35
42
|
empty: {
|
|
@@ -63,3 +70,4 @@ export declare function errorResultOf(caught: unknown): {
|
|
|
63
70
|
message: string;
|
|
64
71
|
};
|
|
65
72
|
export declare function loadGroupStatistics(client: DropshClient, contexts: StatisticsContexts, filters?: StatisticsFilters): Promise<GroupStatisticsResult>;
|
|
73
|
+
export {};
|
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
import { DrupalJsonApiParams } from 'drupal-jsonapi-params';
|
|
2
|
+
const GROUPINGS = ['day', 'week', 'month', 'quarter'];
|
|
3
|
+
const WIDGETS = [
|
|
4
|
+
'matrix',
|
|
5
|
+
'line',
|
|
6
|
+
'grouped_horizontal_bars',
|
|
7
|
+
'bars',
|
|
8
|
+
'tiles',
|
|
9
|
+
'flow',
|
|
10
|
+
'table',
|
|
11
|
+
];
|
|
2
12
|
function statusOf(caught) {
|
|
3
13
|
if (typeof caught !== 'object' || caught === null)
|
|
4
14
|
return undefined;
|
|
@@ -113,7 +123,7 @@ function figureOf(value) {
|
|
|
113
123
|
typeof row.id !== 'string' ||
|
|
114
124
|
typeof row.label !== 'string' ||
|
|
115
125
|
typeof row.description !== 'string' ||
|
|
116
|
-
!
|
|
126
|
+
!WIDGETS.includes(String(row.widget)) ||
|
|
117
127
|
typeof row.generated !== 'string' ||
|
|
118
128
|
!Array.isArray(row.categories) ||
|
|
119
129
|
!Array.isArray(row.measurements) ||
|
|
@@ -129,8 +139,14 @@ function figureOf(value) {
|
|
|
129
139
|
const measurements = row.measurements.map(measurementOf);
|
|
130
140
|
if (categories.includes(undefined) || measurements.includes(undefined))
|
|
131
141
|
return undefined;
|
|
142
|
+
const grouping = recordOf(row.period)?.grouping;
|
|
143
|
+
const period = GROUPINGS.find((item) => item === grouping);
|
|
132
144
|
const parsedFilters = {};
|
|
133
145
|
for (const [key, item] of Object.entries(filters)) {
|
|
146
|
+
// An entity filter (project, team, person) picks UUIDs in the web UI; the
|
|
147
|
+
// cockpit offers no picker for it, so it is left out, not refused.
|
|
148
|
+
if (recordOf(item)?.type === 'entities')
|
|
149
|
+
continue;
|
|
134
150
|
const parsed = filterOf(item);
|
|
135
151
|
if (!parsed)
|
|
136
152
|
return undefined;
|
|
@@ -143,6 +159,7 @@ function figureOf(value) {
|
|
|
143
159
|
widget: row.widget,
|
|
144
160
|
generated: row.generated,
|
|
145
161
|
filters: parsedFilters,
|
|
162
|
+
...(period ? { period: { grouping: period } } : {}),
|
|
146
163
|
categories: categories,
|
|
147
164
|
measurements: measurements,
|
|
148
165
|
empty: {
|
|
@@ -163,7 +180,10 @@ function groupOf(value) {
|
|
|
163
180
|
typeof row.label !== 'string' ||
|
|
164
181
|
!Array.isArray(row.figures))
|
|
165
182
|
return undefined;
|
|
166
|
-
|
|
183
|
+
// A figure whose widget the CLI cannot draw is skipped, not malformed.
|
|
184
|
+
const figures = row.figures
|
|
185
|
+
.filter((figure) => WIDGETS.includes(String(recordOf(figure)?.widget)))
|
|
186
|
+
.map(figureOf);
|
|
167
187
|
if (figures.includes(undefined))
|
|
168
188
|
return undefined;
|
|
169
189
|
return {
|
|
@@ -193,5 +213,8 @@ export async function loadGroupStatistics(client, contexts, filters = {}) {
|
|
|
193
213
|
const groups = source.map(groupOf);
|
|
194
214
|
if (groups.includes(undefined))
|
|
195
215
|
return { kind: 'error', message: 'malformed statistics document' };
|
|
196
|
-
return {
|
|
216
|
+
return {
|
|
217
|
+
kind: 'ok',
|
|
218
|
+
groups: groups.filter((group) => group.figures.length > 0),
|
|
219
|
+
};
|
|
197
220
|
}
|
|
@@ -50,11 +50,11 @@ function matrixDisplay(id, figure, width) {
|
|
|
50
50
|
});
|
|
51
51
|
}
|
|
52
52
|
function partialPeriodUnit(figure) {
|
|
53
|
-
return figure.
|
|
53
|
+
return figure.period?.grouping ?? 'day';
|
|
54
54
|
}
|
|
55
55
|
// Shared above every widget: which trailing period is still filling in (the
|
|
56
56
|
// figure's own categories carry the `partial` flag — see
|
|
57
|
-
// MeasurementEvaluator::
|
|
57
|
+
// MeasurementEvaluator::buckets()) and what the figure means, in the
|
|
58
58
|
// figure's own words. Rendered once here rather than per-widget so every
|
|
59
59
|
// shipped widget (matrix, grouped_horizontal_bars) gets both without having
|
|
60
60
|
// to know about them.
|
|
@@ -20,14 +20,9 @@ export declare abstract class StatisticsScreen<T> extends AsyncScreen<T> {
|
|
|
20
20
|
private activeGroup;
|
|
21
21
|
private shiftActiveGroup;
|
|
22
22
|
protected statisticsFilters(): StatisticsFilters;
|
|
23
|
-
/**
|
|
24
|
-
* Maps a preset's raw period value to the granularity legible label
|
|
25
|
-
* (BB-548 scope change 7): `7`/`30` are daily buckets, `365` is monthly.
|
|
26
|
-
*/
|
|
27
|
-
private static rangeLabel;
|
|
28
23
|
private periodFilter;
|
|
29
24
|
/**
|
|
30
|
-
* One boxed filter chip cycling the
|
|
25
|
+
* One boxed filter chip cycling the period kinds
|
|
31
26
|
* (BB-548 scope change 7, replacing the former two independent
|
|
32
27
|
* period/granularity chips of addendum 4). Rendered via
|
|
33
28
|
* `filterBadgeStrip` inside `renderReady`, below Overview — see the
|
|
@@ -60,13 +60,6 @@ export class StatisticsScreen extends AsyncScreen {
|
|
|
60
60
|
filters.period = this.period;
|
|
61
61
|
return filters;
|
|
62
62
|
}
|
|
63
|
-
/**
|
|
64
|
-
* Maps a preset's raw period value to the granularity legible label
|
|
65
|
-
* (BB-548 scope change 7): `7`/`30` are daily buckets, `365` is monthly.
|
|
66
|
-
*/
|
|
67
|
-
static rangeLabel(value) {
|
|
68
|
-
return value === '365' ? '1y·monthly' : `${value}d·daily`;
|
|
69
|
-
}
|
|
70
63
|
periodFilter() {
|
|
71
64
|
const result = this.readyValue === undefined
|
|
72
65
|
? undefined
|
|
@@ -79,14 +72,19 @@ export class StatisticsScreen extends AsyncScreen {
|
|
|
79
72
|
if (filter)
|
|
80
73
|
return {
|
|
81
74
|
value: filter.value,
|
|
82
|
-
|
|
75
|
+
label: filter.options.find((option) => option.value === filter.value)
|
|
76
|
+
?.label ?? filter.value,
|
|
77
|
+
// Custom needs start and end dates, which this screen cannot supply.
|
|
78
|
+
options: filter.options
|
|
79
|
+
.map((option) => option.value)
|
|
80
|
+
.filter((value) => value !== 'custom'),
|
|
83
81
|
};
|
|
84
82
|
}
|
|
85
83
|
}
|
|
86
84
|
return undefined;
|
|
87
85
|
}
|
|
88
86
|
/**
|
|
89
|
-
* One boxed filter chip cycling the
|
|
87
|
+
* One boxed filter chip cycling the period kinds
|
|
90
88
|
* (BB-548 scope change 7, replacing the former two independent
|
|
91
89
|
* period/granularity chips of addendum 4). Rendered via
|
|
92
90
|
* `filterBadgeStrip` inside `renderReady`, below Overview — see the
|
|
@@ -99,7 +97,7 @@ export class StatisticsScreen extends AsyncScreen {
|
|
|
99
97
|
return [
|
|
100
98
|
{
|
|
101
99
|
id: 'period',
|
|
102
|
-
label: `t Range(${
|
|
100
|
+
label: `t Range(${period.label})`,
|
|
103
101
|
},
|
|
104
102
|
];
|
|
105
103
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bakers-build/addon-bakers-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "bakers.build TUI: interactive terminal UI (dashboard, projects, tickets) as a dropsh `tui` renderer plugin.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"zustand": "^5.0.15"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
|
-
"@bakers-build/core": "^0.
|
|
33
|
-
"@bakers-build/message": "^0.
|
|
32
|
+
"@bakers-build/core": "^0.3.0",
|
|
33
|
+
"@bakers-build/message": "^0.3.0"
|
|
34
34
|
}
|
|
35
35
|
}
|