@bluemarble/bi 0.6.6 → 0.7.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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["OTHERS","RechartsBarChart","Tooltip","Tooltip","Tooltip"],"sources":["../../src/client/seriesPivot.ts","../../src/client/BarChart.tsx","../../src/client/ComboChart.tsx","../../src/client/useLayout.ts","../../src/client/DashboardCanvas.tsx","../../src/client/DataTable.tsx","../../src/client/DonutChart.tsx","../../src/client/KpiCard.tsx","../../src/client/DashboardCharts.tsx","../../src/client/FilterSelect.tsx","../../src/client/DashboardFilters.tsx"],"sourcesContent":["import type { DashboardRow, FilterValue } from '../types'\nimport { numberOf, OTHER_COLOR, seriesColor } from './chartKit'\n\n/**\n * Séries vindas de uma dimensão (o `series` do `BarChart`, a \"Legenda\" do Power BI): a consulta\n * devolve linhas longas (categoria, série, valor) e o gráfico precisa delas largas (categoria,\n * série 1, série 2, …).\n */\n\nexport type SeriesItem = {\n /** Chave da série no ponto do gráfico (`s0`, `s1`, …; o valor pode ter \".\" e o Recharts lê como caminho). */\n dataKey: string\n /** Valor da dimensão; `null` = linhas sem valor ou \"Outros\" (não filtram). */\n value: FilterValue | null\n label: string\n color: string\n others?: boolean\n}\n\nexport const EMPTY_SERIES_LABEL = '(em branco)'\nconst OTHERS = 'Outros'\n\nconst keyOf = (value: FilterValue | null) => (value === null ? '\\u0000' : String(value))\n\n/**\n * Séries a partir do domínio (série × medida sem filtros): ordenadas pelo total, maior primeiro, e\n * a cor segue essa ordem — como o domínio não depende dos filtros, cada valor tem sempre a mesma\n * cor. Além de `max`, as menores viram \"Outros\" (a última vaga), em cinza.\n */\nexport function seriesItems(\n domain: DashboardRow[],\n series: string,\n measure: string,\n max: number,\n format: (value: FilterValue) => string = String\n): SeriesItem[] {\n const ranked = domain\n .map((row) => ({ value: row[series] ?? null, amount: Math.abs(numberOf(row, measure) ?? 0) }))\n .sort((a, b) => b.amount - a.amount)\n const limit = Math.min(Math.max(max, 2), 8)\n const kept = ranked.length > limit ? ranked.slice(0, limit - 1) : ranked\n const items: SeriesItem[] = kept.map((item, index) => ({\n dataKey: `s${index}`,\n value: item.value,\n label: item.value === null ? EMPTY_SERIES_LABEL : format(item.value),\n color: seriesColor(index)\n }))\n if (ranked.length > kept.length) items.push(othersItem(ranked.length - kept.length))\n return items\n}\n\nconst othersItem = (count?: number): SeriesItem => ({\n dataKey: 'outros',\n value: null,\n label: count ? `${OTHERS} (${count})` : OTHERS,\n color: OTHER_COLOR,\n others: true\n})\n\nexport type SeriesPoint = { value: FilterValue; label: string } & Record<string, number | string>\n\n/**\n * Linhas (categoria, série, medida) → um ponto por categoria, na ordem da consulta, com o valor de\n * cada série em `dataKey`. Valor fora das séries soma em \"Outros\" (criado se o domínio não tinha).\n * Devolve só as séries com algum valor nos pontos (um filtro pode ter tirado uma delas).\n */\nexport function pivotSeries(\n rows: DashboardRow[],\n dimension: string,\n series: string,\n measure: string,\n items: SeriesItem[],\n format: (value: FilterValue) => string = String\n): { points: SeriesPoint[]; items: SeriesItem[] } {\n const all = [...items]\n const byValue = new Map(\n all.filter((item) => !item.others).map((item) => [keyOf(item.value), item])\n )\n const points = new Map<string, SeriesPoint>()\n const used = new Set<string>()\n for (const row of rows) {\n const value = row[dimension] ?? ''\n const key = String(value)\n let point = points.get(key)\n if (!point) {\n point = { value, label: format(value) }\n for (const item of all) point[item.dataKey] = 0\n points.set(key, point)\n }\n let item = byValue.get(keyOf(row[series] ?? null))\n if (!item) {\n item = all.find((other) => other.others)\n if (!item) {\n item = othersItem()\n all.push(item)\n for (const other of points.values()) other[item.dataKey] = 0\n }\n }\n const amount = numberOf(row, measure)\n if (amount) {\n point[item.dataKey] = Number(point[item.dataKey] ?? 0) + amount\n used.add(item.dataKey)\n }\n }\n return { points: [...points.values()], items: all.filter((item) => used.has(item.dataKey)) }\n}\n\n/** Soma das séries de um ponto (a altura da barra empilhada). */\nexport const pointTotal = (point: SeriesPoint, items: SeriesItem[]) =>\n items.reduce((total, item) => total + Number(point[item.dataKey] ?? 0), 0)\n\n/**\n * Todas as categorias da dimensão (consulta só da dimensão, sem medidas), na ordem dela, com os\n * valores dos pontos que vieram da consulta e zero nas que não têm dado (o \"Mostrar itens sem\n * dados\" do Power BI). Ponto fora da lista (não deveria haver) vai no fim.\n */\nexport function fillCategories<Point extends { value: FilterValue; label: string }>(\n points: Point[],\n categories: DashboardRow[],\n dimension: string,\n dataKeys: string[],\n format: (value: FilterValue) => string = String\n): Point[] {\n const byValue = new Map(points.map((point) => [String(point.value), point]))\n const seen = new Set<string>()\n const filled: Point[] = []\n for (const row of categories) {\n const value = row[dimension] ?? ''\n const key = String(value)\n if (seen.has(key)) continue\n seen.add(key)\n const point = byValue.get(key)\n if (point) filled.push(point)\n else\n filled.push({\n value,\n label: format(value),\n ...Object.fromEntries(dataKeys.map((dataKey) => [dataKey, 0]))\n } as unknown as Point)\n }\n return [...filled, ...points.filter((point) => !seen.has(String(point.value)))]\n}\n","import { Box } from '@mui/material'\nimport type { MouseEvent } from 'react'\nimport {\n Bar,\n CartesianGrid,\n Cell,\n LabelList,\n BarChart as RechartsBarChart,\n ResponsiveContainer,\n Tooltip,\n XAxis,\n YAxis\n} from 'recharts'\nimport { matchesValueRule, type ValueRule } from '../formatRules'\nimport type { BarValuePosition, ChartNumberFormat } from '../layout'\nimport type { FilterValue } from '../types'\nimport {\n chartPlaceholder,\n Legend,\n numberOf,\n seriesColor,\n TooltipBox,\n useClickFilter\n} from './chartKit'\nimport { useDashboard } from './DashboardProvider'\nimport { fieldLabel, formatMeasure, measureFormat, measureFormatter } from './format'\nimport {\n EMPTY_SERIES_LABEL,\n fillCategories,\n pivotSeries,\n pointTotal,\n type SeriesItem,\n seriesItems\n} from './seriesPivot'\nimport { useModelQuery } from './useModelQuery'\n\ntype BarChartProps = {\n /** Dimensão das categorias. */\n dimension: string\n /** Uma série por medida (cores fixas pela posição); com `series`, só a primeira. */\n measures: string[]\n /**\n * Dimensão da legenda: quebra a medida pelos valores dela, uma série por valor (a \"Legenda\" do\n * Power BI). A cor de cada valor é fixa (ordem do total sem filtros), mesmo que um filtro tire\n * outro valor do gráfico.\n */\n series?: string\n formatSeries?: (value: FilterValue) => string\n /** Com `series`: as menores além dessa quantidade viram \"Outros\" (no máximo 8). Padrão: 6. */\n maxSeries?: number\n /** `horizontal` cabe nomes longos; com muitas categorias, rola dentro da altura. */\n orientation?: 'vertical' | 'horizontal'\n /** Empilha as séries (só faz sentido com partes de um total). */\n stacked?: boolean\n /** `dimension` = ordem da consulta; `desc`/`asc` = pela primeira medida (com `series`, pelo total). */\n sort?: 'dimension' | 'desc' | 'asc'\n /** Só os N primeiros depois de ordenar. */\n limit?: number\n formatDimension?: (value: FilterValue) => string\n /** Esconde categorias sem valor em nenhuma medida. */\n hideEmpty?: boolean\n /**\n * Mostra todos os valores da dimensão no eixo, com ou sem dado nas medidas (zerados), na ordem\n * da dimensão. Sobrepõe o `hideEmpty`.\n */\n showEmpty?: boolean\n /** Valores nas barras (até 30 categorias; acima disso, só tooltip). */\n showValues?: boolean\n /**\n * Onde fica o valor: `outside` (na ponta, fora), `insideEnd` (dentro, na ponta), `center` ou\n * `insideBase`. Empilhado, `outside` não mostra os pedaços (só o `showTotal`).\n */\n valuePosition?: BarValuePosition\n /** Cor do valor. Padrão: escuro fora da barra, branco dentro. */\n valueColor?: string\n /** Tamanho do valor, em px. Padrão: 12. */\n valueSize?: number\n /** Empilhado: total da pilha na ponta da barra. */\n showTotal?: boolean\n /** Só mostra o valor (e o total) que atende à regra, ex.: `{ operator: '!=', value: 0 }`. */\n valueRule?: ValueRule\n /**\n * Com `clickToFilter`: o filtro da dimensão (e da série) esconde o resto em vez de só apagá-lo\n * (a consulta passa a respeitar o próprio filtro). Padrão: `false` (apaga).\n */\n hideUnselected?: boolean\n /**\n * Cor por série: `{ medida: '#rrggbb' }` ou, com `series`, `{ valor: '#rrggbb' }` (também\n * \"(em branco)\" e \"Outros\"). O que faltar segue a paleta.\n */\n colors?: Record<string, string>\n clickToFilter?: boolean\n height?: number\n /** Rótulo por dimensão/medida (sobrepõe o dicionário do modelo). */\n labels?: Record<string, string>\n /** Formato por medida (sobrepõe o dicionário do modelo). */\n formats?: Record<string, ChartNumberFormat>\n /** Nome da consulta no devtools. */\n queryLabel?: string\n}\n\nconst MAX_VALUE_LABELS = 30\n/** Coluna do total da pilha no ponto (para o rótulo do `showTotal`). */\nconst TOTAL_KEY = '\\u0000total'\n\n/** Posição do valor no Recharts, conforme a orientação. */\nconst LABEL_POSITION = {\n vertical: {\n outside: 'top',\n insideEnd: 'insideTop',\n center: 'center',\n insideBase: 'insideBottom'\n },\n horizontal: {\n outside: 'right',\n insideEnd: 'insideRight',\n center: 'center',\n insideBase: 'insideLeft'\n }\n} as const\n\n/** Chave de uma série em `colors`: o valor, \"(em branco)\" ou \"Outros\". */\nconst seriesColorKey = (item: SeriesItem) =>\n item.others ? 'Outros' : item.value === null ? EMPTY_SERIES_LABEL : String(item.value)\n/** Altura de cada categoria no modo horizontal (barras finas, com respiro). */\nconst ROW_HEIGHT = 28\n\ntype Point = { value: FilterValue; label: string } & Record<string, number | string>\n\n/** Uma `<Bar>` do gráfico: uma medida ou um valor da série. */\ntype Bar = { dataKey: string; label: string; color: string; format: (value: number) => string } & (\n | { item?: undefined }\n | { item: SeriesItem }\n)\n\n/**\n * Barras de uma ou mais medidas por uma dimensão. Ex.:\n * `<BarChart dimension=\"navio\" measures={['custoTotal']} orientation=\"horizontal\" sort=\"desc\" limit={10} />`.\n * Com `series`, uma medida quebrada pelos valores de outra dimensão:\n * `<BarChart dimension=\"mes\" series=\"tipo_descarga\" measures={['volume']} stacked />`.\n */\nexport function BarChart({\n dimension,\n measures: measureList,\n series,\n formatSeries = String,\n maxSeries = 6,\n orientation = 'vertical',\n stacked = false,\n sort = 'dimension',\n limit,\n formatDimension = String,\n hideEmpty = true,\n showEmpty = false,\n showValues = true,\n valuePosition = 'outside',\n valueColor,\n valueSize = 12,\n showTotal = false,\n valueRule,\n hideUnselected = false,\n colors,\n clickToFilter = false,\n height = 360,\n labels,\n formats: formatsByMeasure,\n queryLabel\n}: BarChartProps) {\n const { meta, filters, setFilter } = useDashboard()\n const dimming = clickToFilter && !hideUnselected\n // Com série, uma medida só\n const measures = series ? measureList.slice(0, 1) : measureList\n const { rows, isLoading, error, inspectProps } = useModelQuery({\n dimensions: series ? [dimension, series] : [dimension],\n measures,\n // Apagando o resto, o gráfico ignora o próprio filtro (mostra tudo e destaca a seleção)\n ignoreFilters: dimming ? (series ? [dimension, series] : [dimension]) : undefined,\n label: queryLabel ?? `BarChart · ${dimension}`\n })\n // Valores da série sem filtro nenhum: a cor (e quem vira \"Outros\") não muda com os filtros\n const domain = useModelQuery({\n dimensions: series ? [series] : [],\n measures,\n ignoreFilters: Object.keys(filters),\n label: `${queryLabel ?? `BarChart · ${dimension}`} · séries`,\n skip: !series\n })\n // Todas as categorias da dimensão (consulta sem medidas, como a lista de um filtro). Só os\n // filtros da mesma tabela valem: um de outra tabela faria a consulta partir da fato, e as\n // categorias sem dado sumiriam\n const table = meta?.dimensions[dimension]?.table\n const categories = useModelQuery({\n dimensions: [dimension],\n ignoreFilters: Object.keys(filters).filter(\n (name) => (dimming && name === dimension) || !table || meta?.dimensions[name]?.table !== table\n ),\n label: `${queryLabel ?? `BarChart · ${dimension}`} · categorias`,\n // Sem o meta não se sabe a tabela da dimensão\n skip: !showEmpty || !meta\n })\n const filter = useClickFilter(dimension, clickToFilter)\n const seriesFilter = useClickFilter(series, clickToFilter)\n const formats = measures.map((measure) => measureFormatter(meta, measure, 0, formatsByMeasure))\n const labelOf = (name: string) => fieldLabel(meta, name, labels)\n // Eixo de valores: formato da primeira medida, sem casas (os valores exatos ficam nos rótulos)\n const axisFormat = measures[0] ? measureFormat(meta, measures[0], formatsByMeasure) : undefined\n const formatTick = (value: number) =>\n formatMeasure(value, { ...axisFormat, decimals: axisFormat?.compact ? 1 : 0 }, 0)\n\n let data: Point[]\n let bars: Bar[]\n const first = measures[0]\n if (series && first) {\n const format = formats[0] ?? String\n const pivot = pivotSeries(\n rows,\n dimension,\n series,\n first,\n seriesItems(domain.rows, series, first, maxSeries, formatSeries),\n formatDimension\n )\n bars = pivot.items.map((item) => ({\n ...item,\n color: colors?.[seriesColorKey(item)] ?? item.color,\n item,\n format\n }))\n data = pivot.points\n } else {\n bars = measures.map((measure, index) => ({\n dataKey: measure,\n label: labelOf(measure),\n color: colors?.[measure] ?? seriesColor(index),\n format: formats[index] ?? String\n }))\n data = rows.map((row) => {\n const value = row[dimension] ?? ''\n const point: Point = { value, label: formatDimension(value) }\n for (const measure of measures) point[measure] = numberOf(row, measure) ?? 0\n return point\n })\n }\n if (showEmpty)\n data = fillCategories(\n data,\n categories.rows,\n dimension,\n bars.map((bar) => bar.dataKey),\n formatDimension\n )\n else if (hideEmpty) data = data.filter((point) => bars.some((bar) => Number(point[bar.dataKey])))\n // Ordena pela primeira medida ou, com série, pelo total da barra\n const sortValue = (point: Point) =>\n series\n ? pointTotal(\n point,\n bars.map((bar) => bar.item).filter((item) => !!item)\n )\n : Number(point[first ?? ''])\n if (sort !== 'dimension' && first)\n data = [...data].sort((a, b) =>\n sort === 'desc' ? sortValue(b) - sortValue(a) : sortValue(a) - sortValue(b)\n )\n if (limit) data = data.slice(0, limit)\n\n const horizontal = orientation === 'horizontal'\n const showLabels = showValues && data.length <= MAX_VALUE_LABELS\n // Empilhado, o valor de fora seria o do último pedaço: lá vai só o total\n const segmentLabels = showLabels && (!stacked || valuePosition !== 'outside')\n const totalLabel = showLabels && stacked && showTotal && bars.length > 0\n // Rótulo fora da barra precisa de espaço na ponta\n const labelsOutside = (segmentLabels && valuePosition === 'outside') || totalLabel\n if (totalLabel)\n data = data.map((point) => ({\n ...point,\n [TOTAL_KEY]: bars.reduce((total, bar) => total + Number(point[bar.dataKey] ?? 0), 0)\n }))\n const labelStyle = (outside: boolean) => ({\n fontSize: valueSize,\n fill: valueColor ?? (outside ? '#333' : '#fff'),\n fontWeight: 600\n })\n const position = LABEL_POSITION[orientation === 'horizontal' ? 'horizontal' : 'vertical']\n // Horizontal com muitas categorias: o gráfico cresce e a caixa rola\n const chartHeight = horizontal ? Math.max(height, data.length * ROW_HEIGHT + 24) : height\n const longest = Math.max(0, ...data.map((point) => point.label.length))\n\n const loading = isLoading || domain.isLoading || categories.isLoading || (showEmpty && !meta)\n const state = chartPlaceholder({\n height,\n error: error ?? domain.error ?? categories.error,\n isLoading: loading,\n empty: !data.length\n })\n\n const ChartTooltip = ({ active, payload }: any) => {\n if (!active || !payload?.length) return null\n const point: Point = payload[0].payload\n // Com série, só as que têm valor nesta barra (e o total, se empilhado)\n const shown = series ? bars.filter((bar) => Number(point[bar.dataKey])) : bars\n const format = bars[0]?.format ?? String\n return (\n <TooltipBox title={point.label} caption={labelOf(dimension)}>\n {series && first && (\n <Box sx={{ fontSize: 11, color: '#777', mt: 0.5 }}>\n {labelOf(first)} por {labelOf(series).toLocaleLowerCase('pt-BR')}\n </Box>\n )}\n {shown.map((bar) => (\n <Box key={bar.dataKey} sx={{ display: 'flex', alignItems: 'center', gap: 0.75 }}>\n <Box sx={{ width: 8, height: 8, borderRadius: '50%', bgcolor: bar.color }} />\n {bar.label}: {bar.format(Number(point[bar.dataKey]))}\n </Box>\n ))}\n {series && stacked && shown.length > 1 && (\n <Box sx={{ fontWeight: 700, mt: 0.5 }}>\n Total: {format(shown.reduce((total, bar) => total + Number(point[bar.dataKey]), 0))}\n </Box>\n )}\n </TooltipBox>\n )\n }\n\n const handleClick = (index: number, bar: Bar, event: MouseEvent) => {\n // Senão o clique sobe até o container, que limpa o filtro\n event.stopPropagation()\n const point = data[index]\n if (!point) return\n const value = bar.item?.value\n // Segmento de um valor da série: filtra as duas dimensões (sem valor/\"Outros\", só a categoria)\n if (!series || value === null || value === undefined) {\n filter.toggle(point.value, event)\n seriesFilter.clear()\n } else if (event.ctrlKey || event.metaKey) {\n filter.toggle(point.value, event)\n seriesFilter.toggle(value, event)\n } else {\n // Clicar de novo no único segmento selecionado limpa; senão seleciona só ele\n const sole = (selected: FilterValue[], item: FilterValue) =>\n selected.length === 1 && selected[0] === item\n const again = sole(filter.selected, point.value) && sole(seriesFilter.selected, value)\n setFilter(dimension, again ? [] : [point.value])\n setFilter(series, again ? [] : [value])\n }\n }\n const isDimmed = (point: Point, bar: Bar) => {\n if (filter.isDimmed(point.value)) return true\n if (!bar.item || !seriesFilter.selected.length) return false\n return bar.item.value === null || seriesFilter.isDimmed(bar.item.value)\n }\n const clearFilters = () => {\n filter.clear()\n seriesFilter.clear()\n }\n\n // Ponta arredondada só no fim da barra (no empilhado, só no último segmento)\n const radius = (index: number): [number, number, number, number] => {\n if (stacked && index < bars.length - 1) return [0, 0, 0, 0]\n return horizontal ? [0, 4, 4, 0] : [4, 4, 0, 0]\n }\n\n return (\n <Box {...inspectProps} sx={{ minWidth: 0 }}>\n <Legend\n items={series || bars.length > 1 ? bars.map(({ label, color }) => ({ label, color })) : []}\n loading={loading}\n />\n {state ?? (\n <Box\n onClick={clearFilters}\n sx={{\n height,\n overflowY: horizontal ? 'auto' : 'hidden',\n opacity: loading ? 0.5 : 1,\n transition: 'opacity .2s'\n }}\n >\n <Box sx={{ height: chartHeight }}>\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <RechartsBarChart\n data={data}\n layout={horizontal ? 'vertical' : 'horizontal'}\n barGap={2}\n barCategoryGap=\"20%\"\n margin={\n horizontal\n ? { top: 4, right: labelsOutside ? 96 : 16, left: 8, bottom: 4 }\n : { top: labelsOutside ? valueSize + 12 : 8, right: 8, left: 8, bottom: 0 }\n }\n >\n <CartesianGrid stroke=\"#eee\" vertical={horizontal} horizontal={!horizontal} />\n {horizontal ? (\n <>\n <XAxis\n type=\"number\"\n hide={showLabels}\n tick={{ fontSize: 12, fill: '#555' }}\n tickFormatter={formatTick}\n />\n <YAxis\n type=\"category\"\n dataKey=\"label\"\n interval={0}\n width={Math.min(220, longest * 7 + 12)}\n tick={{ fontSize: 12, fill: '#555' }}\n tickLine={false}\n axisLine={false}\n />\n </>\n ) : (\n <>\n <XAxis\n dataKey=\"label\"\n interval={data.length > MAX_VALUE_LABELS ? 'preserveStartEnd' : 0}\n tick={{ fontSize: 12, fill: '#555' }}\n tickLine={false}\n axisLine={{ stroke: '#ccc' }}\n />\n <YAxis\n hide={showLabels}\n tick={{ fontSize: 12, fill: '#555' }}\n tickFormatter={formatTick}\n width={72}\n />\n </>\n )}\n <Tooltip content={<ChartTooltip />} cursor={{ fill: 'rgba(0,0,0,.04)' }} />\n {bars.map((bar, index) => (\n <Bar\n key={bar.dataKey}\n dataKey={bar.dataKey}\n name={bar.label}\n fill={bar.color}\n stackId={stacked ? 'stack' : undefined}\n radius={radius(index)}\n maxBarSize={horizontal ? 18 : 56}\n isAnimationActive={false}\n onClick={\n clickToFilter\n ? (_bar, barIndex, event) => handleClick(barIndex, bar, event)\n : undefined\n }\n cursor={clickToFilter ? 'pointer' : undefined}\n >\n {clickToFilter &&\n data.map((point) => (\n <Cell\n key={String(point.value)}\n fillOpacity={isDimmed(point, bar) ? 0.35 : 1}\n />\n ))}\n {segmentLabels && (\n <LabelList\n dataKey={bar.dataKey}\n position={position[valuePosition]}\n // Pedaço zerado (série sem valor nesta barra) não ganha rótulo\n formatter={(value: unknown) =>\n (stacked && !Number(value)) || !matchesValueRule(valueRule, Number(value))\n ? ''\n : bar.format(value as number)\n }\n style={labelStyle(valuePosition === 'outside')}\n />\n )}\n {/* Total da pilha na ponta do último pedaço */}\n {totalLabel && index === bars.length - 1 && (\n <LabelList\n dataKey={TOTAL_KEY}\n position={position.outside}\n formatter={(value: unknown) =>\n matchesValueRule(valueRule, Number(value))\n ? (bars[0]?.format ?? String)(value as number)\n : ''\n }\n // Valores dentro: a cor escolhida é a deles; o total, fora, fica escuro\n style={{\n ...labelStyle(true),\n ...(valuePosition !== 'outside' && { fill: '#333' }),\n fontWeight: 700\n }}\n />\n )}\n </Bar>\n ))}\n </RechartsBarChart>\n </ResponsiveContainer>\n </Box>\n </Box>\n )}\n </Box>\n )\n}\n","import { Box, CircularProgress, Typography } from '@mui/material'\nimport type { MouseEvent } from 'react'\nimport {\n Bar,\n Cell,\n ComposedChart,\n LabelList,\n Line,\n ResponsiveContainer,\n Tooltip,\n XAxis,\n YAxis\n} from 'recharts'\nimport type { ChartNumberFormat } from '../layout'\nimport type { DashboardRow, FilterValue } from '../types'\nimport { useDashboard } from './DashboardProvider'\nimport { fieldLabel, formatMeasure, formatNumber, measureFormat } from './format'\nimport { useModelQuery } from './useModelQuery'\n\ntype ComboChartProps = {\n /** Dimensão do eixo X. */\n dimension: string\n /** Medida das barras. */\n bar: string\n /** Medida da linha (eixo próprio, oculto; os valores aparecem nos pontos). */\n line: string\n /** Medida extra mostrada como segunda linha do rótulo da barra (ex.: volume). */\n detail?: string\n /**\n * Rótulos e formatos: sem a prop, vale o `labels`/`formats` do gráfico e depois o dicionário do\n * modelo (`label`, `format`).\n */\n barLabel?: string\n lineLabel?: string\n detailLabel?: string\n formatDimension?: (value: FilterValue) => string\n formatBar?: (value: number) => string\n formatLine?: (value: number) => string\n formatDetail?: (value: number) => string\n /** Rótulo por dimensão/medida (sobrepõe o dicionário do modelo). */\n labels?: Record<string, string>\n /** Formato por medida (sobrepõe o dicionário do modelo). */\n formats?: Record<string, ChartNumberFormat>\n /** Esconde grupos cuja medida da barra é vazia/zero (como o Power BI faz). */\n hideEmpty?: boolean\n height?: number\n /** Rótulos de dados só até essa quantidade de barras (acima disso, só tooltip). */\n maxLabels?: number\n barColor?: string\n lineColor?: string\n /**\n * Clicar numa barra filtra o dashboard pelo valor dela (Ctrl/Cmd+clique acumula; clicar de novo\n * no único selecionado ou fora das barras limpa). O próprio gráfico ignora esse filtro e só\n * destaca a seleção, como o filtro cruzado do Power BI.\n */\n clickToFilter?: boolean\n /** Nome da consulta no devtools (padrão: `ComboChart · <dimensão>`). */\n queryLabel?: string\n}\n\n/** Mantém a linha na faixa de baixo do gráfico, longe dos rótulos que ficam em cima das barras. */\nconst lineDomain = ([min, max]: readonly number[]): [number, number] => {\n const range = max - min || Math.abs(max) || 1\n return [min - range * 0.3, max + range * 1.7]\n}\n\ntype Point = {\n value: FilterValue\n label: string\n bar: number\n line: number | null\n detail: number | null\n}\n\n/**\n * Barras + linha de uma dimensão, consultando o modelo do `DashboardProvider` (com os filtros dele).\n * Ex.: `<ComboChart dimension=\"mes\" bar=\"custoTotal\" line=\"custoTon\" detail=\"volTotal\" />`.\n */\nexport function ComboChart({\n dimension,\n bar,\n line,\n detail,\n barLabel,\n lineLabel,\n detailLabel,\n formatDimension = String,\n formatBar,\n formatLine,\n formatDetail,\n labels,\n formats,\n hideEmpty = true,\n height = 360,\n maxLabels = 24,\n barColor = '#F58220',\n lineColor = '#555',\n clickToFilter = false,\n queryLabel\n}: ComboChartProps) {\n const { meta, filters, setFilter } = useDashboard()\n // Prop > formato do gráfico > dicionário do modelo > padrão do componente\n // (sem `format` em nenhum dos dois, o do componente vale com as casas/prefixo de lá por cima)\n const fromModel = (measure: string, fallback: ChartNumberFormat) => {\n const format = measureFormat(meta, measure, formats)\n const resolved = format?.format ? format : { ...fallback, ...format }\n return (value: number) => formatMeasure(value, resolved, fallback.decimals)\n }\n formatBar ??= fromModel(bar, { format: 'currency', decimals: 0 })\n formatLine ??= fromModel(line, { decimals: 2 })\n formatDetail ??= detail ? fromModel(detail, { decimals: 3 }) : (value) => formatNumber(value, 3)\n barLabel ??= fieldLabel(meta, bar, labels)\n lineLabel ??= fieldLabel(meta, line, labels)\n detailLabel ??= detail && fieldLabel(meta, detail, labels)\n const dimensionLabel = fieldLabel(meta, dimension, labels)\n\n const { rows, isLoading, error, inspectProps } = useModelQuery({\n dimensions: [dimension],\n measures: detail ? [bar, line, detail] : [bar, line],\n ignoreFilters: clickToFilter ? [dimension] : undefined,\n label: queryLabel ?? `ComboChart · ${dimension}`\n })\n\n const num = (row: DashboardRow, key?: string) =>\n key && row[key] !== null && row[key] !== undefined ? Number(row[key]) : null\n\n const data: Point[] = rows\n .filter((row) => !hideEmpty || num(row, bar))\n .map((row) => ({\n value: row[dimension] ?? '',\n label: formatDimension(row[dimension] ?? ''),\n bar: num(row, bar) ?? 0,\n line: num(row, line),\n detail: num(row, detail)\n }))\n\n const showLabels = data.length <= maxLabels\n\n const selected = clickToFilter ? (filters[dimension] ?? []) : []\n const isDimmed = (point: Point) => selected.length > 0 && !selected.includes(point.value)\n\n const handleBarClick = (index: number, event: MouseEvent) => {\n // Senão o clique sobe até o container do gráfico, que limpa o filtro\n event.stopPropagation()\n const point = data[index]\n if (!point) return\n if (event.ctrlKey || event.metaKey) {\n setFilter(\n dimension,\n selected.includes(point.value)\n ? selected.filter((value) => value !== point.value)\n : [...selected, point.value]\n )\n } else {\n const onlyThis = selected.length === 1 && selected[0] === point.value\n setFilter(dimension, onlyThis ? [] : [point.value])\n }\n }\n\n const clearFilter = () => {\n if (selected.length) setFilter(dimension, [])\n }\n\n const BarValueLabel = (props: any) => {\n const point = data[props.index]\n if (!point?.bar) return null\n const cx = Number(props.x) + Number(props.width) / 2\n const lines = [\n formatBar(point.bar),\n point.detail === null ? null : formatDetail(point.detail)\n ].filter((text): text is string => !!text)\n const top = Number(props.y) - 6 - lines.length * 15\n const width = Math.max(...lines.map((text) => text.length)) * 6.8 + 10\n return (\n <g>\n <rect\n x={cx - width / 2}\n y={top}\n width={width}\n height={lines.length * 15 + 4}\n rx={2}\n fill=\"#555\"\n />\n {lines.map((text, i) => (\n <text\n key={text}\n x={cx}\n y={top + 14 + i * 15}\n textAnchor=\"middle\"\n fill=\"#fff\"\n fontSize={12}\n fontWeight={700}\n >\n {text}\n </text>\n ))}\n </g>\n )\n }\n\n const LineValueLabel = (props: any) => {\n if (props.value === null || props.value === undefined) return null\n const text = formatLine(Number(props.value))\n const width = text.length * 7 + 10\n return (\n <g>\n <rect\n x={props.x - width / 2}\n y={props.y - 9}\n width={width}\n height={18}\n rx={2}\n fill=\"#d9d9d9\"\n />\n <text\n x={props.x}\n y={props.y + 4}\n textAnchor=\"middle\"\n fill=\"#222\"\n fontSize={12}\n fontWeight={700}\n >\n {text}\n </text>\n </g>\n )\n }\n\n const ChartTooltip = ({ active, payload }: any) => {\n if (!active || !payload?.length) return null\n const point: Point = payload[0].payload\n return (\n <Box sx={{ bgcolor: '#fff', border: '1px solid #ccc', p: 1, fontSize: 13 }}>\n <Typography sx={{ fontSize: 11, color: '#777' }}>{dimensionLabel}</Typography>\n <Typography sx={{ fontWeight: 700, fontSize: 13 }}>{point.label}</Typography>\n <div>\n {barLabel}: {formatBar(point.bar)}\n </div>\n {point.detail !== null && (\n <div>\n {detailLabel}: {formatDetail(point.detail)}\n </div>\n )}\n <div>\n {lineLabel}: {point.line === null ? '' : formatLine(point.line)}\n </div>\n </Box>\n )\n }\n\n const legend = [\n { label: barLabel, color: barColor },\n { label: lineLabel, color: lineColor }\n ]\n\n return (\n <Box {...inspectProps} sx={{ minWidth: 0, position: 'relative' }}>\n <Box sx={{ display: 'flex', gap: 1.5, mb: 1, fontSize: 14, color: '#555' }}>\n {legend.map((item) => (\n <Box key={item.label} sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>\n <Box sx={{ width: 9, height: 9, borderRadius: '50%', bgcolor: item.color }} />\n {item.label}\n </Box>\n ))}\n {isLoading && <CircularProgress size={14} sx={{ ml: 'auto' }} />}\n </Box>\n {error ? (\n <Box\n sx={{\n height,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: 'error.main'\n }}\n >\n Erro ao carregar o gráfico\n </Box>\n ) : !data.length ? (\n <Box\n sx={{\n height,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: '#999'\n }}\n >\n {isLoading ? 'Carregando…' : 'Sem dados para os filtros selecionados'}\n </Box>\n ) : (\n <Box\n onClick={clickToFilter ? clearFilter : undefined}\n sx={{ height, opacity: isLoading ? 0.5 : 1, transition: 'opacity .2s' }}\n >\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <ComposedChart data={data} margin={{ top: showLabels ? 48 : 12, right: 8, left: 8 }}>\n <XAxis\n dataKey=\"label\"\n interval={0}\n tick={{ fontSize: 12, fill: '#555' }}\n tickLine={false}\n axisLine={false}\n />\n <YAxis yAxisId=\"bar\" hide domain={[0, 'auto']} />\n <YAxis yAxisId=\"line\" hide domain={lineDomain} />\n <Tooltip content={<ChartTooltip />} />\n <Bar\n yAxisId=\"bar\"\n dataKey=\"bar\"\n fill={barColor}\n isAnimationActive={false}\n onClick={\n clickToFilter ? (_bar, index, event) => handleBarClick(index, event) : undefined\n }\n cursor={clickToFilter ? 'pointer' : undefined}\n >\n {clickToFilter &&\n data.map((point) => (\n <Cell key={String(point.value)} fillOpacity={isDimmed(point) ? 0.35 : 1} />\n ))}\n {showLabels && <LabelList dataKey=\"bar\" content={<BarValueLabel />} />}\n </Bar>\n <Line\n yAxisId=\"line\"\n dataKey=\"line\"\n stroke={lineColor}\n strokeWidth={2}\n strokeDasharray=\"5 4\"\n dot={{ r: 2, fill: lineColor }}\n connectNulls\n isAnimationActive={false}\n >\n {showLabels && <LabelList dataKey=\"line\" content={<LineValueLabel />} />}\n </Line>\n </ComposedChart>\n </ResponsiveContainer>\n </Box>\n )}\n </Box>\n )\n}\n","import { useEffect, useState, useSyncExternalStore } from 'react'\nimport type { LayoutPart } from '../devtools/layoutStore'\nimport type { ChartsLayout } from '../layout'\nimport { useDashboard } from './DashboardProvider'\n\nconst noLayouts = () => () => {}\n\n/**\n * Layout em vigor: o do arquivo ou, com o devtools, o rascunho editado na aba Layout. Registra a\n * parte (`charts`/`filters`) para o devtools saber o que a página renderiza.\n */\nexport function useLayout(\n layout: ChartsLayout,\n part: LayoutPart,\n formatters: Record<string, unknown>\n): ChartsLayout {\n const { devtools } = useDashboard()\n const layouts = devtools?.layouts\n const formatterNames = Object.keys(formatters).sort().join(',')\n\n useEffect(\n () => layouts?.register(layout, part, formatterNames ? formatterNames.split(',') : []),\n [layouts, layout, part, formatterNames]\n )\n\n // Re-renderiza quando o rascunho muda\n useSyncExternalStore(\n layouts?.subscribe ?? noLayouts,\n () => layouts?.getSnapshot(),\n () => undefined\n )\n // O rascunho vem do sessionStorage: só depois de montar, para não divergir da hidratação\n const [mounted, setMounted] = useState(false)\n useEffect(() => setMounted(true), [])\n return (mounted && layouts?.draftOf(layout)) || layout\n}\n","import { Box } from '@mui/material'\nimport {\n createContext,\n type ReactNode,\n useContext,\n useEffect,\n useLayoutEffect,\n useRef,\n useState\n} from 'react'\nimport type { ChartsLayout } from '../layout'\nimport { useLayout } from './useLayout'\n\n// No servidor o useLayoutEffect só gera aviso; lá não há o que medir\nconst useIsomorphicLayoutEffect = typeof window === 'undefined' ? useEffect : useLayoutEffect\n\nconst FixedCanvasContext = createContext(false)\n\n/** Dentro de um `<DashboardCanvas>` com tamanho fixo: o grid não troca de colunas pela tela. */\nexport const useFixedCanvas = () => useContext(FixedCanvasContext)\n\ntype DashboardCanvasProps = {\n /** O mesmo layout do `<DashboardCharts>` (`canvas` do JSON). */\n layout: ChartsLayout\n children: ReactNode\n}\n\n/**\n * Tela de tamanho fixo (`layout.canvas`, ex.: 1920×1080): desenha os filhos nessa largura e escala\n * tudo para caber na largura disponível, mantendo a proporção — numa tela menor o dashboard encolhe\n * em vez de reorganizar os gráficos. Sem `canvas` no layout, só renderiza os filhos (responsivo).\n *\n * ```tsx\n * <DashboardCanvas layout={layout}>\n * <DashboardFilters layout={layout} />\n * <DashboardCharts layout={layout} />\n * </DashboardCanvas>\n * ```\n *\n * A escala é um `transform`: os gráficos continuam medindo o tamanho de projeto (o Recharts compensa\n * a escala no mouse) e os breakpoints do MUI, que olham a janela, ficam desligados no grid.\n */\nexport function DashboardCanvas({ layout, children }: DashboardCanvasProps) {\n const { canvas } = useLayout(layout, 'canvas', {})\n const outer = useRef<HTMLDivElement>(null)\n const inner = useRef<HTMLDivElement>(null)\n // Largura disponível e altura de projeto do conteúdo (offsetHeight ignora o transform)\n const [size, setSize] = useState<{ available: number; content: number } | null>(null)\n\n useIsomorphicLayoutEffect(() => {\n if (!canvas || !outer.current || !inner.current) return\n const outerElement = outer.current\n const innerElement = inner.current\n const measure = () => {\n const next = { available: outerElement.clientWidth, content: innerElement.offsetHeight }\n // Mudar a altura do outer dispara o observer de novo: só re-renderiza se mudou algo\n setSize((current) =>\n current?.available === next.available && current.content === next.content ? current : next\n )\n }\n measure()\n const observer = new ResizeObserver(measure)\n observer.observe(outerElement)\n observer.observe(innerElement)\n return () => observer.disconnect()\n }, [canvas])\n\n if (!canvas) return <>{children}</>\n\n const scale = size ? size.available / canvas.width : 1\n return (\n <FixedCanvasContext.Provider value>\n <Box\n ref={outer}\n sx={{\n width: '100%',\n overflow: 'hidden',\n height: size ? size.content * scale : undefined\n }}\n >\n <Box\n ref={inner}\n sx={{\n width: canvas.width,\n minHeight: canvas.height,\n transform: `scale(${scale})`,\n transformOrigin: '0 0',\n // Antes de medir a escala é desconhecida: evita piscar no tamanho de projeto\n visibility: size ? undefined : 'hidden'\n }}\n >\n {children}\n </Box>\n </Box>\n </FixedCanvasContext.Provider>\n )\n}\n","import {\n Box,\n CircularProgress,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n TableSortLabel\n} from '@mui/material'\nimport { useState } from 'react'\nimport { type FormatRule, type RuleStyle, rowRuleStyles } from '../formatRules'\nimport {\n type ChartNumberFormat,\n type ColumnAlign,\n type ColumnVerticalAlign,\n PERCENT_PREFIX as PERCENT,\n percentColumn,\n tableColumns\n} from '../layout'\nimport type { DashboardRow, FilterValue } from '../types'\nimport { chartPlaceholder, useClickFilter } from './chartKit'\nimport { useDashboard } from './DashboardProvider'\nimport { fieldLabel, formatNumber, measureFormatter } from './format'\nimport { useModelQuery } from './useModelQuery'\n\ntype SortDirection = 'asc' | 'desc'\n\ntype DataTableProps = {\n /** Uma linha por combinação de dimensões (sem dimensões, uma linha só). */\n dimensions?: string[]\n /** Uma coluna por medida, formatada pelo dicionário do modelo. */\n measures: string[]\n /**\n * Medidas com coluna de participação no total (valor da linha ÷ soma da coluna), logo depois da\n * coluna da medida. Medida fora de `measures` é consultada só para o percentual (coluna no fim).\n */\n percentOf?: string[]\n /** Formatter por dimensão. */\n formatDimensions?: Record<string, (value: FilterValue) => string>\n /**\n * Linha de total, consultada sem as dimensões: razões (custo/t) saem do total, não da soma das\n * linhas.\n */\n showTotal?: boolean\n /**\n * Coluna da ordem inicial (dimensão, medida ou `%:medida`); quem usa reordena clicando no\n * cabeçalho. Dimensão/medida fora da tabela entra na consulta sem coluna (ex.: número do mês para\n * ordenar o nome do mês) — uma dimensão de fora divide as linhas se tiver mais de um valor por linha.\n */\n sortBy?: string\n sortDirection?: SortDirection\n /** Clicar numa linha filtra o dashboard pela primeira dimensão. */\n clickToFilter?: boolean\n /** Altura máxima; a tabela rola com o cabeçalho fixo. */\n height?: number\n /** Cabeçalho por dimensão/medida (sobrepõe o dicionário do modelo). */\n labels?: Record<string, string>\n /** Formato por medida (sobrepõe o dicionário do modelo). */\n formats?: Record<string, ChartNumberFormat>\n /** Casas decimais das colunas de percentual. Padrão: 1. */\n percentDecimals?: number\n /**\n * Ordem das colunas misturando dimensões, medidas e percentuais (ex.: `['custoTotal',\n * '%:custoTotal', 'navio']`); o que não estiver nela vai depois. Padrão: dimensões e depois\n * medidas, cada percentual logo depois da medida.\n */\n columnOrder?: string[]\n /**\n * Formatação condicional: cor do texto/fundo e negrito da célula ou da linha conforme o valor de\n * uma dimensão/medida (da tabela, de fora dela ou `%:medida`).\n */\n formatRules?: FormatRule[]\n /** Bordas entre as células (grade). Padrão: só a linha embaixo de cada linha. */\n cellBorders?: boolean\n /** Cor das bordas da grade. Padrão: `#e0e0e0`. */\n borderColor?: string\n /**\n * Alinhamento horizontal por coluna (`%:medida` para o percentual): cabeçalho, células e total.\n * Padrão: dimensão à esquerda, número à direita.\n */\n align?: Record<string, ColumnAlign>\n /** Alinhamento vertical por coluna (`top`, `middle`, `bottom`). Padrão: `middle`. */\n verticalAlign?: Record<string, ColumnVerticalAlign>\n /** Nome da consulta no devtools. */\n queryLabel?: string\n}\n\nconst EMPTY: string[] = []\nconst NO_RULES: FormatRule[] = []\n\nfunction compare(a: DashboardRow[string], b: DashboardRow[string]) {\n // Vazios sempre por último, nas duas direções (tratado por quem chama)\n if (typeof a === 'number' && typeof b === 'number') return a - b\n return String(a).localeCompare(String(b), 'pt-BR', { numeric: true })\n}\n\n/**\n * Tabela de medidas por dimensões, com total e ordenação pelo cabeçalho. Ex.:\n * `<DataTable dimensions={['navio']} measures={['volTotal', 'custoTotal', 'custoTon']} />`.\n */\nexport function DataTable({\n dimensions = EMPTY,\n measures,\n percentOf = EMPTY,\n formatDimensions = {},\n showTotal = true,\n sortBy,\n sortDirection = 'desc',\n clickToFilter = false,\n height = 400,\n labels,\n formats: formatsByMeasure,\n percentDecimals = 1,\n columnOrder,\n formatRules = NO_RULES,\n cellBorders = false,\n borderColor = '#e0e0e0',\n align,\n verticalAlign,\n queryLabel\n}: DataTableProps) {\n const { meta } = useDashboard()\n const name = queryLabel ?? `DataTable · ${dimensions.join(', ') || 'total'}`\n const firstDimension = dimensions[0]\n const ignoreFilters = clickToFilter && firstDimension ? [firstDimension] : undefined\n const extraMeasures = percentOf.filter((measure) => !measures.includes(measure))\n // Dimensões/medidas fora da tabela (ordem inicial, regras): consultadas sem coluna. Saber se é\n // dimensão ou medida depende do dicionário; até ele chegar, a consulta espera\n const outside = [\n ...new Set([sortBy, ...formatRules.map((rule) => rule.field)].filter(Boolean) as string[])\n ].filter(\n (field) =>\n !field.startsWith(PERCENT) &&\n !dimensions.includes(field) &&\n !measures.includes(field) &&\n !extraMeasures.includes(field)\n )\n const waitingMeta = outside.length > 0 && !meta\n const queryDimensions = [...dimensions, ...outside.filter((field) => meta?.dimensions[field])]\n const { rows, isLoading, error, inspectProps } = useModelQuery({\n dimensions: queryDimensions,\n measures: [\n ...measures,\n ...extraMeasures,\n ...outside.filter((field) => meta?.measures[field] && !meta.dimensions[field])\n ],\n ignoreFilters,\n label: name,\n skip: waitingMeta\n })\n // Sem dimensões a própria consulta já é o total\n const totals = useModelQuery({\n measures,\n ignoreFilters,\n label: `${name} · total`,\n skip: !showTotal || !dimensions.length\n })\n const filter = useClickFilter(firstDimension, clickToFilter)\n\n const [sort, setSort] = useState<{ by?: string; direction: SortDirection }>({\n by: sortBy,\n direction: sortDirection\n })\n // Props mudaram (ex.: devtools): volta para a ordem configurada\n const [configured, setConfigured] = useState([sortBy, sortDirection])\n if (configured[0] !== sortBy || configured[1] !== sortDirection) {\n setConfigured([sortBy, sortDirection])\n setSort({ by: sortBy, direction: sortDirection })\n }\n\n // O percentual ordena igual à medida\n const sortKey = sort.by?.startsWith(PERCENT) ? sort.by.slice(PERCENT.length) : sort.by\n const sorted = sortKey\n ? [...rows].sort((a, b) => {\n const [x, y] = [a[sortKey], b[sortKey]]\n if (x === null || x === undefined) return 1\n if (y === null || y === undefined) return -1\n return sort.direction === 'asc' ? compare(x, y) : compare(y, x)\n })\n : rows\n\n const formats = Object.fromEntries(\n measures.map((measure) => [measure, measureFormatter(meta, measure, 2, formatsByMeasure)])\n )\n const formatPercent = (value: number | null) =>\n value === null ? '' : `${formatNumber(value * 100, percentDecimals)}%`\n const dimensionText = (dimension: string, value: DashboardRow[string]) =>\n value === null || value === undefined\n ? '(vazio)'\n : (formatDimensions[dimension] ?? String)(value)\n const labelOf = (column: string) => fieldLabel(meta, column, labels)\n const headerOf = (column: string) => {\n if (!column.startsWith(PERCENT)) return labelOf(column)\n const measure = column.slice(PERCENT.length)\n return measures.includes(measure) ? '%' : `% ${labelOf(measure)}`\n }\n\n // Total de cada medida com percentual: soma das linhas mostradas\n const sums = Object.fromEntries(\n percentOf.map((measure) => [\n measure,\n rows.reduce((total, row) => total + (Number(row[measure]) || 0), 0)\n ])\n )\n const percentOfRow = (row: DashboardRow, measure: string) => {\n const value = row[measure]\n const total = sums[measure]\n return value === null || value === undefined || !total ? null : Number(value) / total\n }\n // Colunas na ordem configurada; percentual fora dela logo depois da medida (avulsos no fim)\n const columns = tableColumns(\n [...dimensions, ...measures],\n percentOf.filter((measure) => !dimensions.includes(measure)),\n columnOrder\n )\n // Estilo das regras por coluna; percentuais entram na linha avaliada como `%:medida`\n const ruleStyles = (row: DashboardRow): Record<string, RuleStyle> | undefined => {\n if (!formatRules.length) return undefined\n const evaluated = { ...row }\n for (const measure of percentOf) evaluated[percentColumn(measure)] = percentOfRow(row, measure)\n return rowRuleStyles(formatRules, evaluated, columns)\n }\n const ruleSx = (style: RuleStyle | undefined) =>\n style && {\n ...(style.color && { color: style.color }),\n ...(style.background && { bgcolor: style.background }),\n ...(style.bold && { fontWeight: 700 }),\n ...(style.align && { textAlign: style.align }),\n ...(style.verticalAlign && { verticalAlign: style.verticalAlign })\n }\n const isDimension = (column: string) => dimensions.includes(column)\n const alignOf = (column: string) => align?.[column] ?? (isDimension(column) ? 'left' : 'right')\n const verticalOf = (column: string) => verticalAlign?.[column] ?? 'middle'\n // \"Total\" vai na primeira coluna de dimensão da tabela\n const totalLabelColumn = columns.find(isDimension)\n const cellText = (row: DashboardRow, column: string) =>\n column.startsWith(PERCENT)\n ? formatPercent(percentOfRow(row, column.slice(PERCENT.length)))\n : formats[column]?.(row[column])\n\n const toggleSort = (column: string) =>\n setSort((current) =>\n current.by === column\n ? { by: column, direction: current.direction === 'asc' ? 'desc' : 'asc' }\n : // Medidas começam do maior; dimensões, em ordem alfabética\n { by: column, direction: dimensions.includes(column) ? 'asc' : 'desc' }\n )\n\n const totalRow = dimensions.length ? totals.rows[0] : undefined\n const loading = isLoading || waitingMeta\n const placeholder = chartPlaceholder({\n height: 160,\n error,\n isLoading: loading,\n empty: !rows.length\n })\n\n const header = (column: string, numeric: boolean) => (\n <TableCell\n key={column}\n align={alignOf(column)}\n sortDirection={sort.by === column ? sort.direction : false}\n sx={{\n fontWeight: 700,\n bgcolor: '#f3f3f3',\n whiteSpace: 'nowrap',\n verticalAlign: verticalOf(column)\n }}\n >\n <TableSortLabel\n active={sort.by === column}\n direction={sort.by === column ? sort.direction : numeric ? 'desc' : 'asc'}\n onClick={() => toggleSort(column)}\n >\n {headerOf(column)}\n </TableSortLabel>\n </TableCell>\n )\n\n return (\n <Box {...inspectProps} sx={{ minWidth: 0, position: 'relative' }}>\n {loading && <CircularProgress size={14} sx={{ position: 'absolute', top: -22, right: 0 }} />}\n {placeholder ?? (\n <Box\n sx={{\n maxHeight: height,\n overflow: 'auto',\n opacity: loading ? 0.5 : 1,\n transition: 'opacity .2s'\n }}\n >\n <Table\n size=\"small\"\n stickyHeader\n sx={{\n '& td, & th': {\n fontSize: 13,\n ...(cellBorders && { border: `1px solid ${borderColor}` })\n }\n }}\n >\n <TableHead>\n <TableRow>{columns.map((column) => header(column, !isDimension(column)))}</TableRow>\n </TableHead>\n <TableBody>\n {sorted.map((row) => {\n const value = firstDimension ? row[firstDimension] : null\n const clickable = clickToFilter && value !== null && value !== undefined\n const styles = ruleStyles(row)\n return (\n <TableRow\n key={queryDimensions.map((dimension) => String(row[dimension])).join('\\u0000')}\n hover\n onClick={clickable ? (event) => filter.toggle(value, event) : undefined}\n selected={clickable && filter.selected.includes(value)}\n sx={{\n cursor: clickable ? 'pointer' : undefined,\n opacity: clickable && filter.isDimmed(value) ? 0.5 : 1\n }}\n >\n {columns.map((column) =>\n isDimension(column) ? (\n <TableCell\n key={column}\n align={alignOf(column)}\n sx={{ verticalAlign: verticalOf(column), ...ruleSx(styles?.[column]) }}\n >\n {dimensionText(column, row[column])}\n </TableCell>\n ) : (\n <TableCell\n key={column}\n align={alignOf(column)}\n sx={{\n whiteSpace: 'nowrap',\n verticalAlign: verticalOf(column),\n ...ruleSx(styles?.[column])\n }}\n >\n {cellText(row, column)}\n </TableCell>\n )\n )}\n </TableRow>\n )\n })}\n {totalRow && (\n <TableRow\n sx={{\n '& td': {\n fontWeight: 700,\n position: 'sticky',\n bottom: 0,\n bgcolor: '#f3f3f3',\n borderTop: '2px solid #ddd'\n }\n }}\n >\n {columns.map((column) =>\n isDimension(column) ? (\n <TableCell\n key={column}\n align={alignOf(column)}\n sx={{ verticalAlign: verticalOf(column) }}\n >\n {column === totalLabelColumn ? 'Total' : ''}\n </TableCell>\n ) : (\n <TableCell\n key={column}\n align={alignOf(column)}\n sx={{ whiteSpace: 'nowrap', verticalAlign: verticalOf(column) }}\n >\n {column.startsWith(PERCENT)\n ? formatPercent(sums[column.slice(PERCENT.length)] ? 1 : null)\n : formats[column]?.(totalRow[column])}\n </TableCell>\n )\n )}\n </TableRow>\n )}\n </TableBody>\n </Table>\n </Box>\n )}\n </Box>\n )\n}\n","import { Box } from '@mui/material'\nimport { Cell, Pie, PieChart, ResponsiveContainer, Tooltip } from 'recharts'\nimport type { ChartNumberFormat, DonutLegendPosition, DonutValueContent } from '../layout'\nimport type { FilterValue } from '../types'\nimport {\n chartPlaceholder,\n numberOf,\n OTHER_COLOR,\n seriesColor,\n TooltipBox,\n useClickFilter\n} from './chartKit'\nimport { useDashboard } from './DashboardProvider'\nimport { fieldLabel, formatNumber, measureFormatter } from './format'\nimport { useModelQuery } from './useModelQuery'\n\ntype DonutChartProps = {\n /** Dimensão das fatias. */\n dimension: string\n /** Medida somável (partes de um total). Valores negativos ou zerados ficam de fora. */\n measure: string\n /** Fatias além dessa quantidade viram \"Outros\" (no máximo 8, o tamanho da paleta). */\n maxSlices?: number\n formatDimension?: (value: FilterValue) => string\n clickToFilter?: boolean\n height?: number\n /** Rótulo por dimensão/medida (sobrepõe o dicionário do modelo). */\n labels?: Record<string, string>\n /** Formato por medida (sobrepõe o dicionário do modelo). */\n formats?: Record<string, ChartNumberFormat>\n /** Casas decimais do percentual. Padrão: 1. */\n percentDecimals?: number\n /** Lado da legenda. Padrão: `right` (nome, % e valor; em cima/embaixo, só o nome, em linha). */\n legendPosition?: DonutLegendPosition\n /** Valor de cada fatia do lado de fora da rosca. */\n showValues?: boolean\n /** O que o valor de fora mostra. Padrão: `both` (`44.981 (51%)`). */\n valueContent?: DonutValueContent\n /** Total no furo da rosca. Padrão: `true`. */\n showTotal?: boolean\n /** Nome da consulta no devtools. */\n queryLabel?: string\n}\n\ntype Slice = {\n key: string\n value: FilterValue | null\n label: string\n amount: number\n color: string\n}\n\nconst OTHERS = 'Outros'\n/** Fatia abaixo dessa fração fica sem valor de fora (os rótulos se atropelariam); tem o tooltip. */\nconst MIN_VALUE_SHARE = 0.02\nconst RADIAN = Math.PI / 180\n\n/** Direção da caixa (rosca + legenda) conforme o lado da legenda. */\nconst LEGEND_DIRECTION = {\n right: 'row',\n left: 'row-reverse',\n top: 'column-reverse',\n bottom: 'column'\n} as const\n\n/**\n * Rosca de uma medida por uma dimensão, com o total no centro e a legenda ao lado (nome, % e valor)\n * ou em cima/embaixo; `showValues` põe o valor de cada fatia do lado de fora.\n * Ex.: `<DonutChart dimension=\"operacao_status\" measure=\"custoTotal\" />`.\n */\nexport function DonutChart({\n dimension,\n measure,\n maxSlices = 6,\n formatDimension = String,\n clickToFilter = false,\n height = 300,\n labels,\n formats,\n percentDecimals = 1,\n legendPosition = 'right',\n showValues = false,\n valueContent = 'both',\n showTotal = true,\n queryLabel\n}: DonutChartProps) {\n const { meta } = useDashboard()\n const { rows, isLoading, error, inspectProps } = useModelQuery({\n dimensions: [dimension],\n measures: [measure],\n ignoreFilters: clickToFilter ? [dimension] : undefined,\n label: queryLabel ?? `DonutChart · ${dimension}`\n })\n const filter = useClickFilter(dimension, clickToFilter)\n const format = measureFormatter(meta, measure, 0, formats)\n\n const positive = rows\n .map((row) => ({ value: row[dimension] ?? '', amount: numberOf(row, measure) ?? 0 }))\n .filter((item) => item.amount > 0)\n .sort((a, b) => b.amount - a.amount)\n const limit = Math.min(Math.max(maxSlices, 2), 8)\n // Com fatias sobrando, a última vaga vira \"Outros\"\n const kept = positive.length > limit ? positive.slice(0, limit - 1) : positive\n const rest = positive.slice(kept.length)\n // A cor segue a posição na ordem (maior = laranja); \"Outros\" é neutro\n const slices: Slice[] = kept.map((item, index) => ({\n key: String(item.value),\n value: item.value,\n label: formatDimension(item.value),\n amount: item.amount,\n color: seriesColor(index)\n }))\n if (rest.length)\n slices.push({\n key: `\\u0000${OTHERS}`,\n value: null,\n label: `${OTHERS} (${rest.length})`,\n amount: rest.reduce((total, item) => total + item.amount, 0),\n color: OTHER_COLOR\n })\n const total = slices.reduce((sum, slice) => sum + slice.amount, 0)\n const percent = (amount: number) => `${formatNumber((amount / total) * 100, percentDecimals)}%`\n\n const placeholder = chartPlaceholder({ height, error, isLoading, empty: !slices.length })\n\n const select = (slice: Slice | undefined, event?: { ctrlKey: boolean; metaKey: boolean }) => {\n if (slice?.value !== null && slice?.value !== undefined) filter.toggle(slice.value, event)\n }\n const dimmed = (slice: Slice) =>\n filter.selected.length > 0 && (slice.value === null || filter.isDimmed(slice.value))\n\n const valueText = (amount: number) =>\n valueContent === 'value'\n ? format(amount)\n : valueContent === 'percent'\n ? percent(amount)\n : `${format(amount)} (${percent(amount)})`\n\n // Valor fora da fatia, na direção do meio dela; o lado define o alinhamento do texto\n const SliceValue = ({ cx, cy, midAngle, outerRadius, payload }: any) => {\n const slice: Slice = payload\n if (slice.amount / total < MIN_VALUE_SHARE) return null\n const radius = outerRadius + 10\n const cos = Math.cos(-midAngle * RADIAN)\n const x = cx + radius * cos\n const y = cy + radius * Math.sin(-midAngle * RADIAN)\n return (\n <text\n x={x}\n y={y}\n textAnchor={Math.abs(cos) < 0.15 ? 'middle' : cos > 0 ? 'start' : 'end'}\n dominantBaseline=\"central\"\n fontSize={12}\n fill=\"#333\"\n opacity={dimmed(slice) ? 0.45 : 1}\n >\n {valueText(slice.amount)}\n </text>\n )\n }\n\n const side = legendPosition === 'left' || legendPosition === 'right'\n\n const SliceTooltip = ({ active, payload }: any) => {\n if (!active || !payload?.length) return null\n const slice: Slice = payload[0].payload\n return (\n <TooltipBox title={slice.label} caption={fieldLabel(meta, dimension, labels)}>\n {fieldLabel(meta, measure, labels)}: {format(slice.amount)} · {percent(slice.amount)}\n </TooltipBox>\n )\n }\n\n return (\n <Box {...inspectProps} sx={{ minWidth: 0, position: 'relative' }}>\n {placeholder ?? (\n <Box\n sx={{\n height,\n display: 'flex',\n flexDirection: LEGEND_DIRECTION[legendPosition],\n alignItems: side ? 'center' : 'stretch',\n gap: side ? 2 : 1,\n opacity: isLoading ? 0.5 : 1,\n transition: 'opacity .2s'\n }}\n >\n <Box\n sx={{\n position: 'relative',\n minWidth: 140,\n minHeight: 0,\n // Com o valor de fora, a rosca precisa de mais espaço que a legenda\n ...(side\n ? { height: '100%', flex: showValues ? '1 1 0' : '0 0 50%' }\n : { flex: '1 1 0' })\n }}\n >\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <PieChart>\n <Tooltip content={<SliceTooltip />} />\n <Pie\n data={slices}\n dataKey=\"amount\"\n nameKey=\"label\"\n innerRadius={showValues ? '46%' : '62%'}\n outerRadius={showValues ? '68%' : '92%'}\n startAngle={90}\n endAngle={-270}\n stroke=\"#fff\"\n strokeWidth={2}\n isAnimationActive={false}\n label={showValues ? SliceValue : false}\n labelLine={false}\n onClick={(_, index, event) => select(slices[index], event)}\n cursor={clickToFilter ? 'pointer' : undefined}\n >\n {slices.map((slice) => (\n <Cell\n key={slice.key}\n fill={slice.color}\n fillOpacity={dimmed(slice) ? 0.35 : 1}\n />\n ))}\n </Pie>\n </PieChart>\n </ResponsiveContainer>\n {/* Total no furo da rosca */}\n {showTotal && (\n <Box\n sx={{\n position: 'absolute',\n inset: 0,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n pointerEvents: 'none',\n textAlign: 'center'\n }}\n >\n <Box sx={{ fontSize: 12, color: '#777' }}>Total</Box>\n <Box sx={{ fontSize: 15, fontWeight: 700, color: '#333' }}>{format(total)}</Box>\n </Box>\n )}\n </Box>\n {side ? (\n <Box\n component=\"ul\"\n sx={{\n listStyle: 'none',\n m: 0,\n p: 0,\n minWidth: 0,\n flex: showValues ? '0 1 auto' : 1,\n maxWidth: showValues ? '45%' : undefined,\n overflow: 'auto',\n maxHeight: '100%'\n }}\n >\n {slices.map((slice) => (\n <Box\n component=\"li\"\n key={slice.key}\n onClick={(event) => select(slice, event)}\n sx={{\n display: 'grid',\n gridTemplateColumns: '10px minmax(0, 1fr) auto',\n alignItems: 'center',\n columnGap: 0.75,\n py: 0.5,\n fontSize: 13,\n color: '#333',\n opacity: dimmed(slice) ? 0.45 : 1,\n cursor: clickToFilter && slice.value !== null ? 'pointer' : undefined\n }}\n >\n <Box sx={{ width: 10, height: 10, borderRadius: '50%', bgcolor: slice.color }} />\n <Box sx={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>\n {slice.label}\n </Box>\n <Box sx={{ fontWeight: 700, textAlign: 'right' }}>{percent(slice.amount)}</Box>\n <Box />\n <Box sx={{ gridColumn: '2 / 4', fontSize: 12, color: '#777' }}>\n {format(slice.amount)}\n </Box>\n </Box>\n ))}\n </Box>\n ) : (\n <Box\n component=\"ul\"\n sx={{\n listStyle: 'none',\n m: 0,\n p: 0,\n display: 'flex',\n flexWrap: 'wrap',\n justifyContent: 'center',\n columnGap: 1.5,\n rowGap: 0.25,\n flex: '0 0 auto',\n maxHeight: '40%',\n overflow: 'auto'\n }}\n >\n {slices.map((slice) => (\n <Box\n component=\"li\"\n key={slice.key}\n title={`${format(slice.amount)} · ${percent(slice.amount)}`}\n onClick={(event) => select(slice, event)}\n sx={{\n display: 'flex',\n alignItems: 'center',\n gap: 0.5,\n fontSize: 13,\n color: '#333',\n whiteSpace: 'nowrap',\n opacity: dimmed(slice) ? 0.45 : 1,\n cursor: clickToFilter && slice.value !== null ? 'pointer' : undefined\n }}\n >\n <Box\n sx={{\n width: 10,\n height: 10,\n borderRadius: '50%',\n bgcolor: slice.color,\n flex: '0 0 auto'\n }}\n />\n {slice.label}\n </Box>\n ))}\n </Box>\n )}\n </Box>\n )}\n </Box>\n )\n}\n","import { Box, CircularProgress } from '@mui/material'\nimport type { ChartNumberFormat } from '../layout'\nimport { numberOf } from './chartKit'\nimport { useDashboard } from './DashboardProvider'\nimport { fieldLabel, measureFormatter } from './format'\nimport { useModelQuery } from './useModelQuery'\n\ntype KpiCardProps = {\n /** Medida do número grande: o total com os filtros da página. */\n measure: string\n /** Rótulo acima do número (no `<DashboardCharts>`, o título do painel faz esse papel). */\n label?: string\n /** Medida extra numa linha menor embaixo (ex.: volume, custo/t). */\n secondary?: string\n /** Padrão: `labels[secondary]` ou o `label` da medida secundária no dicionário. */\n secondaryLabel?: string\n /** Rótulo por medida (sobrepõe o dicionário); o da principal entra quando não há `label`. */\n labels?: Record<string, string>\n /** Formato por medida (sobrepõe o dicionário). */\n formats?: Record<string, ChartNumberFormat>\n /** Nome da consulta no devtools. */\n queryLabel?: string\n}\n\n/**\n * Card com o total de uma medida (e, opcionalmente, uma segunda medida embaixo). Uma consulta sem\n * dimensões: razões (custo/t) saem do total, não de uma média. Ex.:\n * `<KpiCard label=\"Custo total\" measure=\"custoTotal\" secondary=\"custoTon\" />`.\n */\nexport function KpiCard({\n measure,\n label,\n secondary,\n secondaryLabel,\n labels,\n formats,\n queryLabel\n}: KpiCardProps) {\n const { meta } = useDashboard()\n const { rows, isLoading, error, inspectProps } = useModelQuery({\n measures: secondary ? [measure, secondary] : [measure],\n label: queryLabel ?? `KpiCard · ${measure}`\n })\n const row = rows[0]\n const value = row ? numberOf(row, measure) : null\n const extra = row && secondary ? numberOf(row, secondary) : null\n label ??= labels?.[measure]\n\n return (\n <Box {...inspectProps} sx={{ minWidth: 0, position: 'relative' }}>\n {label && <Box sx={{ fontSize: 13, color: '#666', mb: 0.5 }}>{label}</Box>}\n {isLoading && <CircularProgress size={12} sx={{ position: 'absolute', top: 0, right: 0 }} />}\n <Box\n sx={{\n fontSize: 28,\n fontWeight: 700,\n lineHeight: 1.2,\n color: error ? 'error.main' : '#333',\n fontVariantNumeric: 'tabular-nums',\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n opacity: isLoading ? 0.5 : 1,\n transition: 'opacity .2s'\n }}\n >\n {error ? 'Erro' : value === null ? '—' : measureFormatter(meta, measure, 0, formats)(value)}\n </Box>\n {secondary && (\n <Box sx={{ fontSize: 13, color: '#666', mt: 0.25, minHeight: 20 }}>\n {secondaryLabel ?? fieldLabel(meta, secondary, labels)}:{' '}\n <Box component=\"span\" sx={{ fontWeight: 600, color: '#444' }}>\n {extra === null ? '—' : measureFormatter(meta, secondary, 2, formats)(extra)}\n </Box>\n </Box>\n )}\n </Box>\n )\n}\n","import { Box, Paper, Typography } from '@mui/material'\nimport type { ComponentType, ReactNode } from 'react'\nimport { LAYOUT_ITEM_ATTRIBUTE, layoutItemKey } from '../devtools/layoutStore'\nimport {\n type CardStyle,\n type ChartDef,\n type ChartsLayout,\n cardsGap,\n chartCardStyle,\n customChartProps,\n isBuiltinChart,\n LAYOUT_COLUMNS\n} from '../layout'\nimport type { FilterValue } from '../types'\nimport { BarChart } from './BarChart'\nimport { ComboChart } from './ComboChart'\nimport { useFixedCanvas } from './DashboardCanvas'\nimport { useDashboard } from './DashboardProvider'\nimport { DataTable } from './DataTable'\nimport { DonutChart } from './DonutChart'\nimport { KpiCard } from './KpiCard'\nimport { useLayout } from './useLayout'\n\nexport type ChartPanelProps = {\n title: string\n chart: ChartDef\n /** Estilo do card (`cards` do layout com o `card` do gráfico por cima); vazio = padrão. */\n card: CardStyle\n children: ReactNode\n}\n\ntype DashboardChartsProps = {\n /** Layout importado do JSON (`src/dashboard/layouts/<id>.json`). */\n layout: ChartsLayout\n /** Formatters por nome, referenciados no JSON por `formatDimension`. */\n formatters?: Record<string, (value: FilterValue) => string>\n /** Moldura de cada gráfico (título + conteúdo). */\n panel?: ComponentType<ChartPanelProps>\n /** Espaço entre os cards (unidades do `theme.spacing`); `cards.rowGap`/`columnGap` do layout (px) têm prioridade. */\n gap?: number\n}\n\nconst px = (value: number | undefined) => (value === undefined ? undefined : `${value}px`)\n\n/** Tira as chaves `undefined`, para o estilo do layout só sobrepor o que foi definido. */\nconst defined = <T extends object>(object: T) =>\n Object.fromEntries(\n Object.entries(object).filter(([, value]) => value !== undefined)\n ) as Partial<T>\n\n/**\n * `sx` da moldura de um card com o estilo do layout (`card` do `panel`). Só traz o que o layout\n * definiu, para um `panel` do app espalhar por cima do visual dele:\n * `<Paper sx={{ p: 2, borderRadius: 0, ...chartCardSx(card) }}>`.\n */\nexport function chartCardSx(card: CardStyle) {\n return {\n // Sem `CssBaseline` no app o padrão é `content-box`: com `height: 100%`, padding e borda\n // somariam à altura e o card vazaria da célula do grid por cima do espaço entre as linhas\n boxSizing: 'border-box' as const,\n ...defined({\n p: px(card.padding),\n bgcolor: card.background,\n borderWidth: px(card.borderWidth),\n borderStyle: card.borderWidth === undefined ? undefined : 'solid',\n borderColor: card.borderColor,\n borderRadius: px(card.borderRadius),\n boxShadow: card.shadow\n })\n }\n}\n\n/** `sx` do título de um card com o estilo do layout (idem `chartCardSx`). */\nexport function chartTitleSx(card: CardStyle) {\n return defined({\n color: card.titleColor,\n fontSize: px(card.titleSize),\n textAlign: card.titleAlign\n })\n}\n\nfunction DefaultPanel({ title, card, children }: ChartPanelProps) {\n return (\n <Paper\n elevation={0}\n sx={{\n p: 1.5,\n minWidth: 0,\n height: '100%',\n border: '1px solid',\n borderColor: 'divider',\n ...chartCardSx(card)\n }}\n >\n {title && (\n <Typography sx={{ fontWeight: 700, mb: 1, ...chartTitleSx(card) }}>{title}</Typography>\n )}\n {children}\n </Paper>\n )\n}\n\n/**\n * Renderiza os gráficos de um layout declarativo num grid de 12 colunas (no celular, um por linha;\n * dentro de um `<DashboardCanvas>` de tamanho fixo, sempre as 12). Em desenvolvimento, a aba\n * Layout do devtools edita esse layout ao vivo (rascunho) e grava o JSON de volta.\n *\n * ```tsx\n * import layout from '@/dashboard/layouts/analiseCusto.json'\n * <DashboardCharts layout={layout as ChartsLayout} formatters={{ nomeMes }} panel={Panel} />\n * ```\n */\nexport function DashboardCharts({\n layout,\n formatters = {},\n panel: Panel = DefaultPanel,\n gap = 1.5\n}: DashboardChartsProps) {\n const current = useLayout(layout, 'charts', formatters)\n const { charts } = current\n // Tela fixa: a janela não decide as colunas, o canvas é que escala\n const fixed = useFixedCanvas()\n const columns = `repeat(${LAYOUT_COLUMNS}, minmax(0, 1fr))`\n const space = cardsGap(current.cards)\n\n return (\n <Box\n sx={{\n display: 'grid',\n rowGap: px(space.row) ?? gap,\n columnGap: px(space.column) ?? gap,\n gridTemplateColumns: fixed ? columns : { xs: '1fr', lg: columns }\n }}\n >\n {charts.map((chart) => (\n <Box\n key={chart.id}\n {...{\n [LAYOUT_ITEM_ATTRIBUTE]: layoutItemKey(layout.id, { kind: 'chart', key: chart.id })\n }}\n sx={{\n minWidth: 0,\n gridColumn: fixed\n ? `span ${chart.span ?? LAYOUT_COLUMNS}`\n : { lg: `span ${chart.span ?? LAYOUT_COLUMNS}` }\n }}\n >\n <Panel title={chart.title} chart={chart} card={chartCardStyle(current, chart)}>\n <Chart chart={chart} formatters={formatters} />\n </Panel>\n </Box>\n ))}\n </Box>\n )\n}\n\ntype Formatters = Record<string, (value: FilterValue) => string>\n\nfunction Chart({ chart, formatters }: { chart: ChartDef; formatters: Formatters }) {\n const { chartTypes, chartComponents } = useDashboard()\n if (!isBuiltinChart(chart)) {\n const Component = chartComponents[chart.type]\n if (Component) return <Component {...customChartProps(chart, chartTypes, formatters)} />\n return <UnknownChart type={chart.type} />\n }\n const queryLabel = `${chart.title || chart.id} · ${chart.type}`\n const formatter = (name?: string) => (name ? formatters[name] : undefined)\n switch (chart.type) {\n case 'kpi': {\n const { id, type, title, span, card, ...props } = chart\n return <KpiCard {...props} queryLabel={queryLabel} />\n }\n case 'combo': {\n const { id, type, title, span, card, formatDimension, ...props } = chart\n return (\n <ComboChart\n {...props}\n queryLabel={queryLabel}\n formatDimension={formatter(formatDimension)}\n />\n )\n }\n case 'bar': {\n const { id, type, title, span, card, formatDimension, formatSeries, ...props } = chart\n return (\n <BarChart\n {...props}\n queryLabel={queryLabel}\n formatDimension={formatter(formatDimension)}\n formatSeries={formatter(formatSeries)}\n />\n )\n }\n case 'donut': {\n const { id, type, title, span, card, formatDimension, ...props } = chart\n return (\n <DonutChart\n {...props}\n queryLabel={queryLabel}\n formatDimension={formatter(formatDimension)}\n />\n )\n }\n case 'table': {\n const { id, type, title, span, card, formatDimensions, ...props } = chart\n const resolved: Formatters = {}\n for (const [dimension, name] of Object.entries(formatDimensions ?? {})) {\n const format = formatter(name)\n if (format) resolved[dimension] = format\n }\n return <DataTable {...props} queryLabel={queryLabel} formatDimensions={resolved} />\n }\n default:\n return <UnknownChart type={(chart as { type: unknown }).type} />\n }\n}\n\nfunction UnknownChart({ type }: { type: unknown }) {\n return (\n <Box sx={{ color: 'error.main', p: 2 }}>\n Tipo de gráfico desconhecido: {String(type)} (tipos do app vão no{' '}\n <code>{'<DashboardProvider charts>'}</code>)\n </Box>\n )\n}\n","import {\n Checkbox,\n FormControl,\n InputLabel,\n ListItemText,\n MenuItem,\n OutlinedInput,\n Select\n} from '@mui/material'\nimport type { FilterValue } from '../types'\nimport { useDashboard } from './DashboardProvider'\nimport { useModelQuery } from './useModelQuery'\n\ntype FilterSelectProps = {\n dimension: string\n /** Padrão: `label` da dimensão no dicionário do modelo. */\n label?: string\n formatLabel?: (value: FilterValue) => string\n width?: number\n}\n\n/**\n * Filtro de múltipla escolha de uma dimensão. As opções vêm do próprio modelo e respeitam os\n * DEMAIS filtros (filtro cruzado): com Mês = Janeiro, o filtro de navio só lista quem atracou em\n * janeiro. Nada selecionado = \"Todos\".\n */\nexport function FilterSelect({\n dimension,\n label,\n formatLabel = String,\n width = 200\n}: FilterSelectProps) {\n const { filters, setFilter, meta } = useDashboard()\n label ??= meta?.dimensions[dimension]?.label ?? dimension\n const { rows, inspectProps } = useModelQuery({\n dimensions: [dimension],\n ignoreFilters: [dimension],\n label: `FilterSelect · ${dimension}`\n })\n\n const selected = filters[dimension] ?? []\n const options = rows\n .map((row) => row[dimension])\n .filter((value): value is FilterValue => value !== null && value !== '')\n // Mantém visíveis valores selecionados que sumiram das opções por causa de outro filtro\n for (const value of selected) if (!options.includes(value)) options.push(value)\n\n return (\n <FormControl {...inspectProps} size=\"small\" sx={{ width }}>\n <InputLabel shrink>{label}</InputLabel>\n <Select<FilterValue[]>\n multiple\n displayEmpty\n value={selected}\n onChange={(event) => setFilter(dimension, event.target.value as FilterValue[])}\n input={<OutlinedInput notched label={label} />}\n renderValue={(values) => (values.length ? values.map(formatLabel).join(', ') : 'Todos')}\n MenuProps={{ slotProps: { paper: { sx: { maxHeight: 360 } } } }}\n sx={{ bgcolor: '#fff' }}\n >\n {options.map((option) => (\n <MenuItem key={option} value={option} dense>\n <Checkbox size=\"small\" checked={selected.includes(option)} sx={{ p: 0.5, mr: 1 }} />\n <ListItemText primary={formatLabel(option)} />\n </MenuItem>\n ))}\n </Select>\n </FormControl>\n )\n}\n","import { Box } from '@mui/material'\nimport { LAYOUT_ITEM_ATTRIBUTE, layoutItemKey } from '../devtools/layoutStore'\nimport type { ChartsLayout } from '../layout'\nimport type { FilterValue } from '../types'\nimport { FilterSelect } from './FilterSelect'\nimport { useLayout } from './useLayout'\n\ntype DashboardFiltersProps = {\n /** O mesmo layout do `<DashboardCharts>` (`filters` do JSON). */\n layout: ChartsLayout\n /** Formatters por nome, referenciados no JSON por `formatLabel`. */\n formatters?: Record<string, (value: FilterValue) => string>\n gap?: number\n}\n\n/**\n * Filtros (slicers) declarados em `layout.filters`, na ordem. Em desenvolvimento, a aba Layout do\n * devtools adiciona, remove, reordena e edita os filtros ao vivo.\n */\nexport function DashboardFilters({ layout, formatters = {}, gap = 2 }: DashboardFiltersProps) {\n const { filters = [] } = useLayout(layout, 'filters', formatters)\n return (\n <Box sx={{ display: 'flex', flexWrap: 'wrap', gap }}>\n {filters.map((filter) => (\n <Box\n key={filter.dimension}\n {...{\n [LAYOUT_ITEM_ATTRIBUTE]: layoutItemKey(layout.id, {\n kind: 'filter',\n key: filter.dimension\n })\n }}\n >\n <FilterSelect\n dimension={filter.dimension}\n label={filter.label}\n width={filter.width}\n formatLabel={filter.formatLabel ? formatters[filter.formatLabel] : undefined}\n />\n </Box>\n ))}\n </Box>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["OTHERS","RechartsBarChart","Tooltip","Tooltip","Tooltip"],"sources":["../../src/client/seriesPivot.ts","../../src/client/BarChart.tsx","../../src/client/ComboChart.tsx","../../src/client/useLayout.ts","../../src/client/DashboardCanvas.tsx","../../src/client/DataTable.tsx","../../src/client/DonutChart.tsx","../../src/client/KpiCard.tsx","../../src/client/DashboardCharts.tsx","../../src/client/FilterSelect.tsx","../../src/client/DashboardFilters.tsx"],"sourcesContent":["import type { DashboardRow, FilterValue } from '../types'\nimport { numberOf, OTHER_COLOR, seriesColor } from './chartKit'\n\n/**\n * Séries vindas de uma dimensão (o `series` do `BarChart`, a \"Legenda\" do Power BI): a consulta\n * devolve linhas longas (categoria, série, valor) e o gráfico precisa delas largas (categoria,\n * série 1, série 2, …).\n */\n\nexport type SeriesItem = {\n /** Chave da série no ponto do gráfico (`s0`, `s1`, …; o valor pode ter \".\" e o Recharts lê como caminho). */\n dataKey: string\n /** Valor da dimensão; `null` = linhas sem valor ou \"Outros\" (não filtram). */\n value: FilterValue | null\n label: string\n color: string\n others?: boolean\n}\n\nexport const EMPTY_SERIES_LABEL = '(em branco)'\nconst OTHERS = 'Outros'\n\nconst keyOf = (value: FilterValue | null) => (value === null ? '\\u0000' : String(value))\n\n/**\n * Séries a partir do domínio (série × medida sem filtros): ordenadas pelo total, maior primeiro, e\n * a cor segue essa ordem — como o domínio não depende dos filtros, cada valor tem sempre a mesma\n * cor. Além de `max`, as menores viram \"Outros\" (a última vaga), em cinza.\n */\nexport function seriesItems(\n domain: DashboardRow[],\n series: string,\n measure: string,\n max: number,\n format: (value: FilterValue) => string = String\n): SeriesItem[] {\n const ranked = domain\n .map((row) => ({ value: row[series] ?? null, amount: Math.abs(numberOf(row, measure) ?? 0) }))\n .sort((a, b) => b.amount - a.amount)\n const limit = Math.min(Math.max(max, 2), 8)\n const kept = ranked.length > limit ? ranked.slice(0, limit - 1) : ranked\n const items: SeriesItem[] = kept.map((item, index) => ({\n dataKey: `s${index}`,\n value: item.value,\n label: item.value === null ? EMPTY_SERIES_LABEL : format(item.value),\n color: seriesColor(index)\n }))\n if (ranked.length > kept.length) items.push(othersItem(ranked.length - kept.length))\n return items\n}\n\nconst othersItem = (count?: number): SeriesItem => ({\n dataKey: 'outros',\n value: null,\n label: count ? `${OTHERS} (${count})` : OTHERS,\n color: OTHER_COLOR,\n others: true\n})\n\nexport type SeriesPoint = { value: FilterValue; label: string } & Record<string, number | string>\n\n/**\n * Linhas (categoria, série, medida) → um ponto por categoria, na ordem da consulta, com o valor de\n * cada série em `dataKey`. Valor fora das séries soma em \"Outros\" (criado se o domínio não tinha).\n * Devolve só as séries com algum valor nos pontos (um filtro pode ter tirado uma delas).\n */\nexport function pivotSeries(\n rows: DashboardRow[],\n dimension: string,\n series: string,\n measure: string,\n items: SeriesItem[],\n format: (value: FilterValue) => string = String\n): { points: SeriesPoint[]; items: SeriesItem[] } {\n const all = [...items]\n const byValue = new Map(\n all.filter((item) => !item.others).map((item) => [keyOf(item.value), item])\n )\n const points = new Map<string, SeriesPoint>()\n const used = new Set<string>()\n for (const row of rows) {\n const value = row[dimension] ?? ''\n const key = String(value)\n let point = points.get(key)\n if (!point) {\n point = { value, label: format(value) }\n for (const item of all) point[item.dataKey] = 0\n points.set(key, point)\n }\n let item = byValue.get(keyOf(row[series] ?? null))\n if (!item) {\n item = all.find((other) => other.others)\n if (!item) {\n item = othersItem()\n all.push(item)\n for (const other of points.values()) other[item.dataKey] = 0\n }\n }\n const amount = numberOf(row, measure)\n if (amount) {\n point[item.dataKey] = Number(point[item.dataKey] ?? 0) + amount\n used.add(item.dataKey)\n }\n }\n return { points: [...points.values()], items: all.filter((item) => used.has(item.dataKey)) }\n}\n\n/** Soma das séries de um ponto (a altura da barra empilhada). */\nexport const pointTotal = (point: SeriesPoint, items: SeriesItem[]) =>\n items.reduce((total, item) => total + Number(point[item.dataKey] ?? 0), 0)\n\n/**\n * Todas as categorias da dimensão (consulta só da dimensão, sem medidas), na ordem dela, com os\n * valores dos pontos que vieram da consulta e zero nas que não têm dado (o \"Mostrar itens sem\n * dados\" do Power BI). Ponto fora da lista (não deveria haver) vai no fim.\n */\nexport function fillCategories<Point extends { value: FilterValue; label: string }>(\n points: Point[],\n categories: DashboardRow[],\n dimension: string,\n dataKeys: string[],\n format: (value: FilterValue) => string = String\n): Point[] {\n const byValue = new Map(points.map((point) => [String(point.value), point]))\n const seen = new Set<string>()\n const filled: Point[] = []\n for (const row of categories) {\n const value = row[dimension] ?? ''\n const key = String(value)\n if (seen.has(key)) continue\n seen.add(key)\n const point = byValue.get(key)\n if (point) filled.push(point)\n else\n filled.push({\n value,\n label: format(value),\n ...Object.fromEntries(dataKeys.map((dataKey) => [dataKey, 0]))\n } as unknown as Point)\n }\n return [...filled, ...points.filter((point) => !seen.has(String(point.value)))]\n}\n","import { Box } from '@mui/material'\nimport type { MouseEvent } from 'react'\nimport {\n Bar,\n CartesianGrid,\n Cell,\n LabelList,\n BarChart as RechartsBarChart,\n ResponsiveContainer,\n Tooltip,\n XAxis,\n YAxis\n} from 'recharts'\nimport { matchesValueRule, type ValueRule } from '../formatRules'\nimport type { BarValuePosition, ChartNumberFormat } from '../layout'\nimport type { FilterValue } from '../types'\nimport {\n chartPlaceholder,\n Legend,\n numberOf,\n seriesColor,\n TooltipBox,\n useClickFilter\n} from './chartKit'\nimport { useDashboard } from './DashboardProvider'\nimport { fieldLabel, formatMeasure, measureFormat, measureFormatter } from './format'\nimport {\n EMPTY_SERIES_LABEL,\n fillCategories,\n pivotSeries,\n pointTotal,\n type SeriesItem,\n seriesItems\n} from './seriesPivot'\nimport { useModelQuery } from './useModelQuery'\n\ntype BarChartProps = {\n /** Dimensão das categorias. */\n dimension: string\n /** Uma série por medida (cores fixas pela posição); com `series`, só a primeira. */\n measures: string[]\n /**\n * Dimensão da legenda: quebra a medida pelos valores dela, uma série por valor (a \"Legenda\" do\n * Power BI). A cor de cada valor é fixa (ordem do total sem filtros), mesmo que um filtro tire\n * outro valor do gráfico.\n */\n series?: string\n formatSeries?: (value: FilterValue) => string\n /** Com `series`: as menores além dessa quantidade viram \"Outros\" (no máximo 8). Padrão: 6. */\n maxSeries?: number\n /** `horizontal` cabe nomes longos; com muitas categorias, rola dentro da altura. */\n orientation?: 'vertical' | 'horizontal'\n /** Empilha as séries (só faz sentido com partes de um total). */\n stacked?: boolean\n /** `dimension` = ordem da consulta; `desc`/`asc` = pela primeira medida (com `series`, pelo total). */\n sort?: 'dimension' | 'desc' | 'asc'\n /** Só os N primeiros depois de ordenar. */\n limit?: number\n formatDimension?: (value: FilterValue) => string\n /** Esconde categorias sem valor em nenhuma medida. */\n hideEmpty?: boolean\n /**\n * Mostra todos os valores da dimensão no eixo, com ou sem dado nas medidas (zerados), na ordem\n * da dimensão. Sobrepõe o `hideEmpty`.\n */\n showEmpty?: boolean\n /** Valores nas barras (até 30 categorias; acima disso, só tooltip). */\n showValues?: boolean\n /**\n * Onde fica o valor: `outside` (na ponta, fora), `insideEnd` (dentro, na ponta), `center` ou\n * `insideBase`. Empilhado, `outside` não mostra os pedaços (só o `showTotal`).\n */\n valuePosition?: BarValuePosition\n /** Cor do valor. Padrão: escuro fora da barra, branco dentro. */\n valueColor?: string\n /** Tamanho do valor, em px. Padrão: 12. */\n valueSize?: number\n /** Empilhado: total da pilha na ponta da barra. */\n showTotal?: boolean\n /** Só mostra o valor (e o total) que atende à regra, ex.: `{ operator: '!=', value: 0 }`. */\n valueRule?: ValueRule\n /**\n * Com `clickToFilter`: o filtro da dimensão (e da série) esconde o resto em vez de só apagá-lo\n * (a consulta passa a respeitar o próprio filtro). Padrão: `false` (apaga).\n */\n hideUnselected?: boolean\n /**\n * Cor por série: `{ medida: '#rrggbb' }` ou, com `series`, `{ valor: '#rrggbb' }` (também\n * \"(em branco)\" e \"Outros\"). O que faltar segue a paleta.\n */\n colors?: Record<string, string>\n clickToFilter?: boolean\n height?: number\n /** Rótulo por dimensão/medida (sobrepõe o dicionário do modelo). */\n labels?: Record<string, string>\n /** Formato por medida (sobrepõe o dicionário do modelo). */\n formats?: Record<string, ChartNumberFormat>\n /** Nome da consulta no devtools. */\n queryLabel?: string\n}\n\nconst MAX_VALUE_LABELS = 30\n/** Coluna do total da pilha no ponto (para o rótulo do `showTotal`). */\nconst TOTAL_KEY = '\\u0000total'\n\n/** Posição do valor no Recharts, conforme a orientação. */\nconst LABEL_POSITION = {\n vertical: {\n outside: 'top',\n insideEnd: 'insideTop',\n center: 'center',\n insideBase: 'insideBottom'\n },\n horizontal: {\n outside: 'right',\n insideEnd: 'insideRight',\n center: 'center',\n insideBase: 'insideLeft'\n }\n} as const\n\n/** Chave de uma série em `colors`: o valor, \"(em branco)\" ou \"Outros\". */\nconst seriesColorKey = (item: SeriesItem) =>\n item.others ? 'Outros' : item.value === null ? EMPTY_SERIES_LABEL : String(item.value)\n/** Altura de cada categoria no modo horizontal (barras finas, com respiro). */\nconst ROW_HEIGHT = 28\n\ntype Point = { value: FilterValue; label: string } & Record<string, number | string>\n\n/** Uma `<Bar>` do gráfico: uma medida ou um valor da série. */\ntype Bar = { dataKey: string; label: string; color: string; format: (value: number) => string } & (\n | { item?: undefined }\n | { item: SeriesItem }\n)\n\n/**\n * Barras de uma ou mais medidas por uma dimensão. Ex.:\n * `<BarChart dimension=\"navio\" measures={['custoTotal']} orientation=\"horizontal\" sort=\"desc\" limit={10} />`.\n * Com `series`, uma medida quebrada pelos valores de outra dimensão:\n * `<BarChart dimension=\"mes\" series=\"tipo_descarga\" measures={['volume']} stacked />`.\n */\nexport function BarChart({\n dimension,\n measures: measureList,\n series,\n formatSeries = String,\n maxSeries = 6,\n orientation = 'vertical',\n stacked = false,\n sort = 'dimension',\n limit,\n formatDimension = String,\n hideEmpty = true,\n showEmpty = false,\n showValues = true,\n valuePosition = 'outside',\n valueColor,\n valueSize = 12,\n showTotal = false,\n valueRule,\n hideUnselected = false,\n colors,\n clickToFilter = false,\n height = 360,\n labels,\n formats: formatsByMeasure,\n queryLabel\n}: BarChartProps) {\n const { meta, filters, setFilter } = useDashboard()\n const dimming = clickToFilter && !hideUnselected\n // Com série, uma medida só\n const measures = series ? measureList.slice(0, 1) : measureList\n const { rows, isLoading, error, inspectProps } = useModelQuery({\n dimensions: series ? [dimension, series] : [dimension],\n measures,\n // Apagando o resto, o gráfico ignora o próprio filtro (mostra tudo e destaca a seleção)\n ignoreFilters: dimming ? (series ? [dimension, series] : [dimension]) : undefined,\n label: queryLabel ?? `BarChart · ${dimension}`\n })\n // Valores da série sem filtro nenhum: a cor (e quem vira \"Outros\") não muda com os filtros\n const domain = useModelQuery({\n dimensions: series ? [series] : [],\n measures,\n ignoreFilters: Object.keys(filters),\n label: `${queryLabel ?? `BarChart · ${dimension}`} · séries`,\n skip: !series\n })\n // Todas as categorias da dimensão (consulta sem medidas, como a lista de um filtro). Só os\n // filtros da mesma tabela valem: um de outra tabela faria a consulta partir da fato, e as\n // categorias sem dado sumiriam\n const table = meta?.dimensions[dimension]?.table\n const categories = useModelQuery({\n dimensions: [dimension],\n ignoreFilters: Object.keys(filters).filter(\n (name) => (dimming && name === dimension) || !table || meta?.dimensions[name]?.table !== table\n ),\n label: `${queryLabel ?? `BarChart · ${dimension}`} · categorias`,\n // Sem o meta não se sabe a tabela da dimensão\n skip: !showEmpty || !meta\n })\n const filter = useClickFilter(dimension, clickToFilter)\n const seriesFilter = useClickFilter(series, clickToFilter)\n const formats = measures.map((measure) => measureFormatter(meta, measure, 0, formatsByMeasure))\n const labelOf = (name: string) => fieldLabel(meta, name, labels)\n // Eixo de valores: formato da primeira medida, sem casas (os valores exatos ficam nos rótulos)\n const axisFormat = measures[0] ? measureFormat(meta, measures[0], formatsByMeasure) : undefined\n const formatTick = (value: number) =>\n formatMeasure(value, { ...axisFormat, decimals: axisFormat?.compact ? 1 : 0 }, 0)\n\n let data: Point[]\n let bars: Bar[]\n const first = measures[0]\n if (series && first) {\n const format = formats[0] ?? String\n const pivot = pivotSeries(\n rows,\n dimension,\n series,\n first,\n seriesItems(domain.rows, series, first, maxSeries, formatSeries),\n formatDimension\n )\n bars = pivot.items.map((item) => ({\n ...item,\n color: colors?.[seriesColorKey(item)] ?? item.color,\n item,\n format\n }))\n data = pivot.points\n } else {\n bars = measures.map((measure, index) => ({\n dataKey: measure,\n label: labelOf(measure),\n color: colors?.[measure] ?? seriesColor(index),\n format: formats[index] ?? String\n }))\n data = rows.map((row) => {\n const value = row[dimension] ?? ''\n const point: Point = { value, label: formatDimension(value) }\n for (const measure of measures) point[measure] = numberOf(row, measure) ?? 0\n return point\n })\n }\n if (showEmpty)\n data = fillCategories(\n data,\n categories.rows,\n dimension,\n bars.map((bar) => bar.dataKey),\n formatDimension\n )\n else if (hideEmpty) data = data.filter((point) => bars.some((bar) => Number(point[bar.dataKey])))\n // Ordena pela primeira medida ou, com série, pelo total da barra\n const sortValue = (point: Point) =>\n series\n ? pointTotal(\n point,\n bars.map((bar) => bar.item).filter((item) => !!item)\n )\n : Number(point[first ?? ''])\n if (sort !== 'dimension' && first)\n data = [...data].sort((a, b) =>\n sort === 'desc' ? sortValue(b) - sortValue(a) : sortValue(a) - sortValue(b)\n )\n if (limit) data = data.slice(0, limit)\n\n const horizontal = orientation === 'horizontal'\n const showLabels = showValues && data.length <= MAX_VALUE_LABELS\n // Empilhado, o valor de fora seria o do último pedaço: lá vai só o total\n const segmentLabels = showLabels && (!stacked || valuePosition !== 'outside')\n const totalLabel = showLabels && stacked && showTotal && bars.length > 0\n // Rótulo fora da barra precisa de espaço na ponta\n const labelsOutside = (segmentLabels && valuePosition === 'outside') || totalLabel\n if (totalLabel)\n data = data.map((point) => ({\n ...point,\n [TOTAL_KEY]: bars.reduce((total, bar) => total + Number(point[bar.dataKey] ?? 0), 0)\n }))\n const labelStyle = (outside: boolean) => ({\n fontSize: valueSize,\n fill: valueColor ?? (outside ? '#333' : '#fff'),\n fontWeight: 600\n })\n const position = LABEL_POSITION[orientation === 'horizontal' ? 'horizontal' : 'vertical']\n // Horizontal com muitas categorias: o gráfico cresce e a caixa rola\n const chartHeight = horizontal ? Math.max(height, data.length * ROW_HEIGHT + 24) : height\n const longest = Math.max(0, ...data.map((point) => point.label.length))\n\n const loading = isLoading || domain.isLoading || categories.isLoading || (showEmpty && !meta)\n const state = chartPlaceholder({\n height,\n error: error ?? domain.error ?? categories.error,\n isLoading: loading,\n empty: !data.length\n })\n\n const ChartTooltip = ({ active, payload }: any) => {\n if (!active || !payload?.length) return null\n const point: Point = payload[0].payload\n // Com série, só as que têm valor nesta barra (e o total, se empilhado)\n const shown = series ? bars.filter((bar) => Number(point[bar.dataKey])) : bars\n const format = bars[0]?.format ?? String\n return (\n <TooltipBox title={point.label} caption={labelOf(dimension)}>\n {series && first && (\n <Box sx={{ fontSize: 11, color: '#777', mt: 0.5 }}>\n {labelOf(first)} por {labelOf(series).toLocaleLowerCase('pt-BR')}\n </Box>\n )}\n {shown.map((bar) => (\n <Box key={bar.dataKey} sx={{ display: 'flex', alignItems: 'center', gap: 0.75 }}>\n <Box sx={{ width: 8, height: 8, borderRadius: '50%', bgcolor: bar.color }} />\n {bar.label}: {bar.format(Number(point[bar.dataKey]))}\n </Box>\n ))}\n {series && stacked && shown.length > 1 && (\n <Box sx={{ fontWeight: 700, mt: 0.5 }}>\n Total: {format(shown.reduce((total, bar) => total + Number(point[bar.dataKey]), 0))}\n </Box>\n )}\n </TooltipBox>\n )\n }\n\n const handleClick = (index: number, bar: Bar, event: MouseEvent) => {\n // Senão o clique sobe até o container, que limpa o filtro\n event.stopPropagation()\n const point = data[index]\n if (!point) return\n const value = bar.item?.value\n // Segmento de um valor da série: filtra as duas dimensões (sem valor/\"Outros\", só a categoria)\n if (!series || value === null || value === undefined) {\n filter.toggle(point.value, event)\n seriesFilter.clear()\n } else if (event.ctrlKey || event.metaKey) {\n filter.toggle(point.value, event)\n seriesFilter.toggle(value, event)\n } else {\n // Clicar de novo no único segmento selecionado limpa; senão seleciona só ele\n const sole = (selected: FilterValue[], item: FilterValue) =>\n selected.length === 1 && selected[0] === item\n const again = sole(filter.selected, point.value) && sole(seriesFilter.selected, value)\n setFilter(dimension, again ? [] : [point.value])\n setFilter(series, again ? [] : [value])\n }\n }\n const isDimmed = (point: Point, bar: Bar) => {\n if (filter.isDimmed(point.value)) return true\n if (!bar.item || !seriesFilter.selected.length) return false\n return bar.item.value === null || seriesFilter.isDimmed(bar.item.value)\n }\n const clearFilters = () => {\n filter.clear()\n seriesFilter.clear()\n }\n\n // Ponta arredondada só no fim da barra (no empilhado, só no último segmento)\n const radius = (index: number): [number, number, number, number] => {\n if (stacked && index < bars.length - 1) return [0, 0, 0, 0]\n return horizontal ? [0, 4, 4, 0] : [4, 4, 0, 0]\n }\n\n return (\n <Box {...inspectProps} sx={{ minWidth: 0 }}>\n <Legend\n items={series || bars.length > 1 ? bars.map(({ label, color }) => ({ label, color })) : []}\n loading={loading}\n />\n {state ?? (\n <Box\n onClick={clearFilters}\n sx={{\n height,\n overflowY: horizontal ? 'auto' : 'hidden',\n opacity: loading ? 0.5 : 1,\n transition: 'opacity .2s'\n }}\n >\n <Box sx={{ height: chartHeight }}>\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <RechartsBarChart\n data={data}\n layout={horizontal ? 'vertical' : 'horizontal'}\n barGap={2}\n barCategoryGap=\"20%\"\n margin={\n horizontal\n ? { top: 4, right: labelsOutside ? 96 : 16, left: 8, bottom: 4 }\n : { top: labelsOutside ? valueSize + 12 : 8, right: 8, left: 8, bottom: 0 }\n }\n >\n <CartesianGrid stroke=\"#eee\" vertical={horizontal} horizontal={!horizontal} />\n {horizontal ? (\n <>\n <XAxis\n type=\"number\"\n hide={showLabels}\n tick={{ fontSize: 12, fill: '#555' }}\n tickFormatter={formatTick}\n />\n <YAxis\n type=\"category\"\n dataKey=\"label\"\n interval={0}\n width={Math.min(220, longest * 7 + 12)}\n tick={{ fontSize: 12, fill: '#555' }}\n tickLine={false}\n axisLine={false}\n />\n </>\n ) : (\n <>\n <XAxis\n dataKey=\"label\"\n interval={data.length > MAX_VALUE_LABELS ? 'preserveStartEnd' : 0}\n tick={{ fontSize: 12, fill: '#555' }}\n tickLine={false}\n axisLine={{ stroke: '#ccc' }}\n />\n <YAxis\n hide={showLabels}\n tick={{ fontSize: 12, fill: '#555' }}\n tickFormatter={formatTick}\n width={72}\n />\n </>\n )}\n <Tooltip content={<ChartTooltip />} cursor={{ fill: 'rgba(0,0,0,.04)' }} />\n {bars.map((bar, index) => (\n <Bar\n key={bar.dataKey}\n dataKey={bar.dataKey}\n name={bar.label}\n fill={bar.color}\n stackId={stacked ? 'stack' : undefined}\n radius={radius(index)}\n maxBarSize={horizontal ? 18 : 56}\n isAnimationActive={false}\n onClick={\n clickToFilter\n ? (_bar, barIndex, event) => handleClick(barIndex, bar, event)\n : undefined\n }\n cursor={clickToFilter ? 'pointer' : undefined}\n >\n {clickToFilter &&\n data.map((point) => (\n <Cell\n key={String(point.value)}\n fillOpacity={isDimmed(point, bar) ? 0.35 : 1}\n />\n ))}\n {segmentLabels && (\n <LabelList\n dataKey={bar.dataKey}\n position={position[valuePosition]}\n // Pedaço zerado (série sem valor nesta barra) não ganha rótulo\n formatter={(value: unknown) =>\n (stacked && !Number(value)) || !matchesValueRule(valueRule, Number(value))\n ? ''\n : bar.format(value as number)\n }\n style={labelStyle(valuePosition === 'outside')}\n />\n )}\n {/* Total da pilha na ponta do último pedaço */}\n {totalLabel && index === bars.length - 1 && (\n <LabelList\n dataKey={TOTAL_KEY}\n position={position.outside}\n formatter={(value: unknown) =>\n matchesValueRule(valueRule, Number(value))\n ? (bars[0]?.format ?? String)(value as number)\n : ''\n }\n // Valores dentro: a cor escolhida é a deles; o total, fora, fica escuro\n style={{\n ...labelStyle(true),\n ...(valuePosition !== 'outside' && { fill: '#333' }),\n fontWeight: 700\n }}\n />\n )}\n </Bar>\n ))}\n </RechartsBarChart>\n </ResponsiveContainer>\n </Box>\n </Box>\n )}\n </Box>\n )\n}\n","import { Box, CircularProgress, Typography } from '@mui/material'\nimport type { MouseEvent } from 'react'\nimport {\n Bar,\n Cell,\n ComposedChart,\n LabelList,\n Line,\n ResponsiveContainer,\n Tooltip,\n XAxis,\n YAxis\n} from 'recharts'\nimport type { ChartNumberFormat } from '../layout'\nimport type { DashboardRow, FilterValue } from '../types'\nimport { useDashboard } from './DashboardProvider'\nimport { fieldLabel, formatMeasure, formatNumber, measureFormat } from './format'\nimport { useModelQuery } from './useModelQuery'\n\ntype ComboChartProps = {\n /** Dimensão do eixo X. */\n dimension: string\n /** Medida das barras. */\n bar: string\n /** Medida da linha (eixo próprio, oculto; os valores aparecem nos pontos). */\n line: string\n /** Medida extra mostrada como segunda linha do rótulo da barra (ex.: volume). */\n detail?: string\n /**\n * Rótulos e formatos: sem a prop, vale o `labels`/`formats` do gráfico e depois o dicionário do\n * modelo (`label`, `format`).\n */\n barLabel?: string\n lineLabel?: string\n detailLabel?: string\n formatDimension?: (value: FilterValue) => string\n formatBar?: (value: number) => string\n formatLine?: (value: number) => string\n formatDetail?: (value: number) => string\n /** Rótulo por dimensão/medida (sobrepõe o dicionário do modelo). */\n labels?: Record<string, string>\n /** Formato por medida (sobrepõe o dicionário do modelo). */\n formats?: Record<string, ChartNumberFormat>\n /** Esconde grupos cuja medida da barra é vazia/zero (como o Power BI faz). */\n hideEmpty?: boolean\n height?: number\n /** Rótulos de dados só até essa quantidade de barras (acima disso, só tooltip). */\n maxLabels?: number\n barColor?: string\n lineColor?: string\n /**\n * Clicar numa barra filtra o dashboard pelo valor dela (Ctrl/Cmd+clique acumula; clicar de novo\n * no único selecionado ou fora das barras limpa). O próprio gráfico ignora esse filtro e só\n * destaca a seleção, como o filtro cruzado do Power BI.\n */\n clickToFilter?: boolean\n /** Nome da consulta no devtools (padrão: `ComboChart · <dimensão>`). */\n queryLabel?: string\n}\n\n/** Mantém a linha na faixa de baixo do gráfico, longe dos rótulos que ficam em cima das barras. */\nconst lineDomain = ([min, max]: readonly number[]): [number, number] => {\n const range = max - min || Math.abs(max) || 1\n return [min - range * 0.3, max + range * 1.7]\n}\n\ntype Point = {\n value: FilterValue\n label: string\n bar: number\n line: number | null\n detail: number | null\n}\n\n/**\n * Barras + linha de uma dimensão, consultando o modelo do `DashboardProvider` (com os filtros dele).\n * Ex.: `<ComboChart dimension=\"mes\" bar=\"custoTotal\" line=\"custoTon\" detail=\"volTotal\" />`.\n */\nexport function ComboChart({\n dimension,\n bar,\n line,\n detail,\n barLabel,\n lineLabel,\n detailLabel,\n formatDimension = String,\n formatBar,\n formatLine,\n formatDetail,\n labels,\n formats,\n hideEmpty = true,\n height = 360,\n maxLabels = 24,\n barColor = '#F58220',\n lineColor = '#555',\n clickToFilter = false,\n queryLabel\n}: ComboChartProps) {\n const { meta, filters, setFilter } = useDashboard()\n // Prop > formato do gráfico > dicionário do modelo > padrão do componente\n // (sem `format` em nenhum dos dois, o do componente vale com as casas/prefixo de lá por cima)\n const fromModel = (measure: string, fallback: ChartNumberFormat) => {\n const format = measureFormat(meta, measure, formats)\n const resolved = format?.format ? format : { ...fallback, ...format }\n return (value: number) => formatMeasure(value, resolved, fallback.decimals)\n }\n formatBar ??= fromModel(bar, { format: 'currency', decimals: 0 })\n formatLine ??= fromModel(line, { decimals: 2 })\n formatDetail ??= detail ? fromModel(detail, { decimals: 3 }) : (value) => formatNumber(value, 3)\n barLabel ??= fieldLabel(meta, bar, labels)\n lineLabel ??= fieldLabel(meta, line, labels)\n detailLabel ??= detail && fieldLabel(meta, detail, labels)\n const dimensionLabel = fieldLabel(meta, dimension, labels)\n\n const { rows, isLoading, error, inspectProps } = useModelQuery({\n dimensions: [dimension],\n measures: detail ? [bar, line, detail] : [bar, line],\n ignoreFilters: clickToFilter ? [dimension] : undefined,\n label: queryLabel ?? `ComboChart · ${dimension}`\n })\n\n const num = (row: DashboardRow, key?: string) =>\n key && row[key] !== null && row[key] !== undefined ? Number(row[key]) : null\n\n const data: Point[] = rows\n .filter((row) => !hideEmpty || num(row, bar))\n .map((row) => ({\n value: row[dimension] ?? '',\n label: formatDimension(row[dimension] ?? ''),\n bar: num(row, bar) ?? 0,\n line: num(row, line),\n detail: num(row, detail)\n }))\n\n const showLabels = data.length <= maxLabels\n\n const selected = clickToFilter ? (filters[dimension] ?? []) : []\n const isDimmed = (point: Point) => selected.length > 0 && !selected.includes(point.value)\n\n const handleBarClick = (index: number, event: MouseEvent) => {\n // Senão o clique sobe até o container do gráfico, que limpa o filtro\n event.stopPropagation()\n const point = data[index]\n if (!point) return\n if (event.ctrlKey || event.metaKey) {\n setFilter(\n dimension,\n selected.includes(point.value)\n ? selected.filter((value) => value !== point.value)\n : [...selected, point.value]\n )\n } else {\n const onlyThis = selected.length === 1 && selected[0] === point.value\n setFilter(dimension, onlyThis ? [] : [point.value])\n }\n }\n\n const clearFilter = () => {\n if (selected.length) setFilter(dimension, [])\n }\n\n const BarValueLabel = (props: any) => {\n const point = data[props.index]\n if (!point?.bar) return null\n const cx = Number(props.x) + Number(props.width) / 2\n const lines = [\n formatBar(point.bar),\n point.detail === null ? null : formatDetail(point.detail)\n ].filter((text): text is string => !!text)\n const top = Number(props.y) - 6 - lines.length * 15\n const width = Math.max(...lines.map((text) => text.length)) * 6.8 + 10\n return (\n <g>\n <rect\n x={cx - width / 2}\n y={top}\n width={width}\n height={lines.length * 15 + 4}\n rx={2}\n fill=\"#555\"\n />\n {lines.map((text, i) => (\n <text\n key={text}\n x={cx}\n y={top + 14 + i * 15}\n textAnchor=\"middle\"\n fill=\"#fff\"\n fontSize={12}\n fontWeight={700}\n >\n {text}\n </text>\n ))}\n </g>\n )\n }\n\n const LineValueLabel = (props: any) => {\n if (props.value === null || props.value === undefined) return null\n const text = formatLine(Number(props.value))\n const width = text.length * 7 + 10\n return (\n <g>\n <rect\n x={props.x - width / 2}\n y={props.y - 9}\n width={width}\n height={18}\n rx={2}\n fill=\"#d9d9d9\"\n />\n <text\n x={props.x}\n y={props.y + 4}\n textAnchor=\"middle\"\n fill=\"#222\"\n fontSize={12}\n fontWeight={700}\n >\n {text}\n </text>\n </g>\n )\n }\n\n const ChartTooltip = ({ active, payload }: any) => {\n if (!active || !payload?.length) return null\n const point: Point = payload[0].payload\n return (\n <Box sx={{ bgcolor: '#fff', border: '1px solid #ccc', p: 1, fontSize: 13 }}>\n <Typography sx={{ fontSize: 11, color: '#777' }}>{dimensionLabel}</Typography>\n <Typography sx={{ fontWeight: 700, fontSize: 13 }}>{point.label}</Typography>\n <div>\n {barLabel}: {formatBar(point.bar)}\n </div>\n {point.detail !== null && (\n <div>\n {detailLabel}: {formatDetail(point.detail)}\n </div>\n )}\n <div>\n {lineLabel}: {point.line === null ? '' : formatLine(point.line)}\n </div>\n </Box>\n )\n }\n\n const legend = [\n { label: barLabel, color: barColor },\n { label: lineLabel, color: lineColor }\n ]\n\n return (\n <Box {...inspectProps} sx={{ minWidth: 0, position: 'relative' }}>\n <Box sx={{ display: 'flex', gap: 1.5, mb: 1, fontSize: 14, color: '#555' }}>\n {legend.map((item) => (\n <Box key={item.label} sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>\n <Box sx={{ width: 9, height: 9, borderRadius: '50%', bgcolor: item.color }} />\n {item.label}\n </Box>\n ))}\n {isLoading && <CircularProgress size={14} sx={{ ml: 'auto' }} />}\n </Box>\n {error ? (\n <Box\n sx={{\n height,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: 'error.main'\n }}\n >\n Erro ao carregar o gráfico\n </Box>\n ) : !data.length ? (\n <Box\n sx={{\n height,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: '#999'\n }}\n >\n {isLoading ? 'Carregando…' : 'Sem dados para os filtros selecionados'}\n </Box>\n ) : (\n <Box\n onClick={clickToFilter ? clearFilter : undefined}\n sx={{ height, opacity: isLoading ? 0.5 : 1, transition: 'opacity .2s' }}\n >\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <ComposedChart data={data} margin={{ top: showLabels ? 48 : 12, right: 8, left: 8 }}>\n <XAxis\n dataKey=\"label\"\n interval={0}\n tick={{ fontSize: 12, fill: '#555' }}\n tickLine={false}\n axisLine={false}\n />\n <YAxis yAxisId=\"bar\" hide domain={[0, 'auto']} />\n <YAxis yAxisId=\"line\" hide domain={lineDomain} />\n <Tooltip content={<ChartTooltip />} />\n <Bar\n yAxisId=\"bar\"\n dataKey=\"bar\"\n fill={barColor}\n isAnimationActive={false}\n onClick={\n clickToFilter ? (_bar, index, event) => handleBarClick(index, event) : undefined\n }\n cursor={clickToFilter ? 'pointer' : undefined}\n >\n {clickToFilter &&\n data.map((point) => (\n <Cell key={String(point.value)} fillOpacity={isDimmed(point) ? 0.35 : 1} />\n ))}\n {showLabels && <LabelList dataKey=\"bar\" content={<BarValueLabel />} />}\n </Bar>\n <Line\n yAxisId=\"line\"\n dataKey=\"line\"\n stroke={lineColor}\n strokeWidth={2}\n strokeDasharray=\"5 4\"\n dot={{ r: 2, fill: lineColor }}\n connectNulls\n isAnimationActive={false}\n >\n {showLabels && <LabelList dataKey=\"line\" content={<LineValueLabel />} />}\n </Line>\n </ComposedChart>\n </ResponsiveContainer>\n </Box>\n )}\n </Box>\n )\n}\n","import { useEffect, useState, useSyncExternalStore } from 'react'\nimport type { LayoutPart } from '../devtools/layoutStore'\nimport type { ChartsLayout } from '../layout'\nimport { useDashboard } from './DashboardProvider'\n\nconst noLayouts = () => () => {}\n\n/**\n * Layout em vigor: o do arquivo ou, com o devtools, o rascunho editado na aba Layout. Registra a\n * parte (`charts`/`filters`) para o devtools saber o que a página renderiza.\n */\nexport function useLayout(\n layout: ChartsLayout,\n part: LayoutPart,\n formatters: Record<string, unknown>\n): ChartsLayout {\n const { devtools } = useDashboard()\n const layouts = devtools?.layouts\n const formatterNames = Object.keys(formatters).sort().join(',')\n\n useEffect(\n () => layouts?.register(layout, part, formatterNames ? formatterNames.split(',') : []),\n [layouts, layout, part, formatterNames]\n )\n\n // Re-renderiza quando o rascunho muda\n useSyncExternalStore(\n layouts?.subscribe ?? noLayouts,\n () => layouts?.getSnapshot(),\n () => undefined\n )\n // O rascunho vem do sessionStorage: só depois de montar, para não divergir da hidratação\n const [mounted, setMounted] = useState(false)\n useEffect(() => setMounted(true), [])\n return (mounted && layouts?.draftOf(layout)) || layout\n}\n","import { Box } from '@mui/material'\nimport {\n createContext,\n type ReactNode,\n useContext,\n useEffect,\n useLayoutEffect,\n useRef,\n useState\n} from 'react'\nimport type { ChartsLayout } from '../layout'\nimport { useLayout } from './useLayout'\n\n// No servidor o useLayoutEffect só gera aviso; lá não há o que medir\nconst useIsomorphicLayoutEffect = typeof window === 'undefined' ? useEffect : useLayoutEffect\n\nconst FixedCanvasContext = createContext(false)\n\n/** Dentro de um `<DashboardCanvas>` com tamanho fixo: o grid não troca de colunas pela tela. */\nexport const useFixedCanvas = () => useContext(FixedCanvasContext)\n\ntype DashboardCanvasProps = {\n /** O mesmo layout do `<DashboardCharts>` (`canvas` do JSON). */\n layout: ChartsLayout\n children: ReactNode\n}\n\n/**\n * Tela de tamanho fixo (`layout.canvas`, ex.: 1920×1080): desenha os filhos nessa largura e escala\n * tudo para caber na largura disponível, mantendo a proporção — numa tela menor o dashboard encolhe\n * em vez de reorganizar os gráficos. Sem `canvas` no layout, só renderiza os filhos (responsivo).\n *\n * ```tsx\n * <DashboardCanvas layout={layout}>\n * <DashboardFilters layout={layout} />\n * <DashboardCharts layout={layout} />\n * </DashboardCanvas>\n * ```\n *\n * A escala é um `transform`: os gráficos continuam medindo o tamanho de projeto (o Recharts compensa\n * a escala no mouse) e os breakpoints do MUI, que olham a janela, ficam desligados no grid.\n */\nexport function DashboardCanvas({ layout, children }: DashboardCanvasProps) {\n const { canvas } = useLayout(layout, 'canvas', {})\n const outer = useRef<HTMLDivElement>(null)\n const inner = useRef<HTMLDivElement>(null)\n // Largura disponível e altura de projeto do conteúdo (offsetHeight ignora o transform)\n const [size, setSize] = useState<{ available: number; content: number } | null>(null)\n\n useIsomorphicLayoutEffect(() => {\n if (!canvas || !outer.current || !inner.current) return\n const outerElement = outer.current\n const innerElement = inner.current\n const measure = () => {\n const next = { available: outerElement.clientWidth, content: innerElement.offsetHeight }\n // Mudar a altura do outer dispara o observer de novo: só re-renderiza se mudou algo\n setSize((current) =>\n current?.available === next.available && current.content === next.content ? current : next\n )\n }\n measure()\n const observer = new ResizeObserver(measure)\n observer.observe(outerElement)\n observer.observe(innerElement)\n return () => observer.disconnect()\n }, [canvas])\n\n if (!canvas) return <>{children}</>\n\n const scale = size ? size.available / canvas.width : 1\n return (\n <FixedCanvasContext.Provider value>\n <Box\n ref={outer}\n sx={{\n width: '100%',\n overflow: 'hidden',\n height: size ? size.content * scale : undefined\n }}\n >\n <Box\n ref={inner}\n sx={{\n width: canvas.width,\n minHeight: canvas.height,\n transform: `scale(${scale})`,\n transformOrigin: '0 0',\n // Antes de medir a escala é desconhecida: evita piscar no tamanho de projeto\n visibility: size ? undefined : 'hidden'\n }}\n >\n {children}\n </Box>\n </Box>\n </FixedCanvasContext.Provider>\n )\n}\n","import {\n Box,\n CircularProgress,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n TableSortLabel\n} from '@mui/material'\nimport { useState } from 'react'\nimport {\n type ColorScale,\n colorScaleStyles,\n contrastText,\n type FormatRule,\n type RuleStyle,\n rowRuleStyles\n} from '../formatRules'\nimport {\n type ChartNumberFormat,\n type ColumnAlign,\n type ColumnVerticalAlign,\n PERCENT_PREFIX as PERCENT,\n percentColumn,\n tableColumns\n} from '../layout'\nimport type { DashboardRow, FilterValue } from '../types'\nimport { chartPlaceholder, useClickFilter } from './chartKit'\nimport { useDashboard } from './DashboardProvider'\nimport { fieldLabel, formatNumber, measureFormatter } from './format'\nimport { useModelQuery } from './useModelQuery'\n\ntype SortDirection = 'asc' | 'desc'\n\ntype DataTableProps = {\n /** Uma linha por combinação de dimensões (sem dimensões, uma linha só). */\n dimensions?: string[]\n /** Uma coluna por medida, formatada pelo dicionário do modelo. */\n measures: string[]\n /**\n * Medidas com coluna de participação no total (valor da linha ÷ soma da coluna), logo depois da\n * coluna da medida. Medida fora de `measures` é consultada só para o percentual (coluna no fim).\n */\n percentOf?: string[]\n /** Formatter por dimensão. */\n formatDimensions?: Record<string, (value: FilterValue) => string>\n /**\n * Linha de total, consultada sem as dimensões: razões (custo/t) saem do total, não da soma das\n * linhas.\n */\n showTotal?: boolean\n /**\n * Coluna da ordem inicial (dimensão, medida ou `%:medida`); quem usa reordena clicando no\n * cabeçalho. Dimensão/medida fora da tabela entra na consulta sem coluna (ex.: número do mês para\n * ordenar o nome do mês) — uma dimensão de fora divide as linhas se tiver mais de um valor por linha.\n */\n sortBy?: string\n sortDirection?: SortDirection\n /** Clicar numa linha filtra o dashboard pela primeira dimensão. */\n clickToFilter?: boolean\n /** Altura máxima; a tabela rola com o cabeçalho fixo. */\n height?: number\n /** Cabeçalho por dimensão/medida (sobrepõe o dicionário do modelo). */\n labels?: Record<string, string>\n /** Formato por medida (sobrepõe o dicionário do modelo). */\n formats?: Record<string, ChartNumberFormat>\n /** Casas decimais das colunas de percentual. Padrão: 1. */\n percentDecimals?: number\n /**\n * Ordem das colunas misturando dimensões, medidas e percentuais (ex.: `['custoTotal',\n * '%:custoTotal', 'navio']`); o que não estiver nela vai depois. Padrão: dimensões e depois\n * medidas, cada percentual logo depois da medida.\n */\n columnOrder?: string[]\n /**\n * Formatação condicional: cor do texto/fundo e negrito da célula ou da linha conforme o valor de\n * uma dimensão/medida (da tabela, de fora dela ou `%:medida`).\n */\n formatRules?: FormatRule[]\n /**\n * Escalas de cor (gradiente): o fundo ou o texto de uma coluna numérica vai de `minColor` a\n * `color` conforme o valor (ex.: 0 a 100). As regras de `formatRules` ficam por cima.\n */\n colorScales?: ColorScale[]\n /** Bordas entre as células (grade). Padrão: só a linha embaixo de cada linha. */\n cellBorders?: boolean\n /** Cor das bordas da grade. Padrão: `#e0e0e0`. */\n borderColor?: string\n /**\n * Alinhamento horizontal por coluna (`%:medida` para o percentual): cabeçalho, células e total.\n * Padrão: dimensão à esquerda, número à direita.\n */\n align?: Record<string, ColumnAlign>\n /** Alinhamento vertical por coluna (`top`, `middle`, `bottom`). Padrão: `middle`. */\n verticalAlign?: Record<string, ColumnVerticalAlign>\n /** Nome da consulta no devtools. */\n queryLabel?: string\n}\n\nconst EMPTY: string[] = []\nconst NO_RULES: FormatRule[] = []\nconst NO_SCALES: ColorScale[] = []\n\nfunction compare(a: DashboardRow[string], b: DashboardRow[string]) {\n // Vazios sempre por último, nas duas direções (tratado por quem chama)\n if (typeof a === 'number' && typeof b === 'number') return a - b\n return String(a).localeCompare(String(b), 'pt-BR', { numeric: true })\n}\n\n/**\n * Tabela de medidas por dimensões, com total e ordenação pelo cabeçalho. Ex.:\n * `<DataTable dimensions={['navio']} measures={['volTotal', 'custoTotal', 'custoTon']} />`.\n */\nexport function DataTable({\n dimensions = EMPTY,\n measures,\n percentOf = EMPTY,\n formatDimensions = {},\n showTotal = true,\n sortBy,\n sortDirection = 'desc',\n clickToFilter = false,\n height = 400,\n labels,\n formats: formatsByMeasure,\n percentDecimals = 1,\n columnOrder,\n formatRules = NO_RULES,\n colorScales = NO_SCALES,\n cellBorders = false,\n borderColor = '#e0e0e0',\n align,\n verticalAlign,\n queryLabel\n}: DataTableProps) {\n const { meta } = useDashboard()\n const name = queryLabel ?? `DataTable · ${dimensions.join(', ') || 'total'}`\n const firstDimension = dimensions[0]\n const ignoreFilters = clickToFilter && firstDimension ? [firstDimension] : undefined\n const extraMeasures = percentOf.filter((measure) => !measures.includes(measure))\n // Dimensões/medidas fora da tabela (ordem inicial, regras): consultadas sem coluna. Saber se é\n // dimensão ou medida depende do dicionário; até ele chegar, a consulta espera\n const outside = [\n ...new Set([sortBy, ...formatRules.map((rule) => rule.field)].filter(Boolean) as string[])\n ].filter(\n (field) =>\n !field.startsWith(PERCENT) &&\n !dimensions.includes(field) &&\n !measures.includes(field) &&\n !extraMeasures.includes(field)\n )\n const waitingMeta = outside.length > 0 && !meta\n const queryDimensions = [...dimensions, ...outside.filter((field) => meta?.dimensions[field])]\n const { rows, isLoading, error, inspectProps } = useModelQuery({\n dimensions: queryDimensions,\n measures: [\n ...measures,\n ...extraMeasures,\n ...outside.filter((field) => meta?.measures[field] && !meta.dimensions[field])\n ],\n ignoreFilters,\n label: name,\n skip: waitingMeta\n })\n // Sem dimensões a própria consulta já é o total\n const totals = useModelQuery({\n measures,\n ignoreFilters,\n label: `${name} · total`,\n skip: !showTotal || !dimensions.length\n })\n const filter = useClickFilter(firstDimension, clickToFilter)\n\n const [sort, setSort] = useState<{ by?: string; direction: SortDirection }>({\n by: sortBy,\n direction: sortDirection\n })\n // Props mudaram (ex.: devtools): volta para a ordem configurada\n const [configured, setConfigured] = useState([sortBy, sortDirection])\n if (configured[0] !== sortBy || configured[1] !== sortDirection) {\n setConfigured([sortBy, sortDirection])\n setSort({ by: sortBy, direction: sortDirection })\n }\n\n // O percentual ordena igual à medida\n const sortKey = sort.by?.startsWith(PERCENT) ? sort.by.slice(PERCENT.length) : sort.by\n const sorted = sortKey\n ? [...rows].sort((a, b) => {\n const [x, y] = [a[sortKey], b[sortKey]]\n if (x === null || x === undefined) return 1\n if (y === null || y === undefined) return -1\n return sort.direction === 'asc' ? compare(x, y) : compare(y, x)\n })\n : rows\n\n const formats = Object.fromEntries(\n measures.map((measure) => [measure, measureFormatter(meta, measure, 2, formatsByMeasure)])\n )\n const formatPercent = (value: number | null) =>\n value === null ? '' : `${formatNumber(value * 100, percentDecimals)}%`\n const dimensionText = (dimension: string, value: DashboardRow[string]) =>\n value === null || value === undefined\n ? '(vazio)'\n : (formatDimensions[dimension] ?? String)(value)\n const labelOf = (column: string) => fieldLabel(meta, column, labels)\n const headerOf = (column: string) => {\n if (!column.startsWith(PERCENT)) return labelOf(column)\n const measure = column.slice(PERCENT.length)\n return measures.includes(measure) ? '%' : `% ${labelOf(measure)}`\n }\n\n // Total de cada medida com percentual: soma das linhas mostradas\n const sums = Object.fromEntries(\n percentOf.map((measure) => [\n measure,\n rows.reduce((total, row) => total + (Number(row[measure]) || 0), 0)\n ])\n )\n const percentOfRow = (row: DashboardRow, measure: string) => {\n const value = row[measure]\n const total = sums[measure]\n return value === null || value === undefined || !total ? null : Number(value) / total\n }\n // Colunas na ordem configurada; percentual fora dela logo depois da medida (avulsos no fim)\n const columns = tableColumns(\n [...dimensions, ...measures],\n percentOf.filter((measure) => !dimensions.includes(measure)),\n columnOrder\n )\n // Percentuais entram na linha avaliada pelas regras e escalas como `%:medida`\n const evaluate = (row: DashboardRow) => {\n if (!percentOf.length) return row\n const evaluated = { ...row }\n for (const measure of percentOf) evaluated[percentColumn(measure)] = percentOfRow(row, measure)\n return evaluated\n }\n // Mínimo/máximo das escalas saem das linhas mostradas\n const scaleStyles = colorScales.length ? colorScaleStyles(colorScales, rows.map(evaluate)) : null\n // Estilo por coluna: escala por baixo, regras por cima\n const ruleStyles = (row: DashboardRow): Record<string, RuleStyle> | undefined => {\n if (!formatRules.length && !scaleStyles) return undefined\n const evaluated = evaluate(row)\n const rules = formatRules.length ? rowRuleStyles(formatRules, evaluated, columns) : {}\n if (!scaleStyles) return rules\n const scaled = scaleStyles(evaluated)\n return Object.fromEntries(\n columns.map((column) => {\n const [scale, rule] = [scaled[column], rules[column]]\n const style = { ...scale, ...rule }\n // Fundo escuro da escala (sem fundo nem texto de regra/escala por cima): texto branco\n if (scale?.background && !rule?.background && !style.color) {\n const text = contrastText(scale.background)\n if (text) style.color = text\n }\n return [column, style]\n })\n )\n }\n const ruleSx = (style: RuleStyle | undefined) =>\n style && {\n ...(style.color && { color: style.color }),\n ...(style.background && { bgcolor: style.background }),\n ...(style.bold && { fontWeight: 700 }),\n ...(style.align && { textAlign: style.align }),\n ...(style.verticalAlign && { verticalAlign: style.verticalAlign })\n }\n const isDimension = (column: string) => dimensions.includes(column)\n const alignOf = (column: string) => align?.[column] ?? (isDimension(column) ? 'left' : 'right')\n const verticalOf = (column: string) => verticalAlign?.[column] ?? 'middle'\n // \"Total\" vai na primeira coluna de dimensão da tabela\n const totalLabelColumn = columns.find(isDimension)\n const cellText = (row: DashboardRow, column: string) =>\n column.startsWith(PERCENT)\n ? formatPercent(percentOfRow(row, column.slice(PERCENT.length)))\n : formats[column]?.(row[column])\n\n const toggleSort = (column: string) =>\n setSort((current) =>\n current.by === column\n ? { by: column, direction: current.direction === 'asc' ? 'desc' : 'asc' }\n : // Medidas começam do maior; dimensões, em ordem alfabética\n { by: column, direction: dimensions.includes(column) ? 'asc' : 'desc' }\n )\n\n const totalRow = dimensions.length ? totals.rows[0] : undefined\n const loading = isLoading || waitingMeta\n const placeholder = chartPlaceholder({\n height: 160,\n error,\n isLoading: loading,\n empty: !rows.length\n })\n\n const header = (column: string, numeric: boolean) => (\n <TableCell\n key={column}\n align={alignOf(column)}\n sortDirection={sort.by === column ? sort.direction : false}\n sx={{\n fontWeight: 700,\n bgcolor: '#f3f3f3',\n whiteSpace: 'nowrap',\n verticalAlign: verticalOf(column)\n }}\n >\n <TableSortLabel\n active={sort.by === column}\n direction={sort.by === column ? sort.direction : numeric ? 'desc' : 'asc'}\n onClick={() => toggleSort(column)}\n >\n {headerOf(column)}\n </TableSortLabel>\n </TableCell>\n )\n\n return (\n <Box {...inspectProps} sx={{ minWidth: 0, position: 'relative' }}>\n {loading && <CircularProgress size={14} sx={{ position: 'absolute', top: -22, right: 0 }} />}\n {placeholder ?? (\n <Box\n sx={{\n maxHeight: height,\n overflow: 'auto',\n opacity: loading ? 0.5 : 1,\n transition: 'opacity .2s'\n }}\n >\n <Table\n size=\"small\"\n stickyHeader\n sx={{\n '& td, & th': {\n fontSize: 13,\n ...(cellBorders && { border: `1px solid ${borderColor}` })\n }\n }}\n >\n <TableHead>\n <TableRow>{columns.map((column) => header(column, !isDimension(column)))}</TableRow>\n </TableHead>\n <TableBody>\n {sorted.map((row) => {\n const value = firstDimension ? row[firstDimension] : null\n const clickable = clickToFilter && value !== null && value !== undefined\n const styles = ruleStyles(row)\n return (\n <TableRow\n key={queryDimensions.map((dimension) => String(row[dimension])).join('\\u0000')}\n hover\n onClick={clickable ? (event) => filter.toggle(value, event) : undefined}\n selected={clickable && filter.selected.includes(value)}\n sx={{\n cursor: clickable ? 'pointer' : undefined,\n opacity: clickable && filter.isDimmed(value) ? 0.5 : 1\n }}\n >\n {columns.map((column) =>\n isDimension(column) ? (\n <TableCell\n key={column}\n align={alignOf(column)}\n sx={{ verticalAlign: verticalOf(column), ...ruleSx(styles?.[column]) }}\n >\n {dimensionText(column, row[column])}\n </TableCell>\n ) : (\n <TableCell\n key={column}\n align={alignOf(column)}\n sx={{\n whiteSpace: 'nowrap',\n verticalAlign: verticalOf(column),\n ...ruleSx(styles?.[column])\n }}\n >\n {cellText(row, column)}\n </TableCell>\n )\n )}\n </TableRow>\n )\n })}\n {totalRow && (\n <TableRow\n sx={{\n '& td': {\n fontWeight: 700,\n position: 'sticky',\n bottom: 0,\n bgcolor: '#f3f3f3',\n borderTop: '2px solid #ddd'\n }\n }}\n >\n {columns.map((column) =>\n isDimension(column) ? (\n <TableCell\n key={column}\n align={alignOf(column)}\n sx={{ verticalAlign: verticalOf(column) }}\n >\n {column === totalLabelColumn ? 'Total' : ''}\n </TableCell>\n ) : (\n <TableCell\n key={column}\n align={alignOf(column)}\n sx={{ whiteSpace: 'nowrap', verticalAlign: verticalOf(column) }}\n >\n {column.startsWith(PERCENT)\n ? formatPercent(sums[column.slice(PERCENT.length)] ? 1 : null)\n : formats[column]?.(totalRow[column])}\n </TableCell>\n )\n )}\n </TableRow>\n )}\n </TableBody>\n </Table>\n </Box>\n )}\n </Box>\n )\n}\n","import { Box } from '@mui/material'\nimport { Cell, Pie, PieChart, ResponsiveContainer, Tooltip } from 'recharts'\nimport type { ChartNumberFormat, DonutLegendPosition, DonutValueContent } from '../layout'\nimport type { FilterValue } from '../types'\nimport {\n chartPlaceholder,\n numberOf,\n OTHER_COLOR,\n seriesColor,\n TooltipBox,\n useClickFilter\n} from './chartKit'\nimport { useDashboard } from './DashboardProvider'\nimport { fieldLabel, formatNumber, measureFormatter } from './format'\nimport { useModelQuery } from './useModelQuery'\n\ntype DonutChartProps = {\n /** Dimensão das fatias. */\n dimension: string\n /** Medida somável (partes de um total). Valores negativos ou zerados ficam de fora. */\n measure: string\n /** Fatias além dessa quantidade viram \"Outros\" (no máximo 8, o tamanho da paleta). */\n maxSlices?: number\n formatDimension?: (value: FilterValue) => string\n clickToFilter?: boolean\n height?: number\n /** Rótulo por dimensão/medida (sobrepõe o dicionário do modelo). */\n labels?: Record<string, string>\n /** Formato por medida (sobrepõe o dicionário do modelo). */\n formats?: Record<string, ChartNumberFormat>\n /** Casas decimais do percentual. Padrão: 1. */\n percentDecimals?: number\n /** Lado da legenda. Padrão: `right` (nome, % e valor; em cima/embaixo, só o nome, em linha). */\n legendPosition?: DonutLegendPosition\n /** Valor de cada fatia do lado de fora da rosca. */\n showValues?: boolean\n /** O que o valor de fora mostra. Padrão: `both` (`44.981 (51%)`). */\n valueContent?: DonutValueContent\n /** Total no furo da rosca. Padrão: `true`. */\n showTotal?: boolean\n /** Nome da consulta no devtools. */\n queryLabel?: string\n}\n\ntype Slice = {\n key: string\n value: FilterValue | null\n label: string\n amount: number\n color: string\n}\n\nconst OTHERS = 'Outros'\n/** Fatia abaixo dessa fração fica sem valor de fora (os rótulos se atropelariam); tem o tooltip. */\nconst MIN_VALUE_SHARE = 0.02\nconst RADIAN = Math.PI / 180\n\n/** Direção da caixa (rosca + legenda) conforme o lado da legenda. */\nconst LEGEND_DIRECTION = {\n right: 'row',\n left: 'row-reverse',\n top: 'column-reverse',\n bottom: 'column'\n} as const\n\n/**\n * Rosca de uma medida por uma dimensão, com o total no centro e a legenda ao lado (nome, % e valor)\n * ou em cima/embaixo; `showValues` põe o valor de cada fatia do lado de fora.\n * Ex.: `<DonutChart dimension=\"operacao_status\" measure=\"custoTotal\" />`.\n */\nexport function DonutChart({\n dimension,\n measure,\n maxSlices = 6,\n formatDimension = String,\n clickToFilter = false,\n height = 300,\n labels,\n formats,\n percentDecimals = 1,\n legendPosition = 'right',\n showValues = false,\n valueContent = 'both',\n showTotal = true,\n queryLabel\n}: DonutChartProps) {\n const { meta } = useDashboard()\n const { rows, isLoading, error, inspectProps } = useModelQuery({\n dimensions: [dimension],\n measures: [measure],\n ignoreFilters: clickToFilter ? [dimension] : undefined,\n label: queryLabel ?? `DonutChart · ${dimension}`\n })\n const filter = useClickFilter(dimension, clickToFilter)\n const format = measureFormatter(meta, measure, 0, formats)\n\n const positive = rows\n .map((row) => ({ value: row[dimension] ?? '', amount: numberOf(row, measure) ?? 0 }))\n .filter((item) => item.amount > 0)\n .sort((a, b) => b.amount - a.amount)\n const limit = Math.min(Math.max(maxSlices, 2), 8)\n // Com fatias sobrando, a última vaga vira \"Outros\"\n const kept = positive.length > limit ? positive.slice(0, limit - 1) : positive\n const rest = positive.slice(kept.length)\n // A cor segue a posição na ordem (maior = laranja); \"Outros\" é neutro\n const slices: Slice[] = kept.map((item, index) => ({\n key: String(item.value),\n value: item.value,\n label: formatDimension(item.value),\n amount: item.amount,\n color: seriesColor(index)\n }))\n if (rest.length)\n slices.push({\n key: `\\u0000${OTHERS}`,\n value: null,\n label: `${OTHERS} (${rest.length})`,\n amount: rest.reduce((total, item) => total + item.amount, 0),\n color: OTHER_COLOR\n })\n const total = slices.reduce((sum, slice) => sum + slice.amount, 0)\n const percent = (amount: number) => `${formatNumber((amount / total) * 100, percentDecimals)}%`\n\n const placeholder = chartPlaceholder({ height, error, isLoading, empty: !slices.length })\n\n const select = (slice: Slice | undefined, event?: { ctrlKey: boolean; metaKey: boolean }) => {\n if (slice?.value !== null && slice?.value !== undefined) filter.toggle(slice.value, event)\n }\n const dimmed = (slice: Slice) =>\n filter.selected.length > 0 && (slice.value === null || filter.isDimmed(slice.value))\n\n const valueText = (amount: number) =>\n valueContent === 'value'\n ? format(amount)\n : valueContent === 'percent'\n ? percent(amount)\n : `${format(amount)} (${percent(amount)})`\n\n // Valor fora da fatia, na direção do meio dela; o lado define o alinhamento do texto\n const SliceValue = ({ cx, cy, midAngle, outerRadius, payload }: any) => {\n const slice: Slice = payload\n if (slice.amount / total < MIN_VALUE_SHARE) return null\n const radius = outerRadius + 10\n const cos = Math.cos(-midAngle * RADIAN)\n const x = cx + radius * cos\n const y = cy + radius * Math.sin(-midAngle * RADIAN)\n return (\n <text\n x={x}\n y={y}\n textAnchor={Math.abs(cos) < 0.15 ? 'middle' : cos > 0 ? 'start' : 'end'}\n dominantBaseline=\"central\"\n fontSize={12}\n fill=\"#333\"\n opacity={dimmed(slice) ? 0.45 : 1}\n >\n {valueText(slice.amount)}\n </text>\n )\n }\n\n const side = legendPosition === 'left' || legendPosition === 'right'\n\n const SliceTooltip = ({ active, payload }: any) => {\n if (!active || !payload?.length) return null\n const slice: Slice = payload[0].payload\n return (\n <TooltipBox title={slice.label} caption={fieldLabel(meta, dimension, labels)}>\n {fieldLabel(meta, measure, labels)}: {format(slice.amount)} · {percent(slice.amount)}\n </TooltipBox>\n )\n }\n\n return (\n <Box {...inspectProps} sx={{ minWidth: 0, position: 'relative' }}>\n {placeholder ?? (\n <Box\n sx={{\n height,\n display: 'flex',\n flexDirection: LEGEND_DIRECTION[legendPosition],\n alignItems: side ? 'center' : 'stretch',\n gap: side ? 2 : 1,\n opacity: isLoading ? 0.5 : 1,\n transition: 'opacity .2s'\n }}\n >\n <Box\n sx={{\n position: 'relative',\n minWidth: 140,\n minHeight: 0,\n // Com o valor de fora, a rosca precisa de mais espaço que a legenda\n ...(side\n ? { height: '100%', flex: showValues ? '1 1 0' : '0 0 50%' }\n : { flex: '1 1 0' })\n }}\n >\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <PieChart>\n <Tooltip content={<SliceTooltip />} />\n <Pie\n data={slices}\n dataKey=\"amount\"\n nameKey=\"label\"\n innerRadius={showValues ? '46%' : '62%'}\n outerRadius={showValues ? '68%' : '92%'}\n startAngle={90}\n endAngle={-270}\n stroke=\"#fff\"\n strokeWidth={2}\n isAnimationActive={false}\n label={showValues ? SliceValue : false}\n labelLine={false}\n onClick={(_, index, event) => select(slices[index], event)}\n cursor={clickToFilter ? 'pointer' : undefined}\n >\n {slices.map((slice) => (\n <Cell\n key={slice.key}\n fill={slice.color}\n fillOpacity={dimmed(slice) ? 0.35 : 1}\n />\n ))}\n </Pie>\n </PieChart>\n </ResponsiveContainer>\n {/* Total no furo da rosca */}\n {showTotal && (\n <Box\n sx={{\n position: 'absolute',\n inset: 0,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n pointerEvents: 'none',\n textAlign: 'center'\n }}\n >\n <Box sx={{ fontSize: 12, color: '#777' }}>Total</Box>\n <Box sx={{ fontSize: 15, fontWeight: 700, color: '#333' }}>{format(total)}</Box>\n </Box>\n )}\n </Box>\n {side ? (\n <Box\n component=\"ul\"\n sx={{\n listStyle: 'none',\n m: 0,\n p: 0,\n minWidth: 0,\n flex: showValues ? '0 1 auto' : 1,\n maxWidth: showValues ? '45%' : undefined,\n overflow: 'auto',\n maxHeight: '100%'\n }}\n >\n {slices.map((slice) => (\n <Box\n component=\"li\"\n key={slice.key}\n onClick={(event) => select(slice, event)}\n sx={{\n display: 'grid',\n gridTemplateColumns: '10px minmax(0, 1fr) auto',\n alignItems: 'center',\n columnGap: 0.75,\n py: 0.5,\n fontSize: 13,\n color: '#333',\n opacity: dimmed(slice) ? 0.45 : 1,\n cursor: clickToFilter && slice.value !== null ? 'pointer' : undefined\n }}\n >\n <Box sx={{ width: 10, height: 10, borderRadius: '50%', bgcolor: slice.color }} />\n <Box sx={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>\n {slice.label}\n </Box>\n <Box sx={{ fontWeight: 700, textAlign: 'right' }}>{percent(slice.amount)}</Box>\n <Box />\n <Box sx={{ gridColumn: '2 / 4', fontSize: 12, color: '#777' }}>\n {format(slice.amount)}\n </Box>\n </Box>\n ))}\n </Box>\n ) : (\n <Box\n component=\"ul\"\n sx={{\n listStyle: 'none',\n m: 0,\n p: 0,\n display: 'flex',\n flexWrap: 'wrap',\n justifyContent: 'center',\n columnGap: 1.5,\n rowGap: 0.25,\n flex: '0 0 auto',\n maxHeight: '40%',\n overflow: 'auto'\n }}\n >\n {slices.map((slice) => (\n <Box\n component=\"li\"\n key={slice.key}\n title={`${format(slice.amount)} · ${percent(slice.amount)}`}\n onClick={(event) => select(slice, event)}\n sx={{\n display: 'flex',\n alignItems: 'center',\n gap: 0.5,\n fontSize: 13,\n color: '#333',\n whiteSpace: 'nowrap',\n opacity: dimmed(slice) ? 0.45 : 1,\n cursor: clickToFilter && slice.value !== null ? 'pointer' : undefined\n }}\n >\n <Box\n sx={{\n width: 10,\n height: 10,\n borderRadius: '50%',\n bgcolor: slice.color,\n flex: '0 0 auto'\n }}\n />\n {slice.label}\n </Box>\n ))}\n </Box>\n )}\n </Box>\n )}\n </Box>\n )\n}\n","import { Box, CircularProgress } from '@mui/material'\nimport type { ChartNumberFormat } from '../layout'\nimport { numberOf } from './chartKit'\nimport { useDashboard } from './DashboardProvider'\nimport { fieldLabel, measureFormatter } from './format'\nimport { useModelQuery } from './useModelQuery'\n\ntype KpiCardProps = {\n /** Medida do número grande: o total com os filtros da página. */\n measure: string\n /** Rótulo acima do número (no `<DashboardCharts>`, o título do painel faz esse papel). */\n label?: string\n /** Medida extra numa linha menor embaixo (ex.: volume, custo/t). */\n secondary?: string\n /** Padrão: `labels[secondary]` ou o `label` da medida secundária no dicionário. */\n secondaryLabel?: string\n /** Rótulo por medida (sobrepõe o dicionário); o da principal entra quando não há `label`. */\n labels?: Record<string, string>\n /** Formato por medida (sobrepõe o dicionário). */\n formats?: Record<string, ChartNumberFormat>\n /** Nome da consulta no devtools. */\n queryLabel?: string\n}\n\n/**\n * Card com o total de uma medida (e, opcionalmente, uma segunda medida embaixo). Uma consulta sem\n * dimensões: razões (custo/t) saem do total, não de uma média. Ex.:\n * `<KpiCard label=\"Custo total\" measure=\"custoTotal\" secondary=\"custoTon\" />`.\n */\nexport function KpiCard({\n measure,\n label,\n secondary,\n secondaryLabel,\n labels,\n formats,\n queryLabel\n}: KpiCardProps) {\n const { meta } = useDashboard()\n const { rows, isLoading, error, inspectProps } = useModelQuery({\n measures: secondary ? [measure, secondary] : [measure],\n label: queryLabel ?? `KpiCard · ${measure}`\n })\n const row = rows[0]\n const value = row ? numberOf(row, measure) : null\n const extra = row && secondary ? numberOf(row, secondary) : null\n label ??= labels?.[measure]\n\n return (\n <Box {...inspectProps} sx={{ minWidth: 0, position: 'relative' }}>\n {label && <Box sx={{ fontSize: 13, color: '#666', mb: 0.5 }}>{label}</Box>}\n {isLoading && <CircularProgress size={12} sx={{ position: 'absolute', top: 0, right: 0 }} />}\n <Box\n sx={{\n fontSize: 28,\n fontWeight: 700,\n lineHeight: 1.2,\n color: error ? 'error.main' : '#333',\n fontVariantNumeric: 'tabular-nums',\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n opacity: isLoading ? 0.5 : 1,\n transition: 'opacity .2s'\n }}\n >\n {error ? 'Erro' : value === null ? '—' : measureFormatter(meta, measure, 0, formats)(value)}\n </Box>\n {secondary && (\n <Box sx={{ fontSize: 13, color: '#666', mt: 0.25, minHeight: 20 }}>\n {secondaryLabel ?? fieldLabel(meta, secondary, labels)}:{' '}\n <Box component=\"span\" sx={{ fontWeight: 600, color: '#444' }}>\n {extra === null ? '—' : measureFormatter(meta, secondary, 2, formats)(extra)}\n </Box>\n </Box>\n )}\n </Box>\n )\n}\n","import { Box, Paper, Typography } from '@mui/material'\nimport type { ComponentType, ReactNode } from 'react'\nimport { LAYOUT_ITEM_ATTRIBUTE, layoutItemKey } from '../devtools/layoutStore'\nimport {\n type CardStyle,\n type ChartDef,\n type ChartsLayout,\n cardsGap,\n chartCardStyle,\n customChartProps,\n isBuiltinChart,\n LAYOUT_COLUMNS\n} from '../layout'\nimport type { FilterValue } from '../types'\nimport { BarChart } from './BarChart'\nimport { ComboChart } from './ComboChart'\nimport { useFixedCanvas } from './DashboardCanvas'\nimport { useDashboard } from './DashboardProvider'\nimport { DataTable } from './DataTable'\nimport { DonutChart } from './DonutChart'\nimport { KpiCard } from './KpiCard'\nimport { useLayout } from './useLayout'\n\nexport type ChartPanelProps = {\n title: string\n chart: ChartDef\n /** Estilo do card (`cards` do layout com o `card` do gráfico por cima); vazio = padrão. */\n card: CardStyle\n children: ReactNode\n}\n\ntype DashboardChartsProps = {\n /** Layout importado do JSON (`src/dashboard/layouts/<id>.json`). */\n layout: ChartsLayout\n /** Formatters por nome, referenciados no JSON por `formatDimension`. */\n formatters?: Record<string, (value: FilterValue) => string>\n /** Moldura de cada gráfico (título + conteúdo). */\n panel?: ComponentType<ChartPanelProps>\n /** Espaço entre os cards (unidades do `theme.spacing`); `cards.rowGap`/`columnGap` do layout (px) têm prioridade. */\n gap?: number\n}\n\nconst px = (value: number | undefined) => (value === undefined ? undefined : `${value}px`)\n\n/** Tira as chaves `undefined`, para o estilo do layout só sobrepor o que foi definido. */\nconst defined = <T extends object>(object: T) =>\n Object.fromEntries(\n Object.entries(object).filter(([, value]) => value !== undefined)\n ) as Partial<T>\n\n/**\n * `sx` da moldura de um card com o estilo do layout (`card` do `panel`). Só traz o que o layout\n * definiu, para um `panel` do app espalhar por cima do visual dele:\n * `<Paper sx={{ p: 2, borderRadius: 0, ...chartCardSx(card) }}>`.\n */\nexport function chartCardSx(card: CardStyle) {\n return {\n // Sem `CssBaseline` no app o padrão é `content-box`: com `height: 100%`, padding e borda\n // somariam à altura e o card vazaria da célula do grid por cima do espaço entre as linhas\n boxSizing: 'border-box' as const,\n ...defined({\n p: px(card.padding),\n bgcolor: card.background,\n borderWidth: px(card.borderWidth),\n borderStyle: card.borderWidth === undefined ? undefined : 'solid',\n borderColor: card.borderColor,\n borderRadius: px(card.borderRadius),\n boxShadow: card.shadow\n })\n }\n}\n\n/** `sx` do título de um card com o estilo do layout (idem `chartCardSx`). */\nexport function chartTitleSx(card: CardStyle) {\n return defined({\n color: card.titleColor,\n fontSize: px(card.titleSize),\n textAlign: card.titleAlign\n })\n}\n\nfunction DefaultPanel({ title, card, children }: ChartPanelProps) {\n return (\n <Paper\n elevation={0}\n sx={{\n p: 1.5,\n minWidth: 0,\n height: '100%',\n border: '1px solid',\n borderColor: 'divider',\n ...chartCardSx(card)\n }}\n >\n {title && (\n <Typography sx={{ fontWeight: 700, mb: 1, ...chartTitleSx(card) }}>{title}</Typography>\n )}\n {children}\n </Paper>\n )\n}\n\n/**\n * Renderiza os gráficos de um layout declarativo num grid de 12 colunas (no celular, um por linha;\n * dentro de um `<DashboardCanvas>` de tamanho fixo, sempre as 12). Em desenvolvimento, a aba\n * Layout do devtools edita esse layout ao vivo (rascunho) e grava o JSON de volta.\n *\n * ```tsx\n * import layout from '@/dashboard/layouts/analiseCusto.json'\n * <DashboardCharts layout={layout as ChartsLayout} formatters={{ nomeMes }} panel={Panel} />\n * ```\n */\nexport function DashboardCharts({\n layout,\n formatters = {},\n panel: Panel = DefaultPanel,\n gap = 1.5\n}: DashboardChartsProps) {\n const current = useLayout(layout, 'charts', formatters)\n const { charts } = current\n // Tela fixa: a janela não decide as colunas, o canvas é que escala\n const fixed = useFixedCanvas()\n const columns = `repeat(${LAYOUT_COLUMNS}, minmax(0, 1fr))`\n const space = cardsGap(current.cards)\n\n return (\n <Box\n sx={{\n display: 'grid',\n rowGap: px(space.row) ?? gap,\n columnGap: px(space.column) ?? gap,\n gridTemplateColumns: fixed ? columns : { xs: '1fr', lg: columns }\n }}\n >\n {charts.map((chart) => (\n <Box\n key={chart.id}\n {...{\n [LAYOUT_ITEM_ATTRIBUTE]: layoutItemKey(layout.id, { kind: 'chart', key: chart.id })\n }}\n sx={{\n minWidth: 0,\n gridColumn: fixed\n ? `span ${chart.span ?? LAYOUT_COLUMNS}`\n : { lg: `span ${chart.span ?? LAYOUT_COLUMNS}` }\n }}\n >\n <Panel title={chart.title} chart={chart} card={chartCardStyle(current, chart)}>\n <Chart chart={chart} formatters={formatters} />\n </Panel>\n </Box>\n ))}\n </Box>\n )\n}\n\ntype Formatters = Record<string, (value: FilterValue) => string>\n\nfunction Chart({ chart, formatters }: { chart: ChartDef; formatters: Formatters }) {\n const { chartTypes, chartComponents } = useDashboard()\n if (!isBuiltinChart(chart)) {\n const Component = chartComponents[chart.type]\n if (Component) return <Component {...customChartProps(chart, chartTypes, formatters)} />\n return <UnknownChart type={chart.type} />\n }\n const queryLabel = `${chart.title || chart.id} · ${chart.type}`\n const formatter = (name?: string) => (name ? formatters[name] : undefined)\n switch (chart.type) {\n case 'kpi': {\n const { id, type, title, span, card, ...props } = chart\n return <KpiCard {...props} queryLabel={queryLabel} />\n }\n case 'combo': {\n const { id, type, title, span, card, formatDimension, ...props } = chart\n return (\n <ComboChart\n {...props}\n queryLabel={queryLabel}\n formatDimension={formatter(formatDimension)}\n />\n )\n }\n case 'bar': {\n const { id, type, title, span, card, formatDimension, formatSeries, ...props } = chart\n return (\n <BarChart\n {...props}\n queryLabel={queryLabel}\n formatDimension={formatter(formatDimension)}\n formatSeries={formatter(formatSeries)}\n />\n )\n }\n case 'donut': {\n const { id, type, title, span, card, formatDimension, ...props } = chart\n return (\n <DonutChart\n {...props}\n queryLabel={queryLabel}\n formatDimension={formatter(formatDimension)}\n />\n )\n }\n case 'table': {\n const { id, type, title, span, card, formatDimensions, ...props } = chart\n const resolved: Formatters = {}\n for (const [dimension, name] of Object.entries(formatDimensions ?? {})) {\n const format = formatter(name)\n if (format) resolved[dimension] = format\n }\n return <DataTable {...props} queryLabel={queryLabel} formatDimensions={resolved} />\n }\n default:\n return <UnknownChart type={(chart as { type: unknown }).type} />\n }\n}\n\nfunction UnknownChart({ type }: { type: unknown }) {\n return (\n <Box sx={{ color: 'error.main', p: 2 }}>\n Tipo de gráfico desconhecido: {String(type)} (tipos do app vão no{' '}\n <code>{'<DashboardProvider charts>'}</code>)\n </Box>\n )\n}\n","import {\n Checkbox,\n FormControl,\n InputLabel,\n ListItemText,\n MenuItem,\n OutlinedInput,\n Select\n} from '@mui/material'\nimport type { FilterValue } from '../types'\nimport { useDashboard } from './DashboardProvider'\nimport { useModelQuery } from './useModelQuery'\n\ntype FilterSelectProps = {\n dimension: string\n /** Padrão: `label` da dimensão no dicionário do modelo. */\n label?: string\n formatLabel?: (value: FilterValue) => string\n width?: number\n}\n\n/**\n * Filtro de múltipla escolha de uma dimensão. As opções vêm do próprio modelo e respeitam os\n * DEMAIS filtros (filtro cruzado): com Mês = Janeiro, o filtro de navio só lista quem atracou em\n * janeiro. Nada selecionado = \"Todos\".\n */\nexport function FilterSelect({\n dimension,\n label,\n formatLabel = String,\n width = 200\n}: FilterSelectProps) {\n const { filters, setFilter, meta } = useDashboard()\n label ??= meta?.dimensions[dimension]?.label ?? dimension\n const { rows, inspectProps } = useModelQuery({\n dimensions: [dimension],\n ignoreFilters: [dimension],\n label: `FilterSelect · ${dimension}`\n })\n\n const selected = filters[dimension] ?? []\n const options = rows\n .map((row) => row[dimension])\n .filter((value): value is FilterValue => value !== null && value !== '')\n // Mantém visíveis valores selecionados que sumiram das opções por causa de outro filtro\n for (const value of selected) if (!options.includes(value)) options.push(value)\n\n return (\n <FormControl {...inspectProps} size=\"small\" sx={{ width }}>\n <InputLabel shrink>{label}</InputLabel>\n <Select<FilterValue[]>\n multiple\n displayEmpty\n value={selected}\n onChange={(event) => setFilter(dimension, event.target.value as FilterValue[])}\n input={<OutlinedInput notched label={label} />}\n renderValue={(values) => (values.length ? values.map(formatLabel).join(', ') : 'Todos')}\n MenuProps={{ slotProps: { paper: { sx: { maxHeight: 360 } } } }}\n sx={{ bgcolor: '#fff' }}\n >\n {options.map((option) => (\n <MenuItem key={option} value={option} dense>\n <Checkbox size=\"small\" checked={selected.includes(option)} sx={{ p: 0.5, mr: 1 }} />\n <ListItemText primary={formatLabel(option)} />\n </MenuItem>\n ))}\n </Select>\n </FormControl>\n )\n}\n","import { Box } from '@mui/material'\nimport { LAYOUT_ITEM_ATTRIBUTE, layoutItemKey } from '../devtools/layoutStore'\nimport type { ChartsLayout } from '../layout'\nimport type { FilterValue } from '../types'\nimport { FilterSelect } from './FilterSelect'\nimport { useLayout } from './useLayout'\n\ntype DashboardFiltersProps = {\n /** O mesmo layout do `<DashboardCharts>` (`filters` do JSON). */\n layout: ChartsLayout\n /** Formatters por nome, referenciados no JSON por `formatLabel`. */\n formatters?: Record<string, (value: FilterValue) => string>\n gap?: number\n}\n\n/**\n * Filtros (slicers) declarados em `layout.filters`, na ordem. Em desenvolvimento, a aba Layout do\n * devtools adiciona, remove, reordena e edita os filtros ao vivo.\n */\nexport function DashboardFilters({ layout, formatters = {}, gap = 2 }: DashboardFiltersProps) {\n const { filters = [] } = useLayout(layout, 'filters', formatters)\n return (\n <Box sx={{ display: 'flex', flexWrap: 'wrap', gap }}>\n {filters.map((filter) => (\n <Box\n key={filter.dimension}\n {...{\n [LAYOUT_ITEM_ATTRIBUTE]: layoutItemKey(layout.id, {\n kind: 'filter',\n key: filter.dimension\n })\n }}\n >\n <FilterSelect\n dimension={filter.dimension}\n label={filter.label}\n width={filter.width}\n formatLabel={filter.formatLabel ? formatters[filter.formatLabel] : undefined}\n />\n </Box>\n ))}\n </Box>\n )\n}\n"],"mappings":"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"}