@leo000001/opencode-quota-sidebar 4.0.13 → 4.0.16
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/README.md +504 -504
- package/dist/cli_render.d.ts +4 -4
- package/dist/cli_render.js +136 -107
- package/package.json +1 -1
package/dist/cli_render.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { QuotaSnapshot } from
|
|
2
|
-
import { type UsageSummary } from
|
|
3
|
-
import type { HistoryUsageResult } from
|
|
1
|
+
import type { QuotaSnapshot } from './types.js';
|
|
2
|
+
import { type UsageSummary } from './usage.js';
|
|
3
|
+
import type { HistoryUsageResult } from './usage_service.js';
|
|
4
4
|
export declare function renderCliDashboard(input: {
|
|
5
5
|
label: string;
|
|
6
6
|
usage: UsageSummary;
|
|
@@ -14,4 +14,4 @@ export declare function renderCliHistoryDashboard(input: {
|
|
|
14
14
|
width?: number;
|
|
15
15
|
showCost?: boolean;
|
|
16
16
|
}): string;
|
|
17
|
-
export declare function cliCurrentLabel(period:
|
|
17
|
+
export declare function cliCurrentLabel(period: 'day' | 'week' | 'month'): "Today" | "This Week" | "This Month";
|
package/dist/cli_render.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { canonicalProviderID, collapseQuotaSnapshots, quotaDisplayLabel, } from
|
|
2
|
-
import { getCacheCoverageMetrics, getProviderCacheCoverageMetrics, } from
|
|
1
|
+
import { canonicalProviderID, collapseQuotaSnapshots, quotaDisplayLabel, } from './quota_render.js';
|
|
2
|
+
import { getCacheCoverageMetrics, getProviderCacheCoverageMetrics, } from './usage.js';
|
|
3
3
|
function shortNumber(value, decimals = 1) {
|
|
4
4
|
if (!Number.isFinite(value) || value < 0)
|
|
5
|
-
return
|
|
5
|
+
return '0';
|
|
6
6
|
if (value >= 1_000_000)
|
|
7
7
|
return `${(value / 1_000_000).toFixed(decimals)}m`;
|
|
8
8
|
if (value >= 1000) {
|
|
@@ -16,63 +16,51 @@ function shortNumber(value, decimals = 1) {
|
|
|
16
16
|
}
|
|
17
17
|
function formatCurrency(value, currency) {
|
|
18
18
|
const safe = Number.isFinite(value) ? value : 0;
|
|
19
|
-
const prefix = typeof currency ===
|
|
19
|
+
const prefix = typeof currency === 'string' && currency ? currency : '$';
|
|
20
20
|
if (safe === 0)
|
|
21
21
|
return `${prefix}0.00`;
|
|
22
22
|
if (safe < 10 && safe > -10)
|
|
23
|
-
return `${safe < 0 ?
|
|
24
|
-
const rounded = Math.abs(safe).toFixed(1).replace(/\.0$/,
|
|
25
|
-
return `${safe < 0 ?
|
|
23
|
+
return `${safe < 0 ? '-' : ''}${prefix}${Math.abs(safe).toFixed(2)}`;
|
|
24
|
+
const rounded = Math.abs(safe).toFixed(1).replace(/\.0$/, '');
|
|
25
|
+
return `${safe < 0 ? '-' : ''}${prefix}${rounded}`;
|
|
26
26
|
}
|
|
27
27
|
function formatApiCost(value) {
|
|
28
|
-
return formatCurrency(value,
|
|
28
|
+
return formatCurrency(value, '$');
|
|
29
29
|
}
|
|
30
30
|
function formatPercent(value, decimals = 1) {
|
|
31
31
|
const safe = Number.isFinite(value) && value >= 0 ? value : 0;
|
|
32
32
|
const pct = (safe * 100).toFixed(decimals);
|
|
33
|
-
return `${pct.replace(/\.0+$/,
|
|
33
|
+
return `${pct.replace(/\.0+$/, '').replace(/(\.\d*[1-9])0+$/, '$1')}%`;
|
|
34
34
|
}
|
|
35
35
|
function compactCountdown(iso) {
|
|
36
36
|
if (!iso)
|
|
37
|
-
return
|
|
37
|
+
return 'n/a';
|
|
38
38
|
const timestamp = Date.parse(iso);
|
|
39
39
|
if (Number.isNaN(timestamp))
|
|
40
|
-
return
|
|
40
|
+
return 'n/a';
|
|
41
41
|
const remainingMs = timestamp - Date.now();
|
|
42
42
|
if (!Number.isFinite(remainingMs))
|
|
43
|
-
return
|
|
43
|
+
return 'n/a';
|
|
44
44
|
if (remainingMs <= 0)
|
|
45
|
-
return
|
|
45
|
+
return '0m';
|
|
46
46
|
const totalMinutes = Math.max(1, Math.floor(remainingMs / 60_000));
|
|
47
47
|
if (totalMinutes < 60)
|
|
48
48
|
return `${totalMinutes}m`;
|
|
49
49
|
if (totalMinutes < 24 * 60) {
|
|
50
50
|
const hours = Math.floor(totalMinutes / 60);
|
|
51
51
|
const minutes = totalMinutes % 60;
|
|
52
|
-
return `${hours}h${`${minutes}`.padStart(2,
|
|
52
|
+
return `${hours}h${`${minutes}`.padStart(2, '0')}m`;
|
|
53
53
|
}
|
|
54
54
|
const days = Math.floor(totalMinutes / (24 * 60));
|
|
55
55
|
const hours = Math.floor((totalMinutes % (24 * 60)) / 60);
|
|
56
|
-
return `${days}D${`${hours}`.padStart(2,
|
|
56
|
+
return `${days}D${`${hours}`.padStart(2, '0')}h`;
|
|
57
57
|
}
|
|
58
58
|
function gauge(value, width = 10) {
|
|
59
59
|
if (value === undefined || !Number.isFinite(value))
|
|
60
|
-
return `${
|
|
60
|
+
return `${'░'.repeat(width)} n/a`;
|
|
61
61
|
const ratio = Math.max(0, Math.min(1, value / 100));
|
|
62
62
|
const filled = Math.max(value > 0 ? 1 : 0, Math.round(ratio * width));
|
|
63
|
-
return `${
|
|
64
|
-
}
|
|
65
|
-
function formatDelta(current, previous, format) {
|
|
66
|
-
if (previous === undefined)
|
|
67
|
-
return `${format(current)} now`;
|
|
68
|
-
if (!Number.isFinite(previous) || previous < 0)
|
|
69
|
-
return `${format(current)} now`;
|
|
70
|
-
if (previous === 0)
|
|
71
|
-
return `${format(current)} now, ${current === 0 ? "flat" : "new"}`;
|
|
72
|
-
const delta = ((current - previous) / previous) * 100;
|
|
73
|
-
const rounded = Math.abs(delta) >= 10 ? delta.toFixed(0) : delta.toFixed(1);
|
|
74
|
-
const normalized = rounded.replace(/\.0$/, "");
|
|
75
|
-
return `${format(current)} now, ${delta > 0 ? "+" : ""}${normalized}%`;
|
|
63
|
+
return `${'█'.repeat(filled)}${'░'.repeat(width - filled)} ${`${Math.round(value)}`.padStart(3, ' ')}%`;
|
|
76
64
|
}
|
|
77
65
|
function clip(value, width) {
|
|
78
66
|
return value.length <= width
|
|
@@ -85,58 +73,61 @@ function centerLine(value, width) {
|
|
|
85
73
|
return clipped;
|
|
86
74
|
const left = Math.floor((width - clipped.length) / 2);
|
|
87
75
|
const right = width - clipped.length - left;
|
|
88
|
-
return `${
|
|
76
|
+
return `${' '.repeat(left)}${clipped}${' '.repeat(right)}`;
|
|
89
77
|
}
|
|
90
78
|
function padRight(value, width) {
|
|
91
|
-
return clip(value, width).padEnd(width,
|
|
79
|
+
return clip(value, width).padEnd(width, ' ');
|
|
92
80
|
}
|
|
93
|
-
function box(title, lines,
|
|
81
|
+
function box(title, lines, maxWidth = 78) {
|
|
94
82
|
const longestLine = lines.reduce((max, line) => Math.max(max, line.length), 0);
|
|
95
|
-
|
|
83
|
+
// `maxWidth` is a hard ceiling. We intentionally avoid a fixed minimum so
|
|
84
|
+
// the CLI rules shrink to the rendered content instead of protruding past it.
|
|
85
|
+
const contentWidth = Math.max(title.length, longestLine);
|
|
86
|
+
const inner = Math.max(1, Math.min(maxWidth, contentWidth));
|
|
96
87
|
const top = centerLine(title, inner);
|
|
97
|
-
const rule =
|
|
88
|
+
const rule = '─'.repeat(inner);
|
|
98
89
|
const body = lines.map((line) => clip(line, inner));
|
|
99
|
-
return [top, rule, ...body, rule].join(
|
|
90
|
+
return [top, rule, ...body, rule].join('\n');
|
|
100
91
|
}
|
|
101
92
|
function currentLabel(period) {
|
|
102
|
-
if (period ===
|
|
103
|
-
return
|
|
104
|
-
if (period ===
|
|
105
|
-
return
|
|
106
|
-
return
|
|
93
|
+
if (period === 'day')
|
|
94
|
+
return 'Today';
|
|
95
|
+
if (period === 'week')
|
|
96
|
+
return 'This Week';
|
|
97
|
+
return 'This Month';
|
|
107
98
|
}
|
|
108
99
|
function historyLabel(result) {
|
|
109
|
-
if (result.period ===
|
|
100
|
+
if (result.period === 'day')
|
|
110
101
|
return `Daily since ${result.since.raw}`;
|
|
111
|
-
if (result.period ===
|
|
102
|
+
if (result.period === 'week')
|
|
112
103
|
return `Weekly since ${result.since.raw}`;
|
|
113
104
|
return `Monthly since ${result.since.raw}`;
|
|
114
105
|
}
|
|
115
106
|
function quotaRows(quotas) {
|
|
116
|
-
const visible = collapseQuotaSnapshots(quotas).filter((item) => item.status ===
|
|
107
|
+
const visible = collapseQuotaSnapshots(quotas).filter((item) => item.status === 'ok' || item.status === 'error');
|
|
117
108
|
if (visible.length === 0)
|
|
118
|
-
return [
|
|
109
|
+
return ['no provider quota data available'];
|
|
119
110
|
return visible.flatMap((quota) => {
|
|
120
|
-
const label = quotaDisplayLabel(quota).padEnd(11,
|
|
121
|
-
if (quota.status ===
|
|
122
|
-
return [`${label} error${quota.note ? ` · ${quota.note}` :
|
|
111
|
+
const label = quotaDisplayLabel(quota).padEnd(11, ' ');
|
|
112
|
+
if (quota.status === 'error') {
|
|
113
|
+
return [`${label} error${quota.note ? ` · ${quota.note}` : ''}`];
|
|
123
114
|
}
|
|
124
115
|
if (quota.windows && quota.windows.length > 0) {
|
|
125
116
|
const lines = quota.windows.map((win) => {
|
|
126
|
-
const detail = padRight(win.label ||
|
|
117
|
+
const detail = padRight(win.label || 'quota', 18);
|
|
127
118
|
if (win.showPercent === false) {
|
|
128
119
|
return `${label}${detail} ${compactCountdown(win.resetAt)}`;
|
|
129
120
|
}
|
|
130
121
|
return `${label}${detail} [${gauge(win.remainingPercent)}] ${compactCountdown(win.resetAt)}`;
|
|
131
122
|
});
|
|
132
123
|
if (quota.balance) {
|
|
133
|
-
lines.push(`${label}${padRight(
|
|
124
|
+
lines.push(`${label}${padRight('balance', 18)} ${formatCurrency(quota.balance.amount, quota.balance.currency)}`);
|
|
134
125
|
}
|
|
135
126
|
return lines;
|
|
136
127
|
}
|
|
137
128
|
if (quota.balance) {
|
|
138
129
|
return [
|
|
139
|
-
`${label}${padRight(
|
|
130
|
+
`${label}${padRight('balance', 18)} ${formatCurrency(quota.balance.amount, quota.balance.currency)}`,
|
|
140
131
|
];
|
|
141
132
|
}
|
|
142
133
|
return [
|
|
@@ -147,51 +138,85 @@ function quotaRows(quotas) {
|
|
|
147
138
|
function providerRows(usage, showCost) {
|
|
148
139
|
const providers = Object.values(usage.providers).sort((a, b) => b.total - a.total);
|
|
149
140
|
if (providers.length === 0)
|
|
150
|
-
return [
|
|
151
|
-
|
|
141
|
+
return ['no provider activity'];
|
|
142
|
+
const prepared = providers.map((provider) => {
|
|
152
143
|
const cache = getProviderCacheCoverageMetrics(provider).cachedRatio;
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
144
|
+
return {
|
|
145
|
+
label: quotaDisplayLabel({
|
|
146
|
+
providerID: provider.providerID,
|
|
147
|
+
label: provider.providerID,
|
|
148
|
+
status: 'ok',
|
|
149
|
+
checkedAt: 0,
|
|
150
|
+
}),
|
|
151
|
+
requests: shortNumber(provider.assistantMessages),
|
|
152
|
+
tokens: shortNumber(provider.total),
|
|
153
|
+
cached: cache !== undefined ? formatPercent(cache, 0) : '-',
|
|
154
|
+
cost: canonicalProviderID(provider.providerID) === 'github-copilot'
|
|
155
|
+
? '-'
|
|
156
|
+
: formatApiCost(provider.apiCost),
|
|
157
|
+
};
|
|
158
|
+
});
|
|
159
|
+
const labelWidth = Math.max(...prepared.map((row) => row.label.length));
|
|
160
|
+
const requestWidth = Math.max(...prepared.map((row) => row.requests.length));
|
|
161
|
+
const tokenWidth = Math.max(...prepared.map((row) => row.tokens.length));
|
|
162
|
+
const cachedWidth = Math.max(...prepared.map((row) => row.cached.length));
|
|
163
|
+
const costWidth = Math.max(...prepared.map((row) => row.cost.length));
|
|
164
|
+
return prepared.map((row) => {
|
|
165
|
+
const base = [
|
|
166
|
+
padRight(row.label, labelWidth),
|
|
167
|
+
`${row.requests.padStart(requestWidth)} req`,
|
|
168
|
+
`${row.tokens.padStart(tokenWidth)} tok`,
|
|
169
|
+
`${row.cached.padStart(cachedWidth)} cached`,
|
|
170
|
+
].join(' ');
|
|
171
|
+
return showCost ? `${base} ${row.cost.padStart(costWidth)}` : base;
|
|
158
172
|
});
|
|
159
173
|
}
|
|
160
174
|
function cliApiCostSummary(usage) {
|
|
161
175
|
const providers = Object.values(usage.providers);
|
|
162
176
|
if (providers.length === 0)
|
|
163
177
|
return formatApiCost(usage.apiCost);
|
|
164
|
-
const hasNonCopilot = providers.some((provider) => canonicalProviderID(provider.providerID) !==
|
|
165
|
-
return hasNonCopilot ? formatApiCost(usage.apiCost) :
|
|
178
|
+
const hasNonCopilot = providers.some((provider) => canonicalProviderID(provider.providerID) !== 'github-copilot');
|
|
179
|
+
return hasNonCopilot ? formatApiCost(usage.apiCost) : '-';
|
|
166
180
|
}
|
|
167
181
|
function totalsRows(input) {
|
|
168
|
-
const
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
const
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
182
|
+
const leftLabelWidth = Math.max('Sessions'.length, 'API Cost'.length);
|
|
183
|
+
const leftValueWidth = Math.max(input.sessions.length, input.tokens.length, input.cost?.length ?? 0);
|
|
184
|
+
const rightLabelWidth = 'Requests'.length;
|
|
185
|
+
const rightValueWidth = Math.max(input.requests.length, input.cached?.length ?? 0);
|
|
186
|
+
const leftCell = (label, value) => `${padRight(label, leftLabelWidth)} ${value.padEnd(leftValueWidth, ' ')}`;
|
|
187
|
+
const rightCell = (label, value) => `${padRight(label, rightLabelWidth)} ${value.padEnd(rightValueWidth, ' ')}`;
|
|
188
|
+
const row1 = [
|
|
189
|
+
leftCell('Sessions', input.sessions),
|
|
190
|
+
rightCell('Requests', input.requests),
|
|
191
|
+
]
|
|
192
|
+
.join(' ')
|
|
193
|
+
.trimEnd();
|
|
194
|
+
const row2 = [
|
|
195
|
+
leftCell('Tokens', input.tokens),
|
|
196
|
+
...(input.cached ? [rightCell('Cached', input.cached)] : []),
|
|
197
|
+
]
|
|
198
|
+
.join(' ')
|
|
199
|
+
.trimEnd();
|
|
200
|
+
const row3 = input.cost
|
|
201
|
+
? leftCell('API Cost', input.cost).trimEnd()
|
|
202
|
+
: undefined;
|
|
203
|
+
return [row1, row2, ...(row3 ? [row3] : [])];
|
|
178
204
|
}
|
|
179
|
-
function trendBar(value, maxValue, width =
|
|
205
|
+
function trendBar(value, maxValue, width = 16) {
|
|
180
206
|
if (!Number.isFinite(value) || value <= 0 || maxValue <= 0) {
|
|
181
|
-
return
|
|
207
|
+
return '░'.repeat(width);
|
|
182
208
|
}
|
|
183
209
|
const filled = Math.max(1, Math.round((value / maxValue) * width));
|
|
184
|
-
return `${
|
|
210
|
+
return `${'█'.repeat(filled)}${'░'.repeat(width - filled)}`;
|
|
185
211
|
}
|
|
186
212
|
function trendMetricBlock(input) {
|
|
187
213
|
const visibleRows = input.rows.slice(-Math.min(8, input.rows.length));
|
|
188
214
|
const values = visibleRows.map(input.pick);
|
|
189
215
|
const maxValue = Math.max(...values, 0);
|
|
190
|
-
const
|
|
191
|
-
const
|
|
192
|
-
const labelWidth = Math.max(8, Math.min(28, Math.max(...displayLabels.map((label) => label.length), 8)));
|
|
216
|
+
const displayLabels = visibleRows.map((row) => `${row.range.shortLabel}${row.range.isCurrent ? '*' : ''}`);
|
|
217
|
+
const labelWidth = Math.max(6, Math.min(20, Math.max(...displayLabels.map((label) => label.length), 6)));
|
|
193
218
|
return [
|
|
194
|
-
|
|
219
|
+
input.label,
|
|
195
220
|
...visibleRows.map((row, index) => {
|
|
196
221
|
const value = input.pick(row);
|
|
197
222
|
const tag = padRight(displayLabels[index], labelWidth);
|
|
@@ -200,54 +225,59 @@ function trendMetricBlock(input) {
|
|
|
200
225
|
];
|
|
201
226
|
}
|
|
202
227
|
export function renderCliDashboard(input) {
|
|
203
|
-
const
|
|
228
|
+
const maxWidth = input.width ?? 78;
|
|
204
229
|
const showCost = input.showCost !== false;
|
|
205
230
|
const cache = getCacheCoverageMetrics(input.usage).cachedRatio;
|
|
206
231
|
return box(`opencode-quota · ${input.label}`, [
|
|
207
|
-
|
|
232
|
+
'QUOTA',
|
|
208
233
|
...quotaRows(input.quotas),
|
|
209
|
-
|
|
210
|
-
|
|
234
|
+
'',
|
|
235
|
+
'TOTALS',
|
|
211
236
|
...totalsRows({
|
|
237
|
+
sessions: `${input.usage.sessionCount}`,
|
|
212
238
|
requests: shortNumber(input.usage.assistantMessages),
|
|
213
239
|
tokens: shortNumber(input.usage.total),
|
|
214
240
|
...(showCost ? { cost: cliApiCostSummary(input.usage) } : {}),
|
|
215
|
-
|
|
216
|
-
periods: `${input.usage.sessionCount}`,
|
|
241
|
+
cached: cache !== undefined ? formatPercent(cache, 1) : '-',
|
|
217
242
|
}),
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
"PROVIDERS",
|
|
243
|
+
'',
|
|
244
|
+
'PROVIDERS',
|
|
221
245
|
...providerRows(input.usage, showCost),
|
|
222
|
-
],
|
|
246
|
+
], maxWidth);
|
|
223
247
|
}
|
|
224
248
|
export function renderCliHistoryDashboard(input) {
|
|
225
|
-
const
|
|
249
|
+
const maxWidth = input.width ?? 78;
|
|
226
250
|
const showCost = input.showCost !== false;
|
|
227
251
|
const rows = input.result.rows;
|
|
228
252
|
const current = [...rows].reverse().find((row) => row.range.isCurrent) || rows.at(-1);
|
|
229
|
-
const currentIndex = current ? rows.indexOf(current) : -1;
|
|
230
|
-
const previous = currentIndex > 0 ? rows[currentIndex - 1] : undefined;
|
|
231
253
|
const cache = getCacheCoverageMetrics(input.result.total).cachedRatio;
|
|
232
254
|
const trendBlocks = [
|
|
233
255
|
...trendMetricBlock({
|
|
234
|
-
label:
|
|
256
|
+
label: 'Sessions',
|
|
257
|
+
rows,
|
|
258
|
+
current,
|
|
259
|
+
pick: (row) => row.usage.sessionCount,
|
|
260
|
+
format: (value) => shortNumber(value),
|
|
261
|
+
}),
|
|
262
|
+
'',
|
|
263
|
+
...trendMetricBlock({
|
|
264
|
+
label: 'Requests',
|
|
235
265
|
rows,
|
|
236
266
|
current,
|
|
237
267
|
pick: (row) => row.usage.assistantMessages,
|
|
238
268
|
format: (value) => shortNumber(value),
|
|
239
269
|
}),
|
|
240
|
-
|
|
270
|
+
'',
|
|
241
271
|
...trendMetricBlock({
|
|
242
|
-
label:
|
|
272
|
+
label: 'Tokens',
|
|
243
273
|
rows,
|
|
244
274
|
current,
|
|
245
275
|
pick: (row) => row.usage.total,
|
|
246
276
|
format: (value) => shortNumber(value),
|
|
247
277
|
}),
|
|
248
|
-
|
|
278
|
+
'',
|
|
249
279
|
...trendMetricBlock({
|
|
250
|
-
label:
|
|
280
|
+
label: 'Cached',
|
|
251
281
|
rows,
|
|
252
282
|
current,
|
|
253
283
|
pick: (row) => getCacheCoverageMetrics(row.usage).cachedRatio ?? 0,
|
|
@@ -255,9 +285,9 @@ export function renderCliHistoryDashboard(input) {
|
|
|
255
285
|
}),
|
|
256
286
|
...(showCost
|
|
257
287
|
? [
|
|
258
|
-
|
|
288
|
+
'',
|
|
259
289
|
...trendMetricBlock({
|
|
260
|
-
label:
|
|
290
|
+
label: 'API Cost',
|
|
261
291
|
rows,
|
|
262
292
|
current,
|
|
263
293
|
pick: (row) => row.usage.apiCost,
|
|
@@ -267,25 +297,24 @@ export function renderCliHistoryDashboard(input) {
|
|
|
267
297
|
: []),
|
|
268
298
|
];
|
|
269
299
|
return box(`opencode-quota · ${historyLabel(input.result)}`, [
|
|
270
|
-
|
|
300
|
+
'QUOTA',
|
|
271
301
|
...quotaRows(input.quotas),
|
|
272
|
-
|
|
273
|
-
|
|
302
|
+
'',
|
|
303
|
+
'TOTALS',
|
|
274
304
|
...totalsRows({
|
|
305
|
+
sessions: `${input.result.total.sessionCount}`,
|
|
275
306
|
requests: shortNumber(input.result.total.assistantMessages),
|
|
276
307
|
tokens: shortNumber(input.result.total.total),
|
|
277
308
|
...(showCost ? { cost: cliApiCostSummary(input.result.total) } : {}),
|
|
278
|
-
|
|
279
|
-
periods: `${rows.length}`,
|
|
280
|
-
current: current?.range.shortLabel || "-",
|
|
309
|
+
cached: cache !== undefined ? formatPercent(cache, 1) : '-',
|
|
281
310
|
}),
|
|
282
|
-
|
|
283
|
-
|
|
311
|
+
'',
|
|
312
|
+
'PROVIDERS',
|
|
284
313
|
...providerRows(input.result.total, showCost),
|
|
285
|
-
|
|
286
|
-
|
|
314
|
+
'',
|
|
315
|
+
'TREND',
|
|
287
316
|
...trendBlocks,
|
|
288
|
-
],
|
|
317
|
+
], maxWidth);
|
|
289
318
|
}
|
|
290
319
|
export function cliCurrentLabel(period) {
|
|
291
320
|
return currentLabel(period);
|
package/package.json
CHANGED