@bluemarble/bi 0.3.1 → 0.4.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/{DashboardDevtools-C4E9afPT.js → DashboardDevtools-7L93aV1-.js} +617 -230
- package/dist/DashboardDevtools-7L93aV1-.js.map +1 -0
- package/dist/{ModelDictionary-kUKcdbc8.js → ModelDictionary-Y7W9oK1J.js} +3 -3
- package/dist/{ModelDictionary-kUKcdbc8.js.map → ModelDictionary-Y7W9oK1J.js.map} +1 -1
- package/dist/client/index.d.ts +54 -17
- package/dist/client/index.js +121 -57
- package/dist/client/index.js.map +1 -1
- package/dist/{layout-DTR4vI-I.js → layout-676sEvvb.js} +84 -32
- package/dist/layout-676sEvvb.js.map +1 -0
- package/dist/server/index.d.ts +1 -5
- package/dist/server/index.js +1 -1
- package/dist/{types-DUJS2Zmx.d.ts → types-HXAn-3I1.d.ts} +47 -13
- package/dist/types.d.ts +2 -2
- package/package.json +1 -1
- package/dist/DashboardDevtools-C4E9afPT.js.map +0 -1
- package/dist/layout-DTR4vI-I.js.map +0 -1
package/dist/client/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { f as isBuiltinChart, o as chartCardStyle, u as customChartProps } from "../layout-
|
|
2
|
-
import { a as useDashboard, c as layoutItemKey, i as DashboardProvider, n as INSPECT_ATTRIBUTE, r as useModelQuery, s as LAYOUT_ITEM_ATTRIBUTE, t as ModelDictionary } from "../ModelDictionary-
|
|
1
|
+
import { f as isBuiltinChart, o as chartCardStyle, u as customChartProps } from "../layout-676sEvvb.js";
|
|
2
|
+
import { a as useDashboard, c as layoutItemKey, i as DashboardProvider, n as INSPECT_ATTRIBUTE, r as useModelQuery, s as LAYOUT_ITEM_ATTRIBUTE, t as ModelDictionary } from "../ModelDictionary-Y7W9oK1J.js";
|
|
3
3
|
import { Box, Checkbox, CircularProgress, FormControl, InputLabel, ListItemText, MenuItem, OutlinedInput, Paper, Select, Table, TableBody, TableCell, TableHead, TableRow, TableSortLabel, Typography } from "@mui/material";
|
|
4
4
|
import { Bar, BarChart as BarChart$1, CartesianGrid, Cell, ComposedChart, LabelList, Line, Pie, PieChart, ResponsiveContainer, Tooltip as Tooltip$1, XAxis, YAxis } from "recharts";
|
|
5
5
|
import { createContext, useContext, useEffect, useLayoutEffect, useRef, useState, useSyncExternalStore } from "react";
|
|
@@ -95,7 +95,8 @@ function chartPlaceholder({ height, error, isLoading, empty }) {
|
|
|
95
95
|
children: error ? "Erro ao carregar o gráfico" : isLoading ? "Carregando…" : "Sem dados para os filtros selecionados"
|
|
96
96
|
});
|
|
97
97
|
}
|
|
98
|
-
|
|
98
|
+
/** `caption`: o que é o título (ex.: o rótulo da dimensão), em cinza acima dele. */
|
|
99
|
+
function TooltipBox({ title, caption, children }) {
|
|
99
100
|
return /* @__PURE__ */ jsxs(Box, {
|
|
100
101
|
sx: {
|
|
101
102
|
bgcolor: "#fff",
|
|
@@ -103,53 +104,90 @@ function TooltipBox({ title, children }) {
|
|
|
103
104
|
p: 1,
|
|
104
105
|
fontSize: 13
|
|
105
106
|
},
|
|
106
|
-
children: [
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
107
|
+
children: [
|
|
108
|
+
caption && /* @__PURE__ */ jsx(Box, {
|
|
109
|
+
sx: {
|
|
110
|
+
fontSize: 11,
|
|
111
|
+
color: "#777"
|
|
112
|
+
},
|
|
113
|
+
children: caption
|
|
114
|
+
}),
|
|
115
|
+
/* @__PURE__ */ jsx(Box, {
|
|
116
|
+
sx: { fontWeight: 700 },
|
|
117
|
+
children: title
|
|
118
|
+
}),
|
|
119
|
+
children
|
|
120
|
+
]
|
|
110
121
|
});
|
|
111
122
|
}
|
|
112
123
|
//#endregion
|
|
113
124
|
//#region src/client/format.ts
|
|
114
125
|
const formatters = /* @__PURE__ */ new Map();
|
|
115
|
-
|
|
126
|
+
/** `compact`: notação curta do pt-BR (1,2 mil / 3,4 mi / 5,6 bi). */
|
|
127
|
+
function formatNumber(value, decimals = 2, compact = false) {
|
|
116
128
|
if (value === null || value === void 0 || value === "") return "";
|
|
117
129
|
const number = Number(value);
|
|
118
130
|
if (Number.isNaN(number)) return String(value);
|
|
119
|
-
|
|
131
|
+
const key = `${decimals}:${compact}`;
|
|
132
|
+
let formatter = formatters.get(key);
|
|
120
133
|
if (!formatter) {
|
|
121
134
|
formatter = new Intl.NumberFormat("pt-BR", {
|
|
122
135
|
minimumFractionDigits: decimals,
|
|
123
|
-
maximumFractionDigits: decimals
|
|
136
|
+
maximumFractionDigits: decimals,
|
|
137
|
+
...compact && { notation: "compact" }
|
|
124
138
|
});
|
|
125
|
-
formatters.set(
|
|
139
|
+
formatters.set(key, formatter);
|
|
126
140
|
}
|
|
127
141
|
return formatter.format(number);
|
|
128
142
|
}
|
|
129
|
-
const formatCurrency = (value, decimals = 2) => {
|
|
130
|
-
const text = formatNumber(value, decimals);
|
|
143
|
+
const formatCurrency = (value, decimals = 2, compact = false) => {
|
|
144
|
+
const text = formatNumber(value, decimals, compact);
|
|
131
145
|
return text && `R$ ${text}`;
|
|
132
146
|
};
|
|
133
147
|
/**
|
|
134
|
-
* Formata pelo dicionário do modelo (`format`/`decimals` da medida)
|
|
135
|
-
* do componente quando
|
|
148
|
+
* Formata pelo dicionário do modelo (`format`/`decimals` da medida) ou pelo formato do gráfico.
|
|
149
|
+
* `fallbackDecimals` é o padrão do componente quando nenhum dos dois define `decimals`.
|
|
136
150
|
*/
|
|
137
151
|
function formatMeasure(value, meta, fallbackDecimals = 2) {
|
|
152
|
+
if (value === null || value === void 0 || value === "") return "";
|
|
138
153
|
const decimals = meta?.decimals ?? (meta?.format === "integer" ? 0 : fallbackDecimals);
|
|
154
|
+
const compact = meta?.compact ?? false;
|
|
155
|
+
let text;
|
|
139
156
|
switch (meta?.format) {
|
|
140
|
-
case "currency":
|
|
157
|
+
case "currency":
|
|
158
|
+
text = formatCurrency(value, decimals, compact);
|
|
159
|
+
break;
|
|
141
160
|
case "percent": {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
161
|
+
const number = formatNumber(Number(value) * 100, decimals, compact);
|
|
162
|
+
text = number && `${number}%`;
|
|
163
|
+
break;
|
|
145
164
|
}
|
|
146
|
-
default:
|
|
165
|
+
default: text = formatNumber(value, decimals, compact);
|
|
147
166
|
}
|
|
167
|
+
return text && `${meta?.prefix ?? ""}${text}${meta?.suffix ?? ""}`;
|
|
148
168
|
}
|
|
149
|
-
/**
|
|
150
|
-
function
|
|
151
|
-
const
|
|
152
|
-
|
|
169
|
+
/** Dicionário do modelo com o formato do gráfico por cima. */
|
|
170
|
+
function measureFormat(meta, measure, formats) {
|
|
171
|
+
const fromModel = meta?.measures[measure];
|
|
172
|
+
const fromChart = formats?.[measure];
|
|
173
|
+
if (!fromChart) return fromModel;
|
|
174
|
+
return {
|
|
175
|
+
...fromModel?.format !== void 0 && { format: fromModel.format },
|
|
176
|
+
...fromModel?.decimals !== void 0 && { decimals: fromModel.decimals },
|
|
177
|
+
...fromChart
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Formatter de uma medida: o `formats` do gráfico (se houver) por cima do dicionário do modelo; sem
|
|
182
|
+
* `format`, número com `fallbackDecimals`.
|
|
183
|
+
*/
|
|
184
|
+
function measureFormatter(meta, measure, fallbackDecimals = 2, formats) {
|
|
185
|
+
const format = measureFormat(meta, measure, formats);
|
|
186
|
+
return (value) => formatMeasure(value, format, fallbackDecimals);
|
|
187
|
+
}
|
|
188
|
+
/** Rótulo de uma dimensão/medida: o `labels` do gráfico, o dicionário do modelo ou o nome. */
|
|
189
|
+
function fieldLabel(meta, name, labels) {
|
|
190
|
+
return labels?.[name] || meta?.dimensions[name]?.label || meta?.measures[name]?.label || name;
|
|
153
191
|
}
|
|
154
192
|
//#endregion
|
|
155
193
|
//#region src/client/BarChart.tsx
|
|
@@ -160,7 +198,7 @@ const ROW_HEIGHT = 28;
|
|
|
160
198
|
* Barras de uma ou mais medidas por uma dimensão. Ex.:
|
|
161
199
|
* `<BarChart dimension="navio" measures={['custoTotal']} orientation="horizontal" sort="desc" limit={10} />`.
|
|
162
200
|
*/
|
|
163
|
-
function BarChart({ dimension, measures, orientation = "vertical", stacked = false, sort = "dimension", limit, formatDimension = String, hideEmpty = true, showValues = true, clickToFilter = false, height = 360, queryLabel }) {
|
|
201
|
+
function BarChart({ dimension, measures, orientation = "vertical", stacked = false, sort = "dimension", limit, formatDimension = String, hideEmpty = true, showValues = true, clickToFilter = false, height = 360, labels, formats: formatsByMeasure, queryLabel }) {
|
|
164
202
|
const { meta } = useDashboard();
|
|
165
203
|
const { rows, isLoading, error, inspectProps } = useModelQuery({
|
|
166
204
|
dimensions: [dimension],
|
|
@@ -169,8 +207,13 @@ function BarChart({ dimension, measures, orientation = "vertical", stacked = fal
|
|
|
169
207
|
label: queryLabel ?? `BarChart · ${dimension}`
|
|
170
208
|
});
|
|
171
209
|
const filter = useClickFilter(dimension, clickToFilter);
|
|
172
|
-
const formats = measures.map((measure) => measureFormatter(meta, measure, 0));
|
|
173
|
-
const labelOf = (
|
|
210
|
+
const formats = measures.map((measure) => measureFormatter(meta, measure, 0, formatsByMeasure));
|
|
211
|
+
const labelOf = (name) => fieldLabel(meta, name, labels);
|
|
212
|
+
const axisFormat = measures[0] ? measureFormat(meta, measures[0], formatsByMeasure) : void 0;
|
|
213
|
+
const formatTick = (value) => formatMeasure(value, {
|
|
214
|
+
...axisFormat,
|
|
215
|
+
decimals: axisFormat?.compact ? 1 : 0
|
|
216
|
+
}, 0);
|
|
174
217
|
const first = measures[0];
|
|
175
218
|
let data = rows.filter((row) => !hideEmpty || measures.some((measure) => numberOf(row, measure))).map((row) => {
|
|
176
219
|
const value = row[dimension] ?? "";
|
|
@@ -184,7 +227,7 @@ function BarChart({ dimension, measures, orientation = "vertical", stacked = fal
|
|
|
184
227
|
if (sort !== "dimension" && first) data = [...data].sort((a, b) => sort === "desc" ? Number(b[first]) - Number(a[first]) : Number(a[first]) - Number(b[first]));
|
|
185
228
|
if (limit) data = data.slice(0, limit);
|
|
186
229
|
const horizontal = orientation === "horizontal";
|
|
187
|
-
const
|
|
230
|
+
const showLabels = showValues && data.length <= MAX_VALUE_LABELS;
|
|
188
231
|
const chartHeight = horizontal ? Math.max(height, data.length * ROW_HEIGHT + 24) : height;
|
|
189
232
|
const longest = Math.max(0, ...data.map((point) => point.label.length));
|
|
190
233
|
const state = chartPlaceholder({
|
|
@@ -198,6 +241,7 @@ function BarChart({ dimension, measures, orientation = "vertical", stacked = fal
|
|
|
198
241
|
const point = payload[0].payload;
|
|
199
242
|
return /* @__PURE__ */ jsx(TooltipBox, {
|
|
200
243
|
title: point.label,
|
|
244
|
+
caption: labelOf(dimension),
|
|
201
245
|
children: measures.map((measure, index) => /* @__PURE__ */ jsxs(Box, {
|
|
202
246
|
sx: {
|
|
203
247
|
display: "flex",
|
|
@@ -271,11 +315,11 @@ function BarChart({ dimension, measures, orientation = "vertical", stacked = fal
|
|
|
271
315
|
barCategoryGap: "20%",
|
|
272
316
|
margin: horizontal ? {
|
|
273
317
|
top: 4,
|
|
274
|
-
right:
|
|
318
|
+
right: showLabels ? 96 : 16,
|
|
275
319
|
left: 8,
|
|
276
320
|
bottom: 4
|
|
277
321
|
} : {
|
|
278
|
-
top:
|
|
322
|
+
top: showLabels ? 24 : 8,
|
|
279
323
|
right: 8,
|
|
280
324
|
left: 8,
|
|
281
325
|
bottom: 0
|
|
@@ -288,11 +332,12 @@ function BarChart({ dimension, measures, orientation = "vertical", stacked = fal
|
|
|
288
332
|
}),
|
|
289
333
|
horizontal ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(XAxis, {
|
|
290
334
|
type: "number",
|
|
291
|
-
hide:
|
|
335
|
+
hide: showLabels,
|
|
292
336
|
tick: {
|
|
293
337
|
fontSize: 12,
|
|
294
338
|
fill: "#555"
|
|
295
|
-
}
|
|
339
|
+
},
|
|
340
|
+
tickFormatter: formatTick
|
|
296
341
|
}), /* @__PURE__ */ jsx(YAxis, {
|
|
297
342
|
type: "category",
|
|
298
343
|
dataKey: "label",
|
|
@@ -314,12 +359,12 @@ function BarChart({ dimension, measures, orientation = "vertical", stacked = fal
|
|
|
314
359
|
tickLine: false,
|
|
315
360
|
axisLine: { stroke: "#ccc" }
|
|
316
361
|
}), /* @__PURE__ */ jsx(YAxis, {
|
|
317
|
-
hide:
|
|
362
|
+
hide: showLabels,
|
|
318
363
|
tick: {
|
|
319
364
|
fontSize: 12,
|
|
320
365
|
fill: "#555"
|
|
321
366
|
},
|
|
322
|
-
tickFormatter:
|
|
367
|
+
tickFormatter: formatTick,
|
|
323
368
|
width: 72
|
|
324
369
|
})] }),
|
|
325
370
|
/* @__PURE__ */ jsx(Tooltip$1, {
|
|
@@ -336,7 +381,7 @@ function BarChart({ dimension, measures, orientation = "vertical", stacked = fal
|
|
|
336
381
|
isAnimationActive: false,
|
|
337
382
|
onClick: clickToFilter ? (_bar, barIndex, event) => handleClick(barIndex, event) : void 0,
|
|
338
383
|
cursor: clickToFilter ? "pointer" : void 0,
|
|
339
|
-
children: [clickToFilter && data.map((point) => /* @__PURE__ */ jsx(Cell, { fillOpacity: filter.isDimmed(point.value) ? .35 : 1 }, String(point.value))),
|
|
384
|
+
children: [clickToFilter && data.map((point) => /* @__PURE__ */ jsx(Cell, { fillOpacity: filter.isDimmed(point.value) ? .35 : 1 }, String(point.value))), showLabels && !stacked && /* @__PURE__ */ jsx(LabelList, {
|
|
340
385
|
dataKey: measure,
|
|
341
386
|
position: horizontal ? "right" : "top",
|
|
342
387
|
formatter: (value) => formats[index]?.(value) ?? "",
|
|
@@ -365,18 +410,26 @@ const lineDomain = ([min, max]) => {
|
|
|
365
410
|
* Barras + linha de uma dimensão, consultando o modelo do `DashboardProvider` (com os filtros dele).
|
|
366
411
|
* Ex.: `<ComboChart dimension="mes" bar="custoTotal" line="custoTon" detail="volTotal" />`.
|
|
367
412
|
*/
|
|
368
|
-
function ComboChart({ dimension, bar, line, detail, barLabel, lineLabel, detailLabel, formatDimension = String, formatBar, formatLine, formatDetail, hideEmpty = true, height = 360, maxLabels = 24, barColor = "#F58220", lineColor = "#555", clickToFilter = false, queryLabel }) {
|
|
413
|
+
function ComboChart({ dimension, bar, line, detail, barLabel, lineLabel, detailLabel, formatDimension = String, formatBar, formatLine, formatDetail, labels, formats, hideEmpty = true, height = 360, maxLabels = 24, barColor = "#F58220", lineColor = "#555", clickToFilter = false, queryLabel }) {
|
|
369
414
|
const { meta, filters, setFilter } = useDashboard();
|
|
370
|
-
const fromModel = (measure,
|
|
371
|
-
const
|
|
372
|
-
|
|
415
|
+
const fromModel = (measure, fallback) => {
|
|
416
|
+
const format = measureFormat(meta, measure, formats);
|
|
417
|
+
const resolved = format?.format ? format : {
|
|
418
|
+
...fallback,
|
|
419
|
+
...format
|
|
420
|
+
};
|
|
421
|
+
return (value) => formatMeasure(value, resolved, fallback.decimals);
|
|
373
422
|
};
|
|
374
|
-
formatBar ??= fromModel(bar,
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
423
|
+
formatBar ??= fromModel(bar, {
|
|
424
|
+
format: "currency",
|
|
425
|
+
decimals: 0
|
|
426
|
+
});
|
|
427
|
+
formatLine ??= fromModel(line, { decimals: 2 });
|
|
428
|
+
formatDetail ??= detail ? fromModel(detail, { decimals: 3 }) : (value) => formatNumber(value, 3);
|
|
429
|
+
barLabel ??= fieldLabel(meta, bar, labels);
|
|
430
|
+
lineLabel ??= fieldLabel(meta, line, labels);
|
|
431
|
+
detailLabel ??= detail && fieldLabel(meta, detail, labels);
|
|
432
|
+
const dimensionLabel = fieldLabel(meta, dimension, labels);
|
|
380
433
|
const { rows, isLoading, error, inspectProps } = useModelQuery({
|
|
381
434
|
dimensions: [dimension],
|
|
382
435
|
measures: detail ? [
|
|
@@ -467,6 +520,13 @@ function ComboChart({ dimension, bar, line, detail, barLabel, lineLabel, detailL
|
|
|
467
520
|
fontSize: 13
|
|
468
521
|
},
|
|
469
522
|
children: [
|
|
523
|
+
/* @__PURE__ */ jsx(Typography, {
|
|
524
|
+
sx: {
|
|
525
|
+
fontSize: 11,
|
|
526
|
+
color: "#777"
|
|
527
|
+
},
|
|
528
|
+
children: dimensionLabel
|
|
529
|
+
}),
|
|
470
530
|
/* @__PURE__ */ jsx(Typography, {
|
|
471
531
|
sx: {
|
|
472
532
|
fontWeight: 700,
|
|
@@ -716,7 +776,6 @@ function DashboardCanvas({ layout, children }) {
|
|
|
716
776
|
const EMPTY = [];
|
|
717
777
|
/** Chave da coluna de percentual de uma medida (ordenação). */
|
|
718
778
|
const PERCENT = "%:";
|
|
719
|
-
const formatPercent = (value) => value === null ? "" : `${formatNumber(value * 100, 1)}%`;
|
|
720
779
|
function compare(a, b) {
|
|
721
780
|
if (typeof a === "number" && typeof b === "number") return a - b;
|
|
722
781
|
return String(a).localeCompare(String(b), "pt-BR", { numeric: true });
|
|
@@ -725,7 +784,7 @@ function compare(a, b) {
|
|
|
725
784
|
* Tabela de medidas por dimensões, com total e ordenação pelo cabeçalho. Ex.:
|
|
726
785
|
* `<DataTable dimensions={['navio']} measures={['volTotal', 'custoTotal', 'custoTon']} />`.
|
|
727
786
|
*/
|
|
728
|
-
function DataTable({ dimensions = EMPTY, measures, percentOf = EMPTY, formatDimensions = {}, showTotal = true, sortBy, sortDirection = "desc", clickToFilter = false, height = 400, queryLabel }) {
|
|
787
|
+
function DataTable({ dimensions = EMPTY, measures, percentOf = EMPTY, formatDimensions = {}, showTotal = true, sortBy, sortDirection = "desc", clickToFilter = false, height = 400, labels, formats: formatsByMeasure, percentDecimals = 1, queryLabel }) {
|
|
729
788
|
const { meta } = useDashboard();
|
|
730
789
|
const name = queryLabel ?? `DataTable · ${dimensions.join(", ") || "total"}`;
|
|
731
790
|
const firstDimension = dimensions[0];
|
|
@@ -763,9 +822,10 @@ function DataTable({ dimensions = EMPTY, measures, percentOf = EMPTY, formatDime
|
|
|
763
822
|
if (y === null || y === void 0) return -1;
|
|
764
823
|
return sort.direction === "asc" ? compare(x, y) : compare(y, x);
|
|
765
824
|
}) : rows;
|
|
766
|
-
const formats = Object.fromEntries(measures.map((measure) => [measure, measureFormatter(meta, measure, 2)]));
|
|
825
|
+
const formats = Object.fromEntries(measures.map((measure) => [measure, measureFormatter(meta, measure, 2, formatsByMeasure)]));
|
|
826
|
+
const formatPercent = (value) => value === null ? "" : `${formatNumber(value * 100, percentDecimals)}%`;
|
|
767
827
|
const dimensionText = (dimension, value) => value === null || value === void 0 ? "(vazio)" : (formatDimensions[dimension] ?? String)(value);
|
|
768
|
-
const labelOf = (column) => meta
|
|
828
|
+
const labelOf = (column) => fieldLabel(meta, column, labels);
|
|
769
829
|
const headerOf = (column) => {
|
|
770
830
|
if (!column.startsWith(PERCENT)) return labelOf(column);
|
|
771
831
|
const measure = column.slice(2);
|
|
@@ -874,7 +934,7 @@ const OTHERS = "Outros";
|
|
|
874
934
|
* Rosca de uma medida por uma dimensão, com o total no centro e a legenda ao lado (nome, % e valor).
|
|
875
935
|
* Ex.: `<DonutChart dimension="operacao_status" measure="custoTotal" />`.
|
|
876
936
|
*/
|
|
877
|
-
function DonutChart({ dimension, measure, maxSlices = 6, formatDimension = String, clickToFilter = false, height = 300, queryLabel }) {
|
|
937
|
+
function DonutChart({ dimension, measure, maxSlices = 6, formatDimension = String, clickToFilter = false, height = 300, labels, formats, percentDecimals = 1, queryLabel }) {
|
|
878
938
|
const { meta } = useDashboard();
|
|
879
939
|
const { rows, isLoading, error, inspectProps } = useModelQuery({
|
|
880
940
|
dimensions: [dimension],
|
|
@@ -883,7 +943,7 @@ function DonutChart({ dimension, measure, maxSlices = 6, formatDimension = Strin
|
|
|
883
943
|
label: queryLabel ?? `DonutChart · ${dimension}`
|
|
884
944
|
});
|
|
885
945
|
const filter = useClickFilter(dimension, clickToFilter);
|
|
886
|
-
const format = measureFormatter(meta, measure, 0);
|
|
946
|
+
const format = measureFormatter(meta, measure, 0, formats);
|
|
887
947
|
const positive = rows.map((row) => ({
|
|
888
948
|
value: row[dimension] ?? "",
|
|
889
949
|
amount: numberOf(row, measure) ?? 0
|
|
@@ -906,7 +966,7 @@ function DonutChart({ dimension, measure, maxSlices = 6, formatDimension = Strin
|
|
|
906
966
|
color: OTHER_COLOR
|
|
907
967
|
});
|
|
908
968
|
const total = slices.reduce((sum, slice) => sum + slice.amount, 0);
|
|
909
|
-
const percent = (amount) => `${formatNumber(amount / total * 100,
|
|
969
|
+
const percent = (amount) => `${formatNumber(amount / total * 100, percentDecimals)}%`;
|
|
910
970
|
const placeholder = chartPlaceholder({
|
|
911
971
|
height,
|
|
912
972
|
error,
|
|
@@ -922,7 +982,10 @@ function DonutChart({ dimension, measure, maxSlices = 6, formatDimension = Strin
|
|
|
922
982
|
const slice = payload[0].payload;
|
|
923
983
|
return /* @__PURE__ */ jsxs(TooltipBox, {
|
|
924
984
|
title: slice.label,
|
|
985
|
+
caption: fieldLabel(meta, dimension, labels),
|
|
925
986
|
children: [
|
|
987
|
+
fieldLabel(meta, measure, labels),
|
|
988
|
+
": ",
|
|
926
989
|
format(slice.amount),
|
|
927
990
|
" · ",
|
|
928
991
|
percent(slice.amount)
|
|
@@ -1067,7 +1130,7 @@ function DonutChart({ dimension, measure, maxSlices = 6, formatDimension = Strin
|
|
|
1067
1130
|
* dimensões: razões (custo/t) saem do total, não de uma média. Ex.:
|
|
1068
1131
|
* `<KpiCard label="Custo total" measure="custoTotal" secondary="custoTon" />`.
|
|
1069
1132
|
*/
|
|
1070
|
-
function KpiCard({ measure, label, secondary, secondaryLabel, queryLabel }) {
|
|
1133
|
+
function KpiCard({ measure, label, secondary, secondaryLabel, labels, formats, queryLabel }) {
|
|
1071
1134
|
const { meta } = useDashboard();
|
|
1072
1135
|
const { rows, isLoading, error, inspectProps } = useModelQuery({
|
|
1073
1136
|
measures: secondary ? [measure, secondary] : [measure],
|
|
@@ -1076,6 +1139,7 @@ function KpiCard({ measure, label, secondary, secondaryLabel, queryLabel }) {
|
|
|
1076
1139
|
const row = rows[0];
|
|
1077
1140
|
const value = row ? numberOf(row, measure) : null;
|
|
1078
1141
|
const extra = row && secondary ? numberOf(row, secondary) : null;
|
|
1142
|
+
label ??= labels?.[measure];
|
|
1079
1143
|
return /* @__PURE__ */ jsxs(Box, {
|
|
1080
1144
|
...inspectProps,
|
|
1081
1145
|
sx: {
|
|
@@ -1112,7 +1176,7 @@ function KpiCard({ measure, label, secondary, secondaryLabel, queryLabel }) {
|
|
|
1112
1176
|
opacity: isLoading ? .5 : 1,
|
|
1113
1177
|
transition: "opacity .2s"
|
|
1114
1178
|
},
|
|
1115
|
-
children: error ? "Erro" : value === null ? "—" : measureFormatter(meta, measure, 0)(value)
|
|
1179
|
+
children: error ? "Erro" : value === null ? "—" : measureFormatter(meta, measure, 0, formats)(value)
|
|
1116
1180
|
}),
|
|
1117
1181
|
secondary && /* @__PURE__ */ jsxs(Box, {
|
|
1118
1182
|
sx: {
|
|
@@ -1122,7 +1186,7 @@ function KpiCard({ measure, label, secondary, secondaryLabel, queryLabel }) {
|
|
|
1122
1186
|
minHeight: 20
|
|
1123
1187
|
},
|
|
1124
1188
|
children: [
|
|
1125
|
-
secondaryLabel ?? meta
|
|
1189
|
+
secondaryLabel ?? fieldLabel(meta, secondary, labels),
|
|
1126
1190
|
":",
|
|
1127
1191
|
" ",
|
|
1128
1192
|
/* @__PURE__ */ jsx(Box, {
|
|
@@ -1131,7 +1195,7 @@ function KpiCard({ measure, label, secondary, secondaryLabel, queryLabel }) {
|
|
|
1131
1195
|
fontWeight: 600,
|
|
1132
1196
|
color: "#444"
|
|
1133
1197
|
},
|
|
1134
|
-
children: extra === null ? "—" : measureFormatter(meta, secondary, 2)(extra)
|
|
1198
|
+
children: extra === null ? "—" : measureFormatter(meta, secondary, 2, formats)(extra)
|
|
1135
1199
|
})
|
|
1136
1200
|
]
|
|
1137
1201
|
})
|
|
@@ -1364,6 +1428,6 @@ function DashboardFilters({ layout, formatters = {}, gap = 2 }) {
|
|
|
1364
1428
|
});
|
|
1365
1429
|
}
|
|
1366
1430
|
//#endregion
|
|
1367
|
-
export { BarChart, ComboChart, DashboardCanvas, DashboardCharts, DashboardFilters, DashboardProvider, DataTable, DonutChart, FilterSelect, INSPECT_ATTRIBUTE, KpiCard, Legend, ModelDictionary, OTHER_COLOR, SERIES_COLORS, TooltipBox, chartPlaceholder, formatCurrency, formatMeasure, formatNumber, measureFormatter, numberOf, seriesColor, useClickFilter, useDashboard, useModelQuery };
|
|
1431
|
+
export { BarChart, ComboChart, DashboardCanvas, DashboardCharts, DashboardFilters, DashboardProvider, DataTable, DonutChart, FilterSelect, INSPECT_ATTRIBUTE, KpiCard, Legend, ModelDictionary, OTHER_COLOR, SERIES_COLORS, TooltipBox, chartPlaceholder, fieldLabel, formatCurrency, formatMeasure, formatNumber, measureFormat, measureFormatter, numberOf, seriesColor, useClickFilter, useDashboard, useModelQuery };
|
|
1368
1432
|
|
|
1369
1433
|
//# sourceMappingURL=index.js.map
|