@bluemarble/bi 0.3.1 → 0.5.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-6v5HDe-A.js} +1046 -298
- package/dist/DashboardDevtools-6v5HDe-A.js.map +1 -0
- package/dist/{ModelDictionary-kUKcdbc8.js → ModelDictionary-D3JzCd6x.js} +81 -5
- package/dist/ModelDictionary-D3JzCd6x.js.map +1 -0
- package/dist/client/index.d.ts +62 -17
- package/dist/client/index.js +87 -90
- package/dist/client/index.js.map +1 -1
- package/dist/{layout-DTR4vI-I.js → layout-QuOYFmp1.js} +111 -35
- package/dist/layout-QuOYFmp1.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-FdrY0FOZ.d.ts} +59 -13
- package/dist/types.d.ts +2 -2
- package/package.json +1 -1
- package/dist/DashboardDevtools-C4E9afPT.js.map +0 -1
- package/dist/ModelDictionary-kUKcdbc8.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
|
|
1
|
+
import { f as isBuiltinChart, h as orderedColumns, o as chartCardStyle, u as customChartProps } from "../layout-QuOYFmp1.js";
|
|
2
|
+
import { a as formatCurrency, c as measureFormat, d as useDashboard, i as fieldLabel, l as measureFormatter, m as layoutItemKey, n as INSPECT_ATTRIBUTE, o as formatMeasure, p as LAYOUT_ITEM_ATTRIBUTE, r as useModelQuery, s as formatNumber, t as ModelDictionary, u as DashboardProvider } from "../ModelDictionary-D3JzCd6x.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,55 +104,23 @@ 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
|
-
//#region src/client/format.ts
|
|
114
|
-
const formatters = /* @__PURE__ */ new Map();
|
|
115
|
-
function formatNumber(value, decimals = 2) {
|
|
116
|
-
if (value === null || value === void 0 || value === "") return "";
|
|
117
|
-
const number = Number(value);
|
|
118
|
-
if (Number.isNaN(number)) return String(value);
|
|
119
|
-
let formatter = formatters.get(decimals);
|
|
120
|
-
if (!formatter) {
|
|
121
|
-
formatter = new Intl.NumberFormat("pt-BR", {
|
|
122
|
-
minimumFractionDigits: decimals,
|
|
123
|
-
maximumFractionDigits: decimals
|
|
124
|
-
});
|
|
125
|
-
formatters.set(decimals, formatter);
|
|
126
|
-
}
|
|
127
|
-
return formatter.format(number);
|
|
128
|
-
}
|
|
129
|
-
const formatCurrency = (value, decimals = 2) => {
|
|
130
|
-
const text = formatNumber(value, decimals);
|
|
131
|
-
return text && `R$ ${text}`;
|
|
132
|
-
};
|
|
133
|
-
/**
|
|
134
|
-
* Formata pelo dicionário do modelo (`format`/`decimals` da medida). `fallbackDecimals` é o padrão
|
|
135
|
-
* do componente quando a medida não define `decimals`.
|
|
136
|
-
*/
|
|
137
|
-
function formatMeasure(value, meta, fallbackDecimals = 2) {
|
|
138
|
-
const decimals = meta?.decimals ?? (meta?.format === "integer" ? 0 : fallbackDecimals);
|
|
139
|
-
switch (meta?.format) {
|
|
140
|
-
case "currency": return formatCurrency(value, decimals);
|
|
141
|
-
case "percent": {
|
|
142
|
-
if (value === null || value === void 0 || value === "") return "";
|
|
143
|
-
const text = formatNumber(Number(value) * 100, decimals);
|
|
144
|
-
return text && `${text}%`;
|
|
145
|
-
}
|
|
146
|
-
default: return formatNumber(value, decimals);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
/** Formatter de uma medida pelo dicionário do modelo; sem `format`, número com `fallbackDecimals`. */
|
|
150
|
-
function measureFormatter(meta, measure, fallbackDecimals = 2) {
|
|
151
|
-
const measureMeta = meta?.measures[measure];
|
|
152
|
-
return (value) => formatMeasure(value, measureMeta, fallbackDecimals);
|
|
153
|
-
}
|
|
154
|
-
//#endregion
|
|
155
124
|
//#region src/client/BarChart.tsx
|
|
156
125
|
const MAX_VALUE_LABELS = 30;
|
|
157
126
|
/** Altura de cada categoria no modo horizontal (barras finas, com respiro). */
|
|
@@ -160,7 +129,7 @@ const ROW_HEIGHT = 28;
|
|
|
160
129
|
* Barras de uma ou mais medidas por uma dimensão. Ex.:
|
|
161
130
|
* `<BarChart dimension="navio" measures={['custoTotal']} orientation="horizontal" sort="desc" limit={10} />`.
|
|
162
131
|
*/
|
|
163
|
-
function BarChart({ dimension, measures, orientation = "vertical", stacked = false, sort = "dimension", limit, formatDimension = String, hideEmpty = true, showValues = true, clickToFilter = false, height = 360, queryLabel }) {
|
|
132
|
+
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
133
|
const { meta } = useDashboard();
|
|
165
134
|
const { rows, isLoading, error, inspectProps } = useModelQuery({
|
|
166
135
|
dimensions: [dimension],
|
|
@@ -169,8 +138,13 @@ function BarChart({ dimension, measures, orientation = "vertical", stacked = fal
|
|
|
169
138
|
label: queryLabel ?? `BarChart · ${dimension}`
|
|
170
139
|
});
|
|
171
140
|
const filter = useClickFilter(dimension, clickToFilter);
|
|
172
|
-
const formats = measures.map((measure) => measureFormatter(meta, measure, 0));
|
|
173
|
-
const labelOf = (
|
|
141
|
+
const formats = measures.map((measure) => measureFormatter(meta, measure, 0, formatsByMeasure));
|
|
142
|
+
const labelOf = (name) => fieldLabel(meta, name, labels);
|
|
143
|
+
const axisFormat = measures[0] ? measureFormat(meta, measures[0], formatsByMeasure) : void 0;
|
|
144
|
+
const formatTick = (value) => formatMeasure(value, {
|
|
145
|
+
...axisFormat,
|
|
146
|
+
decimals: axisFormat?.compact ? 1 : 0
|
|
147
|
+
}, 0);
|
|
174
148
|
const first = measures[0];
|
|
175
149
|
let data = rows.filter((row) => !hideEmpty || measures.some((measure) => numberOf(row, measure))).map((row) => {
|
|
176
150
|
const value = row[dimension] ?? "";
|
|
@@ -184,7 +158,7 @@ function BarChart({ dimension, measures, orientation = "vertical", stacked = fal
|
|
|
184
158
|
if (sort !== "dimension" && first) data = [...data].sort((a, b) => sort === "desc" ? Number(b[first]) - Number(a[first]) : Number(a[first]) - Number(b[first]));
|
|
185
159
|
if (limit) data = data.slice(0, limit);
|
|
186
160
|
const horizontal = orientation === "horizontal";
|
|
187
|
-
const
|
|
161
|
+
const showLabels = showValues && data.length <= MAX_VALUE_LABELS;
|
|
188
162
|
const chartHeight = horizontal ? Math.max(height, data.length * ROW_HEIGHT + 24) : height;
|
|
189
163
|
const longest = Math.max(0, ...data.map((point) => point.label.length));
|
|
190
164
|
const state = chartPlaceholder({
|
|
@@ -198,6 +172,7 @@ function BarChart({ dimension, measures, orientation = "vertical", stacked = fal
|
|
|
198
172
|
const point = payload[0].payload;
|
|
199
173
|
return /* @__PURE__ */ jsx(TooltipBox, {
|
|
200
174
|
title: point.label,
|
|
175
|
+
caption: labelOf(dimension),
|
|
201
176
|
children: measures.map((measure, index) => /* @__PURE__ */ jsxs(Box, {
|
|
202
177
|
sx: {
|
|
203
178
|
display: "flex",
|
|
@@ -271,11 +246,11 @@ function BarChart({ dimension, measures, orientation = "vertical", stacked = fal
|
|
|
271
246
|
barCategoryGap: "20%",
|
|
272
247
|
margin: horizontal ? {
|
|
273
248
|
top: 4,
|
|
274
|
-
right:
|
|
249
|
+
right: showLabels ? 96 : 16,
|
|
275
250
|
left: 8,
|
|
276
251
|
bottom: 4
|
|
277
252
|
} : {
|
|
278
|
-
top:
|
|
253
|
+
top: showLabels ? 24 : 8,
|
|
279
254
|
right: 8,
|
|
280
255
|
left: 8,
|
|
281
256
|
bottom: 0
|
|
@@ -288,11 +263,12 @@ function BarChart({ dimension, measures, orientation = "vertical", stacked = fal
|
|
|
288
263
|
}),
|
|
289
264
|
horizontal ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(XAxis, {
|
|
290
265
|
type: "number",
|
|
291
|
-
hide:
|
|
266
|
+
hide: showLabels,
|
|
292
267
|
tick: {
|
|
293
268
|
fontSize: 12,
|
|
294
269
|
fill: "#555"
|
|
295
|
-
}
|
|
270
|
+
},
|
|
271
|
+
tickFormatter: formatTick
|
|
296
272
|
}), /* @__PURE__ */ jsx(YAxis, {
|
|
297
273
|
type: "category",
|
|
298
274
|
dataKey: "label",
|
|
@@ -314,12 +290,12 @@ function BarChart({ dimension, measures, orientation = "vertical", stacked = fal
|
|
|
314
290
|
tickLine: false,
|
|
315
291
|
axisLine: { stroke: "#ccc" }
|
|
316
292
|
}), /* @__PURE__ */ jsx(YAxis, {
|
|
317
|
-
hide:
|
|
293
|
+
hide: showLabels,
|
|
318
294
|
tick: {
|
|
319
295
|
fontSize: 12,
|
|
320
296
|
fill: "#555"
|
|
321
297
|
},
|
|
322
|
-
tickFormatter:
|
|
298
|
+
tickFormatter: formatTick,
|
|
323
299
|
width: 72
|
|
324
300
|
})] }),
|
|
325
301
|
/* @__PURE__ */ jsx(Tooltip$1, {
|
|
@@ -336,7 +312,7 @@ function BarChart({ dimension, measures, orientation = "vertical", stacked = fal
|
|
|
336
312
|
isAnimationActive: false,
|
|
337
313
|
onClick: clickToFilter ? (_bar, barIndex, event) => handleClick(barIndex, event) : void 0,
|
|
338
314
|
cursor: clickToFilter ? "pointer" : void 0,
|
|
339
|
-
children: [clickToFilter && data.map((point) => /* @__PURE__ */ jsx(Cell, { fillOpacity: filter.isDimmed(point.value) ? .35 : 1 }, String(point.value))),
|
|
315
|
+
children: [clickToFilter && data.map((point) => /* @__PURE__ */ jsx(Cell, { fillOpacity: filter.isDimmed(point.value) ? .35 : 1 }, String(point.value))), showLabels && !stacked && /* @__PURE__ */ jsx(LabelList, {
|
|
340
316
|
dataKey: measure,
|
|
341
317
|
position: horizontal ? "right" : "top",
|
|
342
318
|
formatter: (value) => formats[index]?.(value) ?? "",
|
|
@@ -365,18 +341,26 @@ const lineDomain = ([min, max]) => {
|
|
|
365
341
|
* Barras + linha de uma dimensão, consultando o modelo do `DashboardProvider` (com os filtros dele).
|
|
366
342
|
* Ex.: `<ComboChart dimension="mes" bar="custoTotal" line="custoTon" detail="volTotal" />`.
|
|
367
343
|
*/
|
|
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 }) {
|
|
344
|
+
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
345
|
const { meta, filters, setFilter } = useDashboard();
|
|
370
|
-
const fromModel = (measure,
|
|
371
|
-
const
|
|
372
|
-
|
|
346
|
+
const fromModel = (measure, fallback) => {
|
|
347
|
+
const format = measureFormat(meta, measure, formats);
|
|
348
|
+
const resolved = format?.format ? format : {
|
|
349
|
+
...fallback,
|
|
350
|
+
...format
|
|
351
|
+
};
|
|
352
|
+
return (value) => formatMeasure(value, resolved, fallback.decimals);
|
|
373
353
|
};
|
|
374
|
-
formatBar ??= fromModel(bar,
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
354
|
+
formatBar ??= fromModel(bar, {
|
|
355
|
+
format: "currency",
|
|
356
|
+
decimals: 0
|
|
357
|
+
});
|
|
358
|
+
formatLine ??= fromModel(line, { decimals: 2 });
|
|
359
|
+
formatDetail ??= detail ? fromModel(detail, { decimals: 3 }) : (value) => formatNumber(value, 3);
|
|
360
|
+
barLabel ??= fieldLabel(meta, bar, labels);
|
|
361
|
+
lineLabel ??= fieldLabel(meta, line, labels);
|
|
362
|
+
detailLabel ??= detail && fieldLabel(meta, detail, labels);
|
|
363
|
+
const dimensionLabel = fieldLabel(meta, dimension, labels);
|
|
380
364
|
const { rows, isLoading, error, inspectProps } = useModelQuery({
|
|
381
365
|
dimensions: [dimension],
|
|
382
366
|
measures: detail ? [
|
|
@@ -467,6 +451,13 @@ function ComboChart({ dimension, bar, line, detail, barLabel, lineLabel, detailL
|
|
|
467
451
|
fontSize: 13
|
|
468
452
|
},
|
|
469
453
|
children: [
|
|
454
|
+
/* @__PURE__ */ jsx(Typography, {
|
|
455
|
+
sx: {
|
|
456
|
+
fontSize: 11,
|
|
457
|
+
color: "#777"
|
|
458
|
+
},
|
|
459
|
+
children: dimensionLabel
|
|
460
|
+
}),
|
|
470
461
|
/* @__PURE__ */ jsx(Typography, {
|
|
471
462
|
sx: {
|
|
472
463
|
fontWeight: 700,
|
|
@@ -716,7 +707,6 @@ function DashboardCanvas({ layout, children }) {
|
|
|
716
707
|
const EMPTY = [];
|
|
717
708
|
/** Chave da coluna de percentual de uma medida (ordenação). */
|
|
718
709
|
const PERCENT = "%:";
|
|
719
|
-
const formatPercent = (value) => value === null ? "" : `${formatNumber(value * 100, 1)}%`;
|
|
720
710
|
function compare(a, b) {
|
|
721
711
|
if (typeof a === "number" && typeof b === "number") return a - b;
|
|
722
712
|
return String(a).localeCompare(String(b), "pt-BR", { numeric: true });
|
|
@@ -725,7 +715,7 @@ function compare(a, b) {
|
|
|
725
715
|
* Tabela de medidas por dimensões, com total e ordenação pelo cabeçalho. Ex.:
|
|
726
716
|
* `<DataTable dimensions={['navio']} measures={['volTotal', 'custoTotal', 'custoTon']} />`.
|
|
727
717
|
*/
|
|
728
|
-
function DataTable({ dimensions = EMPTY, measures, percentOf = EMPTY, formatDimensions = {}, showTotal = true, sortBy, sortDirection = "desc", clickToFilter = false, height = 400, queryLabel }) {
|
|
718
|
+
function DataTable({ dimensions = EMPTY, measures, percentOf = EMPTY, formatDimensions = {}, showTotal = true, sortBy, sortDirection = "desc", clickToFilter = false, height = 400, labels, formats: formatsByMeasure, percentDecimals = 1, columnOrder, queryLabel }) {
|
|
729
719
|
const { meta } = useDashboard();
|
|
730
720
|
const name = queryLabel ?? `DataTable · ${dimensions.join(", ") || "total"}`;
|
|
731
721
|
const firstDimension = dimensions[0];
|
|
@@ -763,9 +753,10 @@ function DataTable({ dimensions = EMPTY, measures, percentOf = EMPTY, formatDime
|
|
|
763
753
|
if (y === null || y === void 0) return -1;
|
|
764
754
|
return sort.direction === "asc" ? compare(x, y) : compare(y, x);
|
|
765
755
|
}) : rows;
|
|
766
|
-
const formats = Object.fromEntries(measures.map((measure) => [measure, measureFormatter(meta, measure, 2)]));
|
|
756
|
+
const formats = Object.fromEntries(measures.map((measure) => [measure, measureFormatter(meta, measure, 2, formatsByMeasure)]));
|
|
757
|
+
const formatPercent = (value) => value === null ? "" : `${formatNumber(value * 100, percentDecimals)}%`;
|
|
767
758
|
const dimensionText = (dimension, value) => value === null || value === void 0 ? "(vazio)" : (formatDimensions[dimension] ?? String)(value);
|
|
768
|
-
const labelOf = (column) => meta
|
|
759
|
+
const labelOf = (column) => fieldLabel(meta, column, labels);
|
|
769
760
|
const headerOf = (column) => {
|
|
770
761
|
if (!column.startsWith(PERCENT)) return labelOf(column);
|
|
771
762
|
const measure = column.slice(2);
|
|
@@ -777,7 +768,9 @@ function DataTable({ dimensions = EMPTY, measures, percentOf = EMPTY, formatDime
|
|
|
777
768
|
const total = sums[measure];
|
|
778
769
|
return value === null || value === void 0 || !total ? null : Number(value) / total;
|
|
779
770
|
};
|
|
780
|
-
const
|
|
771
|
+
const columns = [...orderedColumns([...dimensions, ...measures], columnOrder).flatMap((column) => percentOf.includes(column) && !dimensions.includes(column) ? [column, `${PERCENT}${column}`] : [column]), ...extraMeasures.map((measure) => `${PERCENT}${measure}`)];
|
|
772
|
+
const isDimension = (column) => dimensions.includes(column);
|
|
773
|
+
const totalLabelColumn = columns.find(isDimension);
|
|
781
774
|
const cellText = (row, column) => column.startsWith(PERCENT) ? formatPercent(percentOfRow(row, column.slice(2))) : formats[column]?.(row[column]);
|
|
782
775
|
const toggleSort = (column) => setSort((current) => current.by === column ? {
|
|
783
776
|
by: column,
|
|
@@ -832,10 +825,10 @@ function DataTable({ dimensions = EMPTY, measures, percentOf = EMPTY, formatDime
|
|
|
832
825
|
size: "small",
|
|
833
826
|
stickyHeader: true,
|
|
834
827
|
sx: { "& td, & th": { fontSize: 13 } },
|
|
835
|
-
children: [/* @__PURE__ */ jsx(TableHead, { children: /* @__PURE__ */
|
|
828
|
+
children: [/* @__PURE__ */ jsx(TableHead, { children: /* @__PURE__ */ jsx(TableRow, { children: columns.map((column) => header(column, !isDimension(column))) }) }), /* @__PURE__ */ jsxs(TableBody, { children: [sorted.map((row) => {
|
|
836
829
|
const value = firstDimension ? row[firstDimension] : null;
|
|
837
830
|
const clickable = clickToFilter && value !== null && value !== void 0;
|
|
838
|
-
return /* @__PURE__ */
|
|
831
|
+
return /* @__PURE__ */ jsx(TableRow, {
|
|
839
832
|
hover: true,
|
|
840
833
|
onClick: clickable ? (event) => filter.toggle(value, event) : void 0,
|
|
841
834
|
selected: clickable && filter.selected.includes(value),
|
|
@@ -843,13 +836,13 @@ function DataTable({ dimensions = EMPTY, measures, percentOf = EMPTY, formatDime
|
|
|
843
836
|
cursor: clickable ? "pointer" : void 0,
|
|
844
837
|
opacity: clickable && filter.isDimmed(value) ? .5 : 1
|
|
845
838
|
},
|
|
846
|
-
children:
|
|
839
|
+
children: columns.map((column) => isDimension(column) ? /* @__PURE__ */ jsx(TableCell, { children: dimensionText(column, row[column]) }, column) : /* @__PURE__ */ jsx(TableCell, {
|
|
847
840
|
align: "right",
|
|
848
841
|
sx: { whiteSpace: "nowrap" },
|
|
849
842
|
children: cellText(row, column)
|
|
850
|
-
}, column))
|
|
843
|
+
}, column))
|
|
851
844
|
}, dimensions.map((dimension) => String(row[dimension])).join("\0"));
|
|
852
|
-
}), totalRow && /* @__PURE__ */
|
|
845
|
+
}), totalRow && /* @__PURE__ */ jsx(TableRow, {
|
|
853
846
|
sx: { "& td": {
|
|
854
847
|
fontWeight: 700,
|
|
855
848
|
position: "sticky",
|
|
@@ -857,11 +850,11 @@ function DataTable({ dimensions = EMPTY, measures, percentOf = EMPTY, formatDime
|
|
|
857
850
|
bgcolor: "#f3f3f3",
|
|
858
851
|
borderTop: "2px solid #ddd"
|
|
859
852
|
} },
|
|
860
|
-
children:
|
|
853
|
+
children: columns.map((column) => isDimension(column) ? /* @__PURE__ */ jsx(TableCell, { children: column === totalLabelColumn ? "Total" : "" }, column) : /* @__PURE__ */ jsx(TableCell, {
|
|
861
854
|
align: "right",
|
|
862
855
|
sx: { whiteSpace: "nowrap" },
|
|
863
856
|
children: column.startsWith(PERCENT) ? formatPercent(sums[column.slice(2)] ? 1 : null) : formats[column]?.(totalRow[column])
|
|
864
|
-
}, column))
|
|
857
|
+
}, column))
|
|
865
858
|
})] })]
|
|
866
859
|
})
|
|
867
860
|
})]
|
|
@@ -874,7 +867,7 @@ const OTHERS = "Outros";
|
|
|
874
867
|
* Rosca de uma medida por uma dimensão, com o total no centro e a legenda ao lado (nome, % e valor).
|
|
875
868
|
* Ex.: `<DonutChart dimension="operacao_status" measure="custoTotal" />`.
|
|
876
869
|
*/
|
|
877
|
-
function DonutChart({ dimension, measure, maxSlices = 6, formatDimension = String, clickToFilter = false, height = 300, queryLabel }) {
|
|
870
|
+
function DonutChart({ dimension, measure, maxSlices = 6, formatDimension = String, clickToFilter = false, height = 300, labels, formats, percentDecimals = 1, queryLabel }) {
|
|
878
871
|
const { meta } = useDashboard();
|
|
879
872
|
const { rows, isLoading, error, inspectProps } = useModelQuery({
|
|
880
873
|
dimensions: [dimension],
|
|
@@ -883,7 +876,7 @@ function DonutChart({ dimension, measure, maxSlices = 6, formatDimension = Strin
|
|
|
883
876
|
label: queryLabel ?? `DonutChart · ${dimension}`
|
|
884
877
|
});
|
|
885
878
|
const filter = useClickFilter(dimension, clickToFilter);
|
|
886
|
-
const format = measureFormatter(meta, measure, 0);
|
|
879
|
+
const format = measureFormatter(meta, measure, 0, formats);
|
|
887
880
|
const positive = rows.map((row) => ({
|
|
888
881
|
value: row[dimension] ?? "",
|
|
889
882
|
amount: numberOf(row, measure) ?? 0
|
|
@@ -906,7 +899,7 @@ function DonutChart({ dimension, measure, maxSlices = 6, formatDimension = Strin
|
|
|
906
899
|
color: OTHER_COLOR
|
|
907
900
|
});
|
|
908
901
|
const total = slices.reduce((sum, slice) => sum + slice.amount, 0);
|
|
909
|
-
const percent = (amount) => `${formatNumber(amount / total * 100,
|
|
902
|
+
const percent = (amount) => `${formatNumber(amount / total * 100, percentDecimals)}%`;
|
|
910
903
|
const placeholder = chartPlaceholder({
|
|
911
904
|
height,
|
|
912
905
|
error,
|
|
@@ -922,7 +915,10 @@ function DonutChart({ dimension, measure, maxSlices = 6, formatDimension = Strin
|
|
|
922
915
|
const slice = payload[0].payload;
|
|
923
916
|
return /* @__PURE__ */ jsxs(TooltipBox, {
|
|
924
917
|
title: slice.label,
|
|
918
|
+
caption: fieldLabel(meta, dimension, labels),
|
|
925
919
|
children: [
|
|
920
|
+
fieldLabel(meta, measure, labels),
|
|
921
|
+
": ",
|
|
926
922
|
format(slice.amount),
|
|
927
923
|
" · ",
|
|
928
924
|
percent(slice.amount)
|
|
@@ -1067,7 +1063,7 @@ function DonutChart({ dimension, measure, maxSlices = 6, formatDimension = Strin
|
|
|
1067
1063
|
* dimensões: razões (custo/t) saem do total, não de uma média. Ex.:
|
|
1068
1064
|
* `<KpiCard label="Custo total" measure="custoTotal" secondary="custoTon" />`.
|
|
1069
1065
|
*/
|
|
1070
|
-
function KpiCard({ measure, label, secondary, secondaryLabel, queryLabel }) {
|
|
1066
|
+
function KpiCard({ measure, label, secondary, secondaryLabel, labels, formats, queryLabel }) {
|
|
1071
1067
|
const { meta } = useDashboard();
|
|
1072
1068
|
const { rows, isLoading, error, inspectProps } = useModelQuery({
|
|
1073
1069
|
measures: secondary ? [measure, secondary] : [measure],
|
|
@@ -1076,6 +1072,7 @@ function KpiCard({ measure, label, secondary, secondaryLabel, queryLabel }) {
|
|
|
1076
1072
|
const row = rows[0];
|
|
1077
1073
|
const value = row ? numberOf(row, measure) : null;
|
|
1078
1074
|
const extra = row && secondary ? numberOf(row, secondary) : null;
|
|
1075
|
+
label ??= labels?.[measure];
|
|
1079
1076
|
return /* @__PURE__ */ jsxs(Box, {
|
|
1080
1077
|
...inspectProps,
|
|
1081
1078
|
sx: {
|
|
@@ -1112,7 +1109,7 @@ function KpiCard({ measure, label, secondary, secondaryLabel, queryLabel }) {
|
|
|
1112
1109
|
opacity: isLoading ? .5 : 1,
|
|
1113
1110
|
transition: "opacity .2s"
|
|
1114
1111
|
},
|
|
1115
|
-
children: error ? "Erro" : value === null ? "—" : measureFormatter(meta, measure, 0)(value)
|
|
1112
|
+
children: error ? "Erro" : value === null ? "—" : measureFormatter(meta, measure, 0, formats)(value)
|
|
1116
1113
|
}),
|
|
1117
1114
|
secondary && /* @__PURE__ */ jsxs(Box, {
|
|
1118
1115
|
sx: {
|
|
@@ -1122,7 +1119,7 @@ function KpiCard({ measure, label, secondary, secondaryLabel, queryLabel }) {
|
|
|
1122
1119
|
minHeight: 20
|
|
1123
1120
|
},
|
|
1124
1121
|
children: [
|
|
1125
|
-
secondaryLabel ?? meta
|
|
1122
|
+
secondaryLabel ?? fieldLabel(meta, secondary, labels),
|
|
1126
1123
|
":",
|
|
1127
1124
|
" ",
|
|
1128
1125
|
/* @__PURE__ */ jsx(Box, {
|
|
@@ -1131,7 +1128,7 @@ function KpiCard({ measure, label, secondary, secondaryLabel, queryLabel }) {
|
|
|
1131
1128
|
fontWeight: 600,
|
|
1132
1129
|
color: "#444"
|
|
1133
1130
|
},
|
|
1134
|
-
children: extra === null ? "—" : measureFormatter(meta, secondary, 2)(extra)
|
|
1131
|
+
children: extra === null ? "—" : measureFormatter(meta, secondary, 2, formats)(extra)
|
|
1135
1132
|
})
|
|
1136
1133
|
]
|
|
1137
1134
|
})
|
|
@@ -1364,6 +1361,6 @@ function DashboardFilters({ layout, formatters = {}, gap = 2 }) {
|
|
|
1364
1361
|
});
|
|
1365
1362
|
}
|
|
1366
1363
|
//#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 };
|
|
1364
|
+
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
1365
|
|
|
1369
1366
|
//# sourceMappingURL=index.js.map
|