@bluemarble/bi 0.8.0 → 0.8.1
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 +77 -77
- package/dist/{DashboardDevtools-wk4vMfhy.js → DashboardDevtools-TFwjFdqn.js} +139 -14
- package/dist/DashboardDevtools-TFwjFdqn.js.map +1 -0
- package/dist/{ModelDictionary-DZiYK1mV.js → ModelDictionary-g5d84D0n.js} +13 -4
- package/dist/ModelDictionary-g5d84D0n.js.map +1 -0
- package/dist/cli.js +0 -0
- package/dist/cli.js.map +1 -1
- package/dist/client/index.d.ts +34 -7
- package/dist/client/index.js +184 -45
- package/dist/client/index.js.map +1 -1
- package/dist/codegen-LoQzFAle.js.map +1 -1
- package/dist/compare-DloZhg1T.js.map +1 -1
- package/dist/{formatRules-DXMHY9tU.d.ts → formatRules-C1PW2EiL.d.ts} +61 -1
- package/dist/{layout-BS3nO6OT.js → layout-BuZhfoRI.js} +167 -15
- package/dist/layout-BuZhfoRI.js.map +1 -0
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/package.json +81 -81
- package/dist/DashboardDevtools-wk4vMfhy.js.map +0 -1
- package/dist/ModelDictionary-DZiYK1mV.js.map +0 -1
- package/dist/layout-BS3nO6OT.js.map +0 -1
package/dist/client/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { A as
|
|
2
|
-
import { C as useDashboard, E as layoutItemKey, S as DashboardProvider, T as LAYOUT_ITEM_ATTRIBUTE, _ as TooltipBox, a as fieldLabel, b as seriesColor, c as formatNumber, d as toDate, f as toMonthName, g as SERIES_COLORS, h as OTHER_COLOR, i as BUILTIN_FORMATTERS, l as measureFormat, m as Legend, n as INSPECT_ATTRIBUTE, o as formatCurrency, p as withBuiltinFormatters, r as useModelQuery, s as formatMeasure, t as ModelDictionary, u as measureFormatter, v as chartPlaceholder, x as useClickFilter, y as numberOf } from "../ModelDictionary-
|
|
1
|
+
import { A as colorScaleStyles, M as matchesValueRule, N as rowRuleStyles, _ as percentColumn, c as chartCardStyle, f as customChartProps, j as contrastText, m as isBuiltinChart, s as cardsGap, y as tableColumns } from "../layout-BuZhfoRI.js";
|
|
2
|
+
import { C as useDashboard, E as layoutItemKey, S as DashboardProvider, T as LAYOUT_ITEM_ATTRIBUTE, _ as TooltipBox, a as fieldLabel, b as seriesColor, c as formatNumber, d as toDate, f as toMonthName, g as SERIES_COLORS, h as OTHER_COLOR, i as BUILTIN_FORMATTERS, l as measureFormat, m as Legend, n as INSPECT_ATTRIBUTE, o as formatCurrency, p as withBuiltinFormatters, r as useModelQuery, s as formatMeasure, t as ModelDictionary, u as measureFormatter, v as chartPlaceholder, x as useClickFilter, y as numberOf } from "../ModelDictionary-g5d84D0n.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
|
-
import { createContext, useContext, useEffect, useLayoutEffect, useRef, useState, useSyncExternalStore } from "react";
|
|
5
|
+
import { createContext, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
6
6
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
7
|
//#region src/client/seriesPivot.ts
|
|
8
8
|
const EMPTY_SERIES_LABEL = "(em branco)";
|
|
@@ -134,14 +134,15 @@ const ROW_HEIGHT = 28;
|
|
|
134
134
|
* Com `series`, uma medida quebrada pelos valores de outra dimensão:
|
|
135
135
|
* `<BarChart dimension="mes" series="tipo_descarga" measures={['volume']} stacked />`.
|
|
136
136
|
*/
|
|
137
|
-
function BarChart({ dimension, measures: measureList, series, formatSeries = String, maxSeries = 6, orientation = "vertical", stacked = false, sort = "dimension", limit, formatDimension = String, hideEmpty = true, showEmpty = false, showValues = true, valuePosition = "outside", valueColor, valueSize = 12, showTotal = false, valueRule, hideUnselected = false, colors, clickToFilter = false, height = 360, labels, formats: formatsByMeasure, queryLabel }) {
|
|
137
|
+
function BarChart({ dimension, measures: measureList, series, formatSeries = String, maxSeries = 6, orientation = "vertical", stacked = false, sort = "dimension", limit, formatDimension = String, hideEmpty = true, showEmpty = false, showValues = true, valuePosition = "outside", valueColor, valueSize = 12, showTotal = false, valueRule, hideUnselected = false, colors, clickToFilter = false, height = 360, labels, formats: formatsByMeasure, ignoreFilters, queryLabel }) {
|
|
138
138
|
const { meta, filters, setFilter } = useDashboard();
|
|
139
139
|
const dimming = clickToFilter && !hideUnselected;
|
|
140
|
+
const configuredIgnore = ignoreFilters ?? [];
|
|
140
141
|
const measures = series ? measureList.slice(0, 1) : measureList;
|
|
141
142
|
const { rows, isLoading, error, inspectProps } = useModelQuery({
|
|
142
143
|
dimensions: series ? [dimension, series] : [dimension],
|
|
143
144
|
measures,
|
|
144
|
-
ignoreFilters: dimming ? series ? [dimension, series] : [dimension] :
|
|
145
|
+
ignoreFilters: [...configuredIgnore, ...dimming ? series ? [dimension, series] : [dimension] : []],
|
|
145
146
|
label: queryLabel ?? `BarChart · ${dimension}`
|
|
146
147
|
});
|
|
147
148
|
const domain = useModelQuery({
|
|
@@ -154,7 +155,7 @@ function BarChart({ dimension, measures: measureList, series, formatSeries = Str
|
|
|
154
155
|
const table = meta?.dimensions[dimension]?.table;
|
|
155
156
|
const categories = useModelQuery({
|
|
156
157
|
dimensions: [dimension],
|
|
157
|
-
ignoreFilters: Object.keys(filters).filter((name) => dimming && name === dimension || !table || meta?.dimensions[name]?.table !== table),
|
|
158
|
+
ignoreFilters: Object.keys(filters).filter((name) => configuredIgnore.includes(name) || dimming && name === dimension || !table || meta?.dimensions[name]?.table !== table),
|
|
158
159
|
label: `${queryLabel ?? `BarChart · ${dimension}`} · categorias`,
|
|
159
160
|
skip: !showEmpty || !meta
|
|
160
161
|
});
|
|
@@ -454,8 +455,9 @@ const lineDomain = ([min, max]) => {
|
|
|
454
455
|
* Barras + linha de uma dimensão, consultando o modelo do `DashboardProvider` (com os filtros dele).
|
|
455
456
|
* Ex.: `<ComboChart dimension="mes" bar="custoTotal" line="custoTon" detail="volTotal" />`.
|
|
456
457
|
*/
|
|
457
|
-
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 }) {
|
|
458
|
+
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, ignoreFilters, queryLabel }) {
|
|
458
459
|
const { meta, filters, setFilter } = useDashboard();
|
|
460
|
+
const ignore = [...ignoreFilters ?? [], ...clickToFilter ? [dimension] : []];
|
|
459
461
|
const fromModel = (measure, fallback) => {
|
|
460
462
|
const format = measureFormat(meta, measure, formats);
|
|
461
463
|
const resolved = format?.format ? format : {
|
|
@@ -481,7 +483,7 @@ function ComboChart({ dimension, bar, line, detail, barLabel, lineLabel, detailL
|
|
|
481
483
|
line,
|
|
482
484
|
detail
|
|
483
485
|
] : [bar, line],
|
|
484
|
-
ignoreFilters:
|
|
486
|
+
ignoreFilters: ignore.length ? ignore : void 0,
|
|
485
487
|
label: queryLabel ?? `ComboChart · ${dimension}`
|
|
486
488
|
});
|
|
487
489
|
const num = (row, key) => key && row[key] !== null && row[key] !== void 0 ? Number(row[key]) : null;
|
|
@@ -828,11 +830,12 @@ function compare(a, b) {
|
|
|
828
830
|
* Tabela de medidas por dimensões, com total e ordenação pelo cabeçalho. Ex.:
|
|
829
831
|
* `<DataTable dimensions={['navio']} measures={['volTotal', 'custoTotal', 'custoTon']} />`.
|
|
830
832
|
*/
|
|
831
|
-
function DataTable({ dimensions = EMPTY, measures, percentOf = EMPTY, formatDimensions = {}, showTotal = true, sortBy, sortDirection = "desc", clickToFilter = false, height = 400, labels, formats: formatsByMeasure, percentDecimals = 1, columnOrder, formatRules = NO_RULES, colorScales = NO_SCALES, cellBorders = false, borderColor = "#e0e0e0", align, verticalAlign, queryLabel }) {
|
|
833
|
+
function DataTable({ dimensions = EMPTY, measures, percentOf = EMPTY, formatDimensions = {}, showTotal = true, sortBy, sortDirection = "desc", clickToFilter = false, height = 400, labels, formats: formatsByMeasure, percentDecimals = 1, columnOrder, formatRules = NO_RULES, colorScales = NO_SCALES, cellBorders = false, borderColor = "#e0e0e0", align, verticalAlign, cellPadding, fontSize = 13, ignoreFilters: ignoreProp = EMPTY, queryLabel }) {
|
|
832
834
|
const { meta } = useDashboard();
|
|
833
835
|
const name = queryLabel ?? `DataTable · ${dimensions.join(", ") || "total"}`;
|
|
834
836
|
const firstDimension = dimensions[0];
|
|
835
|
-
const
|
|
837
|
+
const ignore = [...ignoreProp, ...clickToFilter && firstDimension ? [firstDimension] : []];
|
|
838
|
+
const ignoreFilters = ignore.length ? ignore : void 0;
|
|
836
839
|
const extraMeasures = percentOf.filter((measure) => !measures.includes(measure));
|
|
837
840
|
const outside = [...new Set([sortBy, ...formatRules.map((rule) => rule.field)].filter(Boolean))].filter((field) => !field.startsWith("%:") && !dimensions.includes(field) && !measures.includes(field) && !extraMeasures.includes(field));
|
|
838
841
|
const waitingMeta = outside.length > 0 && !meta;
|
|
@@ -928,6 +931,8 @@ function DataTable({ dimensions = EMPTY, measures, percentOf = EMPTY, formatDime
|
|
|
928
931
|
const verticalOf = (column) => verticalAlign?.[column] ?? "middle";
|
|
929
932
|
const totalLabelColumn = columns.find(isDimension);
|
|
930
933
|
const cellText = (row, column) => column.startsWith("%:") ? formatPercent(percentOfRow(row, column.slice(2))) : formats[column]?.(row[column]);
|
|
934
|
+
const cellPaddingValue = cellPadding ?? 8;
|
|
935
|
+
const cellPaddingStyle = typeof cellPaddingValue === "number" ? `${cellPaddingValue}px` : cellPaddingValue;
|
|
931
936
|
const toggleSort = (column) => setSort((current) => current.by === column ? {
|
|
932
937
|
by: column,
|
|
933
938
|
direction: current.direction === "asc" ? "desc" : "asc"
|
|
@@ -983,7 +988,7 @@ function DataTable({ dimensions = EMPTY, measures, percentOf = EMPTY, formatDime
|
|
|
983
988
|
size: "small",
|
|
984
989
|
stickyHeader: true,
|
|
985
990
|
sx: { "& td, & th": {
|
|
986
|
-
fontSize
|
|
991
|
+
fontSize,
|
|
987
992
|
...cellBorders && { border: `1px solid ${borderColor}` }
|
|
988
993
|
} },
|
|
989
994
|
children: [/* @__PURE__ */ jsx(TableHead, { children: /* @__PURE__ */ jsx(TableRow, { children: columns.map((column) => header(column, !isDimension(column))) }) }), /* @__PURE__ */ jsxs(TableBody, { children: [sorted.map((row) => {
|
|
@@ -1002,6 +1007,8 @@ function DataTable({ dimensions = EMPTY, measures, percentOf = EMPTY, formatDime
|
|
|
1002
1007
|
align: alignOf(column),
|
|
1003
1008
|
sx: {
|
|
1004
1009
|
verticalAlign: verticalOf(column),
|
|
1010
|
+
paddingTop: cellPaddingStyle,
|
|
1011
|
+
paddingBottom: cellPaddingStyle,
|
|
1005
1012
|
...ruleSx(styles?.[column])
|
|
1006
1013
|
},
|
|
1007
1014
|
children: dimensionText(column, row[column])
|
|
@@ -1010,6 +1017,8 @@ function DataTable({ dimensions = EMPTY, measures, percentOf = EMPTY, formatDime
|
|
|
1010
1017
|
sx: {
|
|
1011
1018
|
whiteSpace: "nowrap",
|
|
1012
1019
|
verticalAlign: verticalOf(column),
|
|
1020
|
+
paddingTop: cellPaddingStyle,
|
|
1021
|
+
paddingBottom: cellPaddingStyle,
|
|
1013
1022
|
...ruleSx(styles?.[column])
|
|
1014
1023
|
},
|
|
1015
1024
|
children: cellText(row, column)
|
|
@@ -1025,13 +1034,19 @@ function DataTable({ dimensions = EMPTY, measures, percentOf = EMPTY, formatDime
|
|
|
1025
1034
|
} },
|
|
1026
1035
|
children: columns.map((column) => isDimension(column) ? /* @__PURE__ */ jsx(TableCell, {
|
|
1027
1036
|
align: alignOf(column),
|
|
1028
|
-
sx: {
|
|
1037
|
+
sx: {
|
|
1038
|
+
verticalAlign: verticalOf(column),
|
|
1039
|
+
paddingTop: cellPaddingStyle,
|
|
1040
|
+
paddingBottom: cellPaddingStyle
|
|
1041
|
+
},
|
|
1029
1042
|
children: column === totalLabelColumn ? "Total" : ""
|
|
1030
1043
|
}, column) : /* @__PURE__ */ jsx(TableCell, {
|
|
1031
1044
|
align: alignOf(column),
|
|
1032
1045
|
sx: {
|
|
1033
1046
|
whiteSpace: "nowrap",
|
|
1034
|
-
verticalAlign: verticalOf(column)
|
|
1047
|
+
verticalAlign: verticalOf(column),
|
|
1048
|
+
paddingTop: cellPaddingStyle,
|
|
1049
|
+
paddingBottom: cellPaddingStyle
|
|
1035
1050
|
},
|
|
1036
1051
|
children: column.startsWith("%:") ? formatPercent(sums[column.slice(2)] ? 1 : null) : formats[column]?.(totalRow[column])
|
|
1037
1052
|
}, column))
|
|
@@ -1058,12 +1073,13 @@ const LEGEND_DIRECTION = {
|
|
|
1058
1073
|
* ou em cima/embaixo; `showValues` põe o valor de cada fatia do lado de fora.
|
|
1059
1074
|
* Ex.: `<DonutChart dimension="operacao_status" measure="custoTotal" />`.
|
|
1060
1075
|
*/
|
|
1061
|
-
function DonutChart({ dimension, measure, maxSlices = 6, formatDimension = String, clickToFilter = false, height = 300, labels, formats, percentDecimals = 1, legendPosition = "right", showValues = false, valueContent = "both", showTotal = true, queryLabel }) {
|
|
1076
|
+
function DonutChart({ dimension, measure, maxSlices = 6, formatDimension = String, clickToFilter = false, height = 300, labels, formats, percentDecimals = 1, legendPosition = "right", showValues = false, valueContent = "both", showTotal = true, ignoreFilters, queryLabel }) {
|
|
1062
1077
|
const { meta } = useDashboard();
|
|
1078
|
+
const ignore = [...ignoreFilters ?? [], ...clickToFilter ? [dimension] : []];
|
|
1063
1079
|
const { rows, isLoading, error, inspectProps } = useModelQuery({
|
|
1064
1080
|
dimensions: [dimension],
|
|
1065
1081
|
measures: [measure],
|
|
1066
|
-
ignoreFilters:
|
|
1082
|
+
ignoreFilters: ignore.length ? ignore : void 0,
|
|
1067
1083
|
label: queryLabel ?? `DonutChart · ${dimension}`
|
|
1068
1084
|
});
|
|
1069
1085
|
const filter = useClickFilter(dimension, clickToFilter);
|
|
@@ -1318,10 +1334,11 @@ function DonutChart({ dimension, measure, maxSlices = 6, formatDimension = Strin
|
|
|
1318
1334
|
* dimensões: razões (custo/t) saem do total, não de uma média. Ex.:
|
|
1319
1335
|
* `<KpiCard label="Custo total" measure="custoTotal" secondary="custoTon" />`.
|
|
1320
1336
|
*/
|
|
1321
|
-
function KpiCard({ measure, label, secondary, secondaryLabel, labels, formats, queryLabel }) {
|
|
1337
|
+
function KpiCard({ measure, label, secondary, secondaryLabel, labels, formats, ignoreFilters, queryLabel }) {
|
|
1322
1338
|
const { meta } = useDashboard();
|
|
1323
1339
|
const { rows, isLoading, error, inspectProps } = useModelQuery({
|
|
1324
1340
|
measures: secondary ? [measure, secondary] : [measure],
|
|
1341
|
+
ignoreFilters: ignoreFilters?.length ? ignoreFilters : void 0,
|
|
1325
1342
|
label: queryLabel ?? `KpiCard · ${measure}`
|
|
1326
1343
|
});
|
|
1327
1344
|
const row = rows[0];
|
|
@@ -1422,6 +1439,20 @@ function chartTitleSx(card) {
|
|
|
1422
1439
|
textAlign: card.titleAlign
|
|
1423
1440
|
});
|
|
1424
1441
|
}
|
|
1442
|
+
/**
|
|
1443
|
+
* `sx` da caixa que envolve o título: o espaço até o conteúdo (`contentGap`) e, com `titleDivider`,
|
|
1444
|
+
* a linha abaixo do título e o espaço até ela (`titleGap`). Um `panel` do app põe isto na caixa do
|
|
1445
|
+
* título para herdar divisor e espaçamentos do card (global `cards` ou por gráfico `card`).
|
|
1446
|
+
*/
|
|
1447
|
+
function chartTitleBoxSx(card) {
|
|
1448
|
+
return {
|
|
1449
|
+
mb: px(card.contentGap ?? 8),
|
|
1450
|
+
...card.titleDivider && {
|
|
1451
|
+
pb: px(card.titleGap ?? 4),
|
|
1452
|
+
borderBottom: `1px solid ${card.titleDividerColor ?? "#e0e0e0"}`
|
|
1453
|
+
}
|
|
1454
|
+
};
|
|
1455
|
+
}
|
|
1425
1456
|
function DefaultPanel({ title, card, children }) {
|
|
1426
1457
|
return /* @__PURE__ */ jsxs(Paper, {
|
|
1427
1458
|
elevation: 0,
|
|
@@ -1433,13 +1464,15 @@ function DefaultPanel({ title, card, children }) {
|
|
|
1433
1464
|
borderColor: "divider",
|
|
1434
1465
|
...chartCardSx(card)
|
|
1435
1466
|
},
|
|
1436
|
-
children: [title && /* @__PURE__ */ jsx(
|
|
1437
|
-
sx:
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1467
|
+
children: [title && /* @__PURE__ */ jsx(Box, {
|
|
1468
|
+
sx: chartTitleBoxSx(card),
|
|
1469
|
+
children: /* @__PURE__ */ jsx(Typography, {
|
|
1470
|
+
sx: {
|
|
1471
|
+
fontWeight: 700,
|
|
1472
|
+
...chartTitleSx(card)
|
|
1473
|
+
},
|
|
1474
|
+
children: title
|
|
1475
|
+
})
|
|
1443
1476
|
}), children]
|
|
1444
1477
|
});
|
|
1445
1478
|
}
|
|
@@ -1457,6 +1490,29 @@ function DashboardCharts({ layout, formatters = {}, panel: Panel = DefaultPanel,
|
|
|
1457
1490
|
formatters = withBuiltinFormatters(formatters);
|
|
1458
1491
|
const current = useLayout(layout, "charts", formatters);
|
|
1459
1492
|
const { charts } = current;
|
|
1493
|
+
const { parameters, meta } = useDashboard();
|
|
1494
|
+
const ignoredByFilter = useMemo(() => {
|
|
1495
|
+
const map = /* @__PURE__ */ new Map();
|
|
1496
|
+
for (const filter of current.filters ?? []) for (const id of filter.ignoredBy ?? []) map.set(id, [...map.get(id) ?? [], filter.dimension]);
|
|
1497
|
+
return map;
|
|
1498
|
+
}, [current.filters]);
|
|
1499
|
+
const measureOverride = useMemo(() => {
|
|
1500
|
+
const map = /* @__PURE__ */ new Map();
|
|
1501
|
+
const byName = new Map((current.parameters ?? []).map((parameter) => [parameter.name, parameter]));
|
|
1502
|
+
for (const chart of charts) {
|
|
1503
|
+
const linked = chart.measureParameter;
|
|
1504
|
+
if (typeof linked !== "string") continue;
|
|
1505
|
+
const parameter = byName.get(linked);
|
|
1506
|
+
if (!parameter) continue;
|
|
1507
|
+
const selected = parameters[parameter.name] ?? parameter.default ?? parameter.measures[0];
|
|
1508
|
+
if (selected) map.set(chart.id, selected);
|
|
1509
|
+
}
|
|
1510
|
+
return map;
|
|
1511
|
+
}, [
|
|
1512
|
+
current.parameters,
|
|
1513
|
+
parameters,
|
|
1514
|
+
charts
|
|
1515
|
+
]);
|
|
1460
1516
|
const fixed = useFixedCanvas();
|
|
1461
1517
|
const columns = `repeat(12, minmax(0, 1fr))`;
|
|
1462
1518
|
const space = cardsGap(current.cards);
|
|
@@ -1470,27 +1526,64 @@ function DashboardCharts({ layout, formatters = {}, panel: Panel = DefaultPanel,
|
|
|
1470
1526
|
lg: columns
|
|
1471
1527
|
}
|
|
1472
1528
|
},
|
|
1473
|
-
children: charts.map((chart) =>
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1529
|
+
children: charts.map((chart) => {
|
|
1530
|
+
const override = measureOverride.get(chart.id);
|
|
1531
|
+
const effective = withMeasure(withFilterIgnores(chart, ignoredByFilter.get(chart.id)), override);
|
|
1532
|
+
const measure = override ?? chart.measure;
|
|
1533
|
+
const title = resolveTitle(chart.title, typeof measure === "string" ? measure : void 0, meta);
|
|
1534
|
+
return /* @__PURE__ */ jsx(Box, {
|
|
1535
|
+
[LAYOUT_ITEM_ATTRIBUTE]: layoutItemKey(layout.id, {
|
|
1536
|
+
kind: "chart",
|
|
1537
|
+
key: chart.id
|
|
1538
|
+
}),
|
|
1539
|
+
sx: {
|
|
1540
|
+
minWidth: 0,
|
|
1541
|
+
gridColumn: fixed ? `span ${chart.span ?? 12}` : { lg: `span ${chart.span ?? 12}` }
|
|
1542
|
+
},
|
|
1543
|
+
children: /* @__PURE__ */ jsx(Panel, {
|
|
1544
|
+
title,
|
|
1487
1545
|
chart,
|
|
1488
|
-
|
|
1546
|
+
card: chartCardStyle(current, chart),
|
|
1547
|
+
children: /* @__PURE__ */ jsx(Chart, {
|
|
1548
|
+
chart: effective,
|
|
1549
|
+
formatters
|
|
1550
|
+
})
|
|
1489
1551
|
})
|
|
1490
|
-
})
|
|
1491
|
-
}
|
|
1552
|
+
}, chart.id);
|
|
1553
|
+
})
|
|
1492
1554
|
});
|
|
1493
1555
|
}
|
|
1556
|
+
/**
|
|
1557
|
+
* Soma ao `ignoreFilters` do gráfico as dimensões dos filtros que o marcaram em `ignoredBy`, sem
|
|
1558
|
+
* duplicar. Vazio = devolve o gráfico como está (sem recriar o objeto).
|
|
1559
|
+
*/
|
|
1560
|
+
function withFilterIgnores(chart, fromFilters) {
|
|
1561
|
+
if (!fromFilters?.length) return chart;
|
|
1562
|
+
const ignoreFilters = [.../* @__PURE__ */ new Set([...chart.ignoreFilters ?? [], ...fromFilters])];
|
|
1563
|
+
return {
|
|
1564
|
+
...chart,
|
|
1565
|
+
ignoreFilters
|
|
1566
|
+
};
|
|
1567
|
+
}
|
|
1568
|
+
/** Troca a medida do gráfico pela escolhida num parâmetro de medida (vazio = gráfico como está). */
|
|
1569
|
+
function withMeasure(chart, measure) {
|
|
1570
|
+
if (!measure || chart.measure === measure) return chart;
|
|
1571
|
+
return {
|
|
1572
|
+
...chart,
|
|
1573
|
+
measure
|
|
1574
|
+
};
|
|
1575
|
+
}
|
|
1576
|
+
const TITLE_TOKEN = /\{\{\s*medida\s*\}\}/g;
|
|
1577
|
+
/**
|
|
1578
|
+
* Resolve `{{medida}}` no título para a descrição da medida atual do gráfico (ou o rótulo, se não
|
|
1579
|
+
* houver descrição; vazio, se o gráfico não tem medida única). Com um parâmetro de medida, a medida
|
|
1580
|
+
* atual muda com o slicer, então o título acompanha. Sem token, devolve o título como está.
|
|
1581
|
+
*/
|
|
1582
|
+
function resolveTitle(title, measure, meta) {
|
|
1583
|
+
if (!title.includes("{{")) return title;
|
|
1584
|
+
const name = measure ? meta?.measures[measure]?.description || fieldLabel(meta, measure) : "";
|
|
1585
|
+
return title.replace(TITLE_TOKEN, name);
|
|
1586
|
+
}
|
|
1494
1587
|
function Chart({ chart, formatters }) {
|
|
1495
1588
|
const { chartTypes, chartComponents } = useDashboard();
|
|
1496
1589
|
if (!isBuiltinChart(chart)) {
|
|
@@ -1618,6 +1711,40 @@ function FilterSelect({ dimension, label, formatLabel = String, width = 200 }) {
|
|
|
1618
1711
|
});
|
|
1619
1712
|
}
|
|
1620
1713
|
//#endregion
|
|
1714
|
+
//#region src/client/MeasureSelect.tsx
|
|
1715
|
+
/**
|
|
1716
|
+
* Slicer de um parâmetro de medida ("medida dinâmica"): escolhe UMA medida entre `measures`. A
|
|
1717
|
+
* escolha fica no `DashboardProvider` (`parameters[name]`) e o `<DashboardCharts>` troca a medida
|
|
1718
|
+
* dos gráficos de medida única que seguem o parâmetro. Os rótulos vêm do dicionário do modelo.
|
|
1719
|
+
*/
|
|
1720
|
+
function MeasureSelect({ name, measures, label = "Medida", default: fallback, width = 200 }) {
|
|
1721
|
+
const { meta, parameters, setParameter } = useDashboard();
|
|
1722
|
+
const selected = parameters[name] ?? fallback ?? measures[0];
|
|
1723
|
+
if (!selected) return null;
|
|
1724
|
+
return /* @__PURE__ */ jsxs(FormControl, {
|
|
1725
|
+
size: "small",
|
|
1726
|
+
sx: { width },
|
|
1727
|
+
children: [/* @__PURE__ */ jsx(InputLabel, {
|
|
1728
|
+
shrink: true,
|
|
1729
|
+
children: label
|
|
1730
|
+
}), /* @__PURE__ */ jsx(Select, {
|
|
1731
|
+
value: selected,
|
|
1732
|
+
onChange: (event) => setParameter(name, event.target.value),
|
|
1733
|
+
input: /* @__PURE__ */ jsx(OutlinedInput, {
|
|
1734
|
+
notched: true,
|
|
1735
|
+
label
|
|
1736
|
+
}),
|
|
1737
|
+
MenuProps: { slotProps: { paper: { sx: { maxHeight: 360 } } } },
|
|
1738
|
+
sx: { bgcolor: "#fff" },
|
|
1739
|
+
children: measures.map((measure) => /* @__PURE__ */ jsx(MenuItem, {
|
|
1740
|
+
value: measure,
|
|
1741
|
+
dense: true,
|
|
1742
|
+
children: fieldLabel(meta, measure)
|
|
1743
|
+
}, measure))
|
|
1744
|
+
})]
|
|
1745
|
+
});
|
|
1746
|
+
}
|
|
1747
|
+
//#endregion
|
|
1621
1748
|
//#region src/client/DashboardFilters.tsx
|
|
1622
1749
|
/**
|
|
1623
1750
|
* Filtros (slicers) declarados em `layout.filters`, na ordem. Em desenvolvimento, a aba Layout do
|
|
@@ -1625,14 +1752,14 @@ function FilterSelect({ dimension, label, formatLabel = String, width = 200 }) {
|
|
|
1625
1752
|
*/
|
|
1626
1753
|
function DashboardFilters({ layout, formatters = {}, gap = 2 }) {
|
|
1627
1754
|
formatters = withBuiltinFormatters(formatters);
|
|
1628
|
-
const { filters = [] } = useLayout(layout, "filters", formatters);
|
|
1629
|
-
return /* @__PURE__ */
|
|
1755
|
+
const { filters = [], parameters = [] } = useLayout(layout, "filters", formatters);
|
|
1756
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
1630
1757
|
sx: {
|
|
1631
1758
|
display: "flex",
|
|
1632
1759
|
flexWrap: "wrap",
|
|
1633
1760
|
gap
|
|
1634
1761
|
},
|
|
1635
|
-
children: filters.map((filter) => /* @__PURE__ */ jsx(Box, {
|
|
1762
|
+
children: [filters.map((filter) => /* @__PURE__ */ jsx(Box, {
|
|
1636
1763
|
[LAYOUT_ITEM_ATTRIBUTE]: layoutItemKey(layout.id, {
|
|
1637
1764
|
kind: "filter",
|
|
1638
1765
|
key: filter.dimension
|
|
@@ -1643,10 +1770,22 @@ function DashboardFilters({ layout, formatters = {}, gap = 2 }) {
|
|
|
1643
1770
|
width: filter.width,
|
|
1644
1771
|
formatLabel: filter.formatLabel ? formatters[filter.formatLabel] : void 0
|
|
1645
1772
|
})
|
|
1646
|
-
}, filter.dimension))
|
|
1773
|
+
}, filter.dimension)), parameters.map((parameter) => /* @__PURE__ */ jsx(Box, {
|
|
1774
|
+
[LAYOUT_ITEM_ATTRIBUTE]: layoutItemKey(layout.id, {
|
|
1775
|
+
kind: "parameter",
|
|
1776
|
+
key: parameter.name
|
|
1777
|
+
}),
|
|
1778
|
+
children: /* @__PURE__ */ jsx(MeasureSelect, {
|
|
1779
|
+
name: parameter.name,
|
|
1780
|
+
measures: parameter.measures,
|
|
1781
|
+
label: parameter.label,
|
|
1782
|
+
default: parameter.default,
|
|
1783
|
+
width: parameter.width
|
|
1784
|
+
})
|
|
1785
|
+
}, `param:${parameter.name}`))]
|
|
1647
1786
|
});
|
|
1648
1787
|
}
|
|
1649
1788
|
//#endregion
|
|
1650
|
-
export { BUILTIN_FORMATTERS, BarChart, ComboChart, DashboardCanvas, DashboardCharts, DashboardFilters, DashboardProvider, DataTable, DonutChart, FilterSelect, INSPECT_ATTRIBUTE, KpiCard, Legend, ModelDictionary, OTHER_COLOR, SERIES_COLORS, TooltipBox, chartCardSx, chartPlaceholder, chartTitleSx, fieldLabel, formatCurrency, formatMeasure, formatNumber, measureFormat, measureFormatter, numberOf, seriesColor, toDate, toMonthName, useClickFilter, useDashboard, useModelQuery };
|
|
1789
|
+
export { BUILTIN_FORMATTERS, BarChart, ComboChart, DashboardCanvas, DashboardCharts, DashboardFilters, DashboardProvider, DataTable, DonutChart, FilterSelect, INSPECT_ATTRIBUTE, KpiCard, Legend, ModelDictionary, OTHER_COLOR, SERIES_COLORS, TooltipBox, chartCardSx, chartPlaceholder, chartTitleBoxSx, chartTitleSx, fieldLabel, formatCurrency, formatMeasure, formatNumber, measureFormat, measureFormatter, numberOf, seriesColor, toDate, toMonthName, useClickFilter, useDashboard, useModelQuery };
|
|
1651
1790
|
|
|
1652
1791
|
//# sourceMappingURL=index.js.map
|