@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.
@@ -1,8 +1,8 @@
1
- import { A as contrastText, M as rowRuleStyles, d as customChartProps, g as percentColumn, j as matchesValueRule, k as colorScaleStyles, o as cardsGap, p as isBuiltinChart, s as chartCardStyle, v as tableColumns } from "../layout-BS3nO6OT.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-DZiYK1mV.js";
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] : void 0,
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: clickToFilter ? [dimension] : void 0,
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 ignoreFilters = clickToFilter && firstDimension ? [firstDimension] : void 0;
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: 13,
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: { verticalAlign: verticalOf(column) },
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: clickToFilter ? [dimension] : void 0,
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(Typography, {
1437
- sx: {
1438
- fontWeight: 700,
1439
- mb: 1,
1440
- ...chartTitleSx(card)
1441
- },
1442
- children: title
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) => /* @__PURE__ */ jsx(Box, {
1474
- [LAYOUT_ITEM_ATTRIBUTE]: layoutItemKey(layout.id, {
1475
- kind: "chart",
1476
- key: chart.id
1477
- }),
1478
- sx: {
1479
- minWidth: 0,
1480
- gridColumn: fixed ? `span ${chart.span ?? 12}` : { lg: `span ${chart.span ?? 12}` }
1481
- },
1482
- children: /* @__PURE__ */ jsx(Panel, {
1483
- title: chart.title,
1484
- chart,
1485
- card: chartCardStyle(current, chart),
1486
- children: /* @__PURE__ */ jsx(Chart, {
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
- formatters
1546
+ card: chartCardStyle(current, chart),
1547
+ children: /* @__PURE__ */ jsx(Chart, {
1548
+ chart: effective,
1549
+ formatters
1550
+ })
1489
1551
  })
1490
- })
1491
- }, chart.id))
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__ */ jsx(Box, {
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