@bluemarble/bi 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{DashboardDevtools-7L93aV1-.js → DashboardDevtools-6v5HDe-A.js} +597 -236
- package/dist/DashboardDevtools-6v5HDe-A.js.map +1 -0
- package/dist/{ModelDictionary-Y7W9oK1J.js → ModelDictionary-D3JzCd6x.js} +81 -5
- package/dist/ModelDictionary-D3JzCd6x.js.map +1 -0
- package/dist/client/index.d.ts +10 -2
- package/dist/client/index.js +13 -80
- package/dist/client/index.js.map +1 -1
- package/dist/{layout-676sEvvb.js → layout-QuOYFmp1.js} +29 -5
- package/dist/layout-QuOYFmp1.js.map +1 -0
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -1
- package/dist/{types-HXAn-3I1.d.ts → types-FdrY0FOZ.d.ts} +13 -1
- package/dist/types.d.ts +1 -1
- package/package.json +1 -1
- package/dist/DashboardDevtools-7L93aV1-.js.map +0 -1
- package/dist/ModelDictionary-Y7W9oK1J.js.map +0 -1
- package/dist/layout-676sEvvb.js.map +0 -1
package/dist/client/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["RechartsBarChart","Tooltip","Tooltip","Tooltip"],"sources":["../../src/client/chartKit.tsx","../../src/client/format.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 { Box, CircularProgress } from '@mui/material'\nimport type { MouseEvent, ReactNode } from 'react'\nimport type { DashboardRow, FilterValue } from '../types'\nimport { useDashboard } from './DashboardProvider'\n\n/**\n * Peças comuns dos gráficos ligados ao modelo: paleta, filtro por clique, legenda e os estados de\n * carregando/erro/vazio.\n */\n\n/**\n * Paleta categórica, sempre nesta ordem (a série N tem sempre a mesma cor). Laranja Rocha primeiro;\n * a ordem passa no validador de daltonismo (CVD ΔE ≥ 9 entre vizinhas) e de visão normal (≥ 19).\n */\nexport const SERIES_COLORS = [\n '#F58220',\n '#2a78d6',\n '#1baf7a',\n '#eda100',\n '#e87ba4',\n '#008300',\n '#6250d6',\n '#e34948'\n] as const\n\n/** \"Outros\" (fatias agrupadas) fica neutro, fora da paleta. */\nexport const OTHER_COLOR = '#9e9e9e'\n\nexport const seriesColor = (index: number) => SERIES_COLORS[index % SERIES_COLORS.length] as string\n\n/** Valor numérico de uma coluna da linha (`null` quando vazio). */\nexport const numberOf = (row: DashboardRow, key?: string) =>\n key && row[key] !== null && row[key] !== undefined ? Number(row[key]) : null\n\n/**\n * Filtro cruzado a partir do gráfico: clicar num valor filtra o dashboard por ele (Ctrl/Cmd+clique\n * acumula; clicar de novo no único selecionado limpa). O gráfico deve ignorar o próprio filtro na\n * consulta (`ignoreFilters`) e só destacar a seleção.\n */\nexport function useClickFilter(dimension: string | undefined, enabled: boolean) {\n const { filters, setFilter } = useDashboard()\n const selected = enabled && dimension ? (filters[dimension] ?? []) : []\n\n const toggle = (value: FilterValue, event?: Pick<MouseEvent, 'ctrlKey' | 'metaKey'>) => {\n if (!enabled || !dimension) return\n if (event?.ctrlKey || event?.metaKey)\n setFilter(\n dimension,\n selected.includes(value) ? selected.filter((item) => item !== value) : [...selected, value]\n )\n else setFilter(dimension, selected.length === 1 && selected[0] === value ? [] : [value])\n }\n\n return {\n selected,\n /** Há seleção e este valor não está nela. */\n isDimmed: (value: FilterValue) => selected.length > 0 && !selected.includes(value),\n toggle,\n clear: () => {\n if (enabled && dimension && selected.length) setFilter(dimension, [])\n }\n }\n}\n\nexport function Legend({\n items,\n loading\n}: {\n items: { label: string; color: string }[]\n loading?: boolean\n}) {\n return (\n <Box\n sx={{\n display: 'flex',\n flexWrap: 'wrap',\n columnGap: 1.5,\n rowGap: 0.5,\n mb: 1,\n fontSize: 14,\n color: '#555',\n minHeight: 21\n }}\n >\n {items.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 {loading && <CircularProgress size={14} sx={{ ml: 'auto' }} />}\n </Box>\n )\n}\n\n/** Erro / carregando / sem dados no lugar do gráfico; `null` quando há o que desenhar (função, não componente). */\nexport function chartPlaceholder({\n height,\n error,\n isLoading,\n empty\n}: {\n height: number\n error: unknown\n isLoading: boolean\n empty: boolean\n}): ReactNode {\n if (!error && !empty) return null\n return (\n <Box\n sx={{\n height,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: error ? 'error.main' : '#999'\n }}\n >\n {error\n ? 'Erro ao carregar o gráfico'\n : isLoading\n ? 'Carregando…'\n : 'Sem dados para os filtros selecionados'}\n </Box>\n )\n}\n\n/** `caption`: o que é o título (ex.: o rótulo da dimensão), em cinza acima dele. */\nexport function TooltipBox({\n title,\n caption,\n children\n}: {\n title: string\n caption?: string\n children: ReactNode\n}) {\n return (\n <Box sx={{ bgcolor: '#fff', border: '1px solid #ccc', p: 1, fontSize: 13 }}>\n {caption && <Box sx={{ fontSize: 11, color: '#777' }}>{caption}</Box>}\n <Box sx={{ fontWeight: 700 }}>{title}</Box>\n {children}\n </Box>\n )\n}\n","import type { ChartNumberFormat } from '../layout'\nimport type { ModelMeta } from '../model'\n\nconst formatters = new Map<string, Intl.NumberFormat>()\n\n/** `compact`: notação curta do pt-BR (1,2 mil / 3,4 mi / 5,6 bi). */\nexport function formatNumber(\n value: number | string | null | undefined,\n decimals = 2,\n compact = false\n) {\n if (value === null || value === undefined || value === '') return ''\n const number = Number(value)\n if (Number.isNaN(number)) return String(value)\n const key = `${decimals}:${compact}`\n let formatter = formatters.get(key)\n if (!formatter) {\n formatter = new Intl.NumberFormat('pt-BR', {\n minimumFractionDigits: decimals,\n maximumFractionDigits: decimals,\n ...(compact && { notation: 'compact' })\n })\n formatters.set(key, formatter)\n }\n return formatter.format(number)\n}\n\nexport const formatCurrency = (\n value: number | string | null | undefined,\n decimals = 2,\n compact = false\n) => {\n const text = formatNumber(value, decimals, compact)\n return text && `R$ ${text}`\n}\n\n/**\n * Formata pelo dicionário do modelo (`format`/`decimals` da medida) ou pelo formato do gráfico.\n * `fallbackDecimals` é o padrão do componente quando nenhum dos dois define `decimals`.\n */\nexport function formatMeasure(\n value: number | string | null | undefined,\n meta: ChartNumberFormat | undefined,\n fallbackDecimals = 2\n) {\n if (value === null || value === undefined || value === '') return ''\n const decimals = meta?.decimals ?? (meta?.format === 'integer' ? 0 : fallbackDecimals)\n const compact = meta?.compact ?? false\n let text: string\n switch (meta?.format) {\n case 'currency':\n text = formatCurrency(value, decimals, compact)\n break\n case 'percent': {\n const number = formatNumber(Number(value) * 100, decimals, compact)\n text = number && `${number}%`\n break\n }\n default:\n text = formatNumber(value, decimals, compact)\n }\n return text && `${meta?.prefix ?? ''}${text}${meta?.suffix ?? ''}`\n}\n\n/** Dicionário do modelo com o formato do gráfico por cima. */\nexport function measureFormat(\n meta: ModelMeta | null,\n measure: string,\n formats?: Record<string, ChartNumberFormat>\n): ChartNumberFormat | undefined {\n const fromModel = meta?.measures[measure]\n const fromChart = formats?.[measure]\n if (!fromChart) return fromModel\n return {\n ...(fromModel?.format !== undefined && { format: fromModel.format }),\n ...(fromModel?.decimals !== undefined && { decimals: fromModel.decimals }),\n ...fromChart\n }\n}\n\n/**\n * Formatter de uma medida: o `formats` do gráfico (se houver) por cima do dicionário do modelo; sem\n * `format`, número com `fallbackDecimals`.\n */\nexport function measureFormatter(\n meta: ModelMeta | null,\n measure: string,\n fallbackDecimals = 2,\n formats?: Record<string, ChartNumberFormat>\n): (value: number | string | null | undefined) => string {\n const format = measureFormat(meta, measure, formats)\n return (value) => formatMeasure(value, format, fallbackDecimals)\n}\n\n/** Rótulo de uma dimensão/medida: o `labels` do gráfico, o dicionário do modelo ou o nome. */\nexport function fieldLabel(\n meta: ModelMeta | null,\n name: string,\n labels?: Record<string, string>\n): string {\n return labels?.[name] || meta?.dimensions[name]?.label || meta?.measures[name]?.label || name\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 type { 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 { 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). */\n measures: string[]\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. */\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 /** Valores nas pontas das barras (até 30 categorias; acima disso, só tooltip). */\n showValues?: boolean\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/** 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 | FilterValue>\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 */\nexport function BarChart({\n dimension,\n measures,\n orientation = 'vertical',\n stacked = false,\n sort = 'dimension',\n limit,\n formatDimension = String,\n hideEmpty = true,\n showValues = true,\n clickToFilter = false,\n height = 360,\n labels,\n formats: formatsByMeasure,\n queryLabel\n}: BarChartProps) {\n const { meta } = useDashboard()\n const { rows, isLoading, error, inspectProps } = useModelQuery({\n dimensions: [dimension],\n measures,\n ignoreFilters: clickToFilter ? [dimension] : undefined,\n label: queryLabel ?? `BarChart · ${dimension}`\n })\n const filter = useClickFilter(dimension, 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 const first = measures[0]\n let data: Point[] = rows\n .filter((row) => !hideEmpty || measures.some((measure) => numberOf(row, measure)))\n .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 if (sort !== 'dimension' && first)\n data = [...data].sort((a, b) =>\n sort === 'desc' ? Number(b[first]) - Number(a[first]) : Number(a[first]) - Number(b[first])\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 // 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 state = chartPlaceholder({ height, error, isLoading, empty: !data.length })\n\n const ChartTooltip = ({ active, payload }: any) => {\n if (!active || !payload?.length) return null\n const point: Point = payload[0].payload\n return (\n <TooltipBox title={point.label} caption={labelOf(dimension)}>\n {measures.map((measure, index) => (\n <Box key={measure} sx={{ display: 'flex', alignItems: 'center', gap: 0.75 }}>\n <Box sx={{ width: 8, height: 8, borderRadius: '50%', bgcolor: seriesColor(index) }} />\n {labelOf(measure)}: {formats[index]?.(point[measure] as number)}\n </Box>\n ))}\n </TooltipBox>\n )\n }\n\n const handleClick = (index: number, 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) filter.toggle(point.value, event)\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 < measures.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={\n measures.length > 1\n ? measures.map((measure, index) => ({\n label: labelOf(measure),\n color: seriesColor(index)\n }))\n : []\n }\n loading={isLoading}\n />\n {state ?? (\n <Box\n onClick={filter.clear}\n sx={{\n height,\n overflowY: horizontal ? 'auto' : 'hidden',\n opacity: isLoading ? 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: showLabels ? 96 : 16, left: 8, bottom: 4 }\n : { top: showLabels ? 24 : 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 {measures.map((measure, index) => (\n <Bar\n key={measure}\n dataKey={measure}\n name={labelOf(measure)}\n fill={seriesColor(index)}\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, 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={filter.isDimmed(point.value) ? 0.35 : 1}\n />\n ))}\n {/* Empilhado: valor só no fim da pilha seria o total; fica no tooltip */}\n {showLabels && !stacked && (\n <LabelList\n dataKey={measure}\n position={horizontal ? 'right' : 'top'}\n formatter={(value: unknown) => formats[index]?.(value as number) ?? ''}\n style={{ fontSize: 12, fill: '#333', fontWeight: 600 }}\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 { ChartNumberFormat } 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 /** Coluna da ordem inicial (dimensão ou medida); quem usa reordena clicando no cabeçalho. */\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 /** Nome da consulta no devtools. */\n queryLabel?: string\n}\n\nconst EMPTY: string[] = []\n\n/** Chave da coluna de percentual de uma medida (ordenação). */\nconst PERCENT = '%:'\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 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 const { rows, isLoading, error, inspectProps } = useModelQuery({\n dimensions,\n measures: [...measures, ...extraMeasures],\n ignoreFilters,\n label: name\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 numéricas na ordem: cada medida seguida do seu percentual; percentuais avulsos no fim\n const valueColumns = [\n ...measures.flatMap((measure) =>\n percentOf.includes(measure) ? [measure, `${PERCENT}${measure}`] : [measure]\n ),\n ...extraMeasures.map((measure) => `${PERCENT}${measure}`)\n ]\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 placeholder = chartPlaceholder({ height: 160, error, isLoading, empty: !rows.length })\n\n const header = (column: string, numeric: boolean) => (\n <TableCell\n key={column}\n align={numeric ? 'right' : 'left'}\n sortDirection={sort.by === column ? sort.direction : false}\n sx={{ fontWeight: 700, bgcolor: '#f3f3f3', whiteSpace: 'nowrap' }}\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 {isLoading && (\n <CircularProgress size={14} sx={{ position: 'absolute', top: -22, right: 0 }} />\n )}\n {placeholder ?? (\n <Box\n sx={{\n maxHeight: height,\n overflow: 'auto',\n opacity: isLoading ? 0.5 : 1,\n transition: 'opacity .2s'\n }}\n >\n <Table size=\"small\" stickyHeader sx={{ '& td, & th': { fontSize: 13 } }}>\n <TableHead>\n <TableRow>\n {dimensions.map((dimension) => header(dimension, false))}\n {valueColumns.map((column) => header(column, true))}\n </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 return (\n <TableRow\n key={dimensions.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 {dimensions.map((dimension) => (\n <TableCell key={dimension}>\n {dimensionText(dimension, row[dimension])}\n </TableCell>\n ))}\n {valueColumns.map((column) => (\n <TableCell key={column} align=\"right\" sx={{ whiteSpace: 'nowrap' }}>\n {cellText(row, column)}\n </TableCell>\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 {dimensions.map((dimension, index) => (\n <TableCell key={dimension}>{index === 0 ? 'Total' : ''}</TableCell>\n ))}\n {valueColumns.map((column) => (\n <TableCell key={column} align=\"right\" sx={{ whiteSpace: 'nowrap' }}>\n {column.startsWith(PERCENT)\n ? formatPercent(sums[column.slice(PERCENT.length)] ? 1 : null)\n : formats[column]?.(totalRow[column])}\n </TableCell>\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 } 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 /** 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\n/**\n * Rosca de uma medida por uma dimensão, com o total no centro e a legenda ao lado (nome, % e valor).\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 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 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 alignItems: 'center',\n gap: 2,\n opacity: isLoading ? 0.5 : 1,\n transition: 'opacity .2s'\n }}\n >\n <Box sx={{ position: 'relative', height: '100%', flex: '0 0 50%', minWidth: 140 }}>\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=\"62%\"\n outerRadius=\"92%\"\n startAngle={90}\n endAngle={-270}\n stroke=\"#fff\"\n strokeWidth={2}\n isAnimationActive={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 <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 </Box>\n <Box\n component=\"ul\"\n sx={{\n listStyle: 'none',\n m: 0,\n p: 0,\n minWidth: 0,\n flex: 1,\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 </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 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`); o `cards.gap` do layout (px) tem prioridade. */\n gap?: number\n}\n\nfunction DefaultPanel({ title, card, children }: ChartPanelProps) {\n const px = (value: number | undefined) => (value === undefined ? undefined : `${value}px`)\n return (\n <Paper\n elevation={card.shadow ?? 0}\n sx={{\n p: px(card.padding) ?? 1.5,\n minWidth: 0,\n height: '100%',\n bgcolor: card.background,\n border: `${card.borderWidth ?? 1}px solid`,\n borderColor: card.borderColor ?? 'divider',\n borderRadius: px(card.borderRadius)\n }}\n >\n {title && (\n <Typography\n sx={{\n fontWeight: 700,\n mb: 1,\n color: card.titleColor,\n fontSize: px(card.titleSize),\n textAlign: card.titleAlign\n }}\n >\n {title}\n </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\n return (\n <Box\n sx={{\n display: 'grid',\n gap: current.cards?.gap === undefined ? gap : `${current.cards.gap}px`,\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, ...props } = chart\n return (\n <BarChart {...props} queryLabel={queryLabel} formatDimension={formatter(formatDimension)} />\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":["RechartsBarChart","Tooltip","Tooltip","Tooltip"],"sources":["../../src/client/chartKit.tsx","../../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 { Box, CircularProgress } from '@mui/material'\nimport type { MouseEvent, ReactNode } from 'react'\nimport type { DashboardRow, FilterValue } from '../types'\nimport { useDashboard } from './DashboardProvider'\n\n/**\n * Peças comuns dos gráficos ligados ao modelo: paleta, filtro por clique, legenda e os estados de\n * carregando/erro/vazio.\n */\n\n/**\n * Paleta categórica, sempre nesta ordem (a série N tem sempre a mesma cor). Laranja Rocha primeiro;\n * a ordem passa no validador de daltonismo (CVD ΔE ≥ 9 entre vizinhas) e de visão normal (≥ 19).\n */\nexport const SERIES_COLORS = [\n '#F58220',\n '#2a78d6',\n '#1baf7a',\n '#eda100',\n '#e87ba4',\n '#008300',\n '#6250d6',\n '#e34948'\n] as const\n\n/** \"Outros\" (fatias agrupadas) fica neutro, fora da paleta. */\nexport const OTHER_COLOR = '#9e9e9e'\n\nexport const seriesColor = (index: number) => SERIES_COLORS[index % SERIES_COLORS.length] as string\n\n/** Valor numérico de uma coluna da linha (`null` quando vazio). */\nexport const numberOf = (row: DashboardRow, key?: string) =>\n key && row[key] !== null && row[key] !== undefined ? Number(row[key]) : null\n\n/**\n * Filtro cruzado a partir do gráfico: clicar num valor filtra o dashboard por ele (Ctrl/Cmd+clique\n * acumula; clicar de novo no único selecionado limpa). O gráfico deve ignorar o próprio filtro na\n * consulta (`ignoreFilters`) e só destacar a seleção.\n */\nexport function useClickFilter(dimension: string | undefined, enabled: boolean) {\n const { filters, setFilter } = useDashboard()\n const selected = enabled && dimension ? (filters[dimension] ?? []) : []\n\n const toggle = (value: FilterValue, event?: Pick<MouseEvent, 'ctrlKey' | 'metaKey'>) => {\n if (!enabled || !dimension) return\n if (event?.ctrlKey || event?.metaKey)\n setFilter(\n dimension,\n selected.includes(value) ? selected.filter((item) => item !== value) : [...selected, value]\n )\n else setFilter(dimension, selected.length === 1 && selected[0] === value ? [] : [value])\n }\n\n return {\n selected,\n /** Há seleção e este valor não está nela. */\n isDimmed: (value: FilterValue) => selected.length > 0 && !selected.includes(value),\n toggle,\n clear: () => {\n if (enabled && dimension && selected.length) setFilter(dimension, [])\n }\n }\n}\n\nexport function Legend({\n items,\n loading\n}: {\n items: { label: string; color: string }[]\n loading?: boolean\n}) {\n return (\n <Box\n sx={{\n display: 'flex',\n flexWrap: 'wrap',\n columnGap: 1.5,\n rowGap: 0.5,\n mb: 1,\n fontSize: 14,\n color: '#555',\n minHeight: 21\n }}\n >\n {items.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 {loading && <CircularProgress size={14} sx={{ ml: 'auto' }} />}\n </Box>\n )\n}\n\n/** Erro / carregando / sem dados no lugar do gráfico; `null` quando há o que desenhar (função, não componente). */\nexport function chartPlaceholder({\n height,\n error,\n isLoading,\n empty\n}: {\n height: number\n error: unknown\n isLoading: boolean\n empty: boolean\n}): ReactNode {\n if (!error && !empty) return null\n return (\n <Box\n sx={{\n height,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: error ? 'error.main' : '#999'\n }}\n >\n {error\n ? 'Erro ao carregar o gráfico'\n : isLoading\n ? 'Carregando…'\n : 'Sem dados para os filtros selecionados'}\n </Box>\n )\n}\n\n/** `caption`: o que é o título (ex.: o rótulo da dimensão), em cinza acima dele. */\nexport function TooltipBox({\n title,\n caption,\n children\n}: {\n title: string\n caption?: string\n children: ReactNode\n}) {\n return (\n <Box sx={{ bgcolor: '#fff', border: '1px solid #ccc', p: 1, fontSize: 13 }}>\n {caption && <Box sx={{ fontSize: 11, color: '#777' }}>{caption}</Box>}\n <Box sx={{ fontWeight: 700 }}>{title}</Box>\n {children}\n </Box>\n )\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 type { 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 { 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). */\n measures: string[]\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. */\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 /** Valores nas pontas das barras (até 30 categorias; acima disso, só tooltip). */\n showValues?: boolean\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/** 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 | FilterValue>\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 */\nexport function BarChart({\n dimension,\n measures,\n orientation = 'vertical',\n stacked = false,\n sort = 'dimension',\n limit,\n formatDimension = String,\n hideEmpty = true,\n showValues = true,\n clickToFilter = false,\n height = 360,\n labels,\n formats: formatsByMeasure,\n queryLabel\n}: BarChartProps) {\n const { meta } = useDashboard()\n const { rows, isLoading, error, inspectProps } = useModelQuery({\n dimensions: [dimension],\n measures,\n ignoreFilters: clickToFilter ? [dimension] : undefined,\n label: queryLabel ?? `BarChart · ${dimension}`\n })\n const filter = useClickFilter(dimension, 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 const first = measures[0]\n let data: Point[] = rows\n .filter((row) => !hideEmpty || measures.some((measure) => numberOf(row, measure)))\n .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 if (sort !== 'dimension' && first)\n data = [...data].sort((a, b) =>\n sort === 'desc' ? Number(b[first]) - Number(a[first]) : Number(a[first]) - Number(b[first])\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 // 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 state = chartPlaceholder({ height, error, isLoading, empty: !data.length })\n\n const ChartTooltip = ({ active, payload }: any) => {\n if (!active || !payload?.length) return null\n const point: Point = payload[0].payload\n return (\n <TooltipBox title={point.label} caption={labelOf(dimension)}>\n {measures.map((measure, index) => (\n <Box key={measure} sx={{ display: 'flex', alignItems: 'center', gap: 0.75 }}>\n <Box sx={{ width: 8, height: 8, borderRadius: '50%', bgcolor: seriesColor(index) }} />\n {labelOf(measure)}: {formats[index]?.(point[measure] as number)}\n </Box>\n ))}\n </TooltipBox>\n )\n }\n\n const handleClick = (index: number, 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) filter.toggle(point.value, event)\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 < measures.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={\n measures.length > 1\n ? measures.map((measure, index) => ({\n label: labelOf(measure),\n color: seriesColor(index)\n }))\n : []\n }\n loading={isLoading}\n />\n {state ?? (\n <Box\n onClick={filter.clear}\n sx={{\n height,\n overflowY: horizontal ? 'auto' : 'hidden',\n opacity: isLoading ? 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: showLabels ? 96 : 16, left: 8, bottom: 4 }\n : { top: showLabels ? 24 : 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 {measures.map((measure, index) => (\n <Bar\n key={measure}\n dataKey={measure}\n name={labelOf(measure)}\n fill={seriesColor(index)}\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, 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={filter.isDimmed(point.value) ? 0.35 : 1}\n />\n ))}\n {/* Empilhado: valor só no fim da pilha seria o total; fica no tooltip */}\n {showLabels && !stacked && (\n <LabelList\n dataKey={measure}\n position={horizontal ? 'right' : 'top'}\n formatter={(value: unknown) => formats[index]?.(value as number) ?? ''}\n style={{ fontSize: 12, fill: '#333', fontWeight: 600 }}\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 ChartNumberFormat, orderedColumns } 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 /** Coluna da ordem inicial (dimensão ou medida); quem usa reordena clicando no cabeçalho. */\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 e medidas (ex.: `['custoTotal', 'navio']`); o que não\n * estiver nela vai depois. Padrão: dimensões e depois medidas.\n */\n columnOrder?: string[]\n /** Nome da consulta no devtools. */\n queryLabel?: string\n}\n\nconst EMPTY: string[] = []\n\n/** Chave da coluna de percentual de uma medida (ordenação). */\nconst PERCENT = '%:'\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 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 const { rows, isLoading, error, inspectProps } = useModelQuery({\n dimensions,\n measures: [...measures, ...extraMeasures],\n ignoreFilters,\n label: name\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: cada medida seguida do seu percentual; percentuais avulsos no fim\n const columns = [\n ...orderedColumns([...dimensions, ...measures], columnOrder).flatMap((column) =>\n percentOf.includes(column) && !dimensions.includes(column)\n ? [column, `${PERCENT}${column}`]\n : [column]\n ),\n ...extraMeasures.map((measure) => `${PERCENT}${measure}`)\n ]\n const isDimension = (column: string) => dimensions.includes(column)\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 placeholder = chartPlaceholder({ height: 160, error, isLoading, empty: !rows.length })\n\n const header = (column: string, numeric: boolean) => (\n <TableCell\n key={column}\n align={numeric ? 'right' : 'left'}\n sortDirection={sort.by === column ? sort.direction : false}\n sx={{ fontWeight: 700, bgcolor: '#f3f3f3', whiteSpace: 'nowrap' }}\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 {isLoading && (\n <CircularProgress size={14} sx={{ position: 'absolute', top: -22, right: 0 }} />\n )}\n {placeholder ?? (\n <Box\n sx={{\n maxHeight: height,\n overflow: 'auto',\n opacity: isLoading ? 0.5 : 1,\n transition: 'opacity .2s'\n }}\n >\n <Table size=\"small\" stickyHeader sx={{ '& td, & th': { fontSize: 13 } }}>\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 return (\n <TableRow\n key={dimensions.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 key={column}>{dimensionText(column, row[column])}</TableCell>\n ) : (\n <TableCell key={column} align=\"right\" sx={{ whiteSpace: 'nowrap' }}>\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 key={column}>\n {column === totalLabelColumn ? 'Total' : ''}\n </TableCell>\n ) : (\n <TableCell key={column} align=\"right\" sx={{ whiteSpace: 'nowrap' }}>\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 } 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 /** 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\n/**\n * Rosca de uma medida por uma dimensão, com o total no centro e a legenda ao lado (nome, % e valor).\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 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 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 alignItems: 'center',\n gap: 2,\n opacity: isLoading ? 0.5 : 1,\n transition: 'opacity .2s'\n }}\n >\n <Box sx={{ position: 'relative', height: '100%', flex: '0 0 50%', minWidth: 140 }}>\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=\"62%\"\n outerRadius=\"92%\"\n startAngle={90}\n endAngle={-270}\n stroke=\"#fff\"\n strokeWidth={2}\n isAnimationActive={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 <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 </Box>\n <Box\n component=\"ul\"\n sx={{\n listStyle: 'none',\n m: 0,\n p: 0,\n minWidth: 0,\n flex: 1,\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 </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 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`); o `cards.gap` do layout (px) tem prioridade. */\n gap?: number\n}\n\nfunction DefaultPanel({ title, card, children }: ChartPanelProps) {\n const px = (value: number | undefined) => (value === undefined ? undefined : `${value}px`)\n return (\n <Paper\n elevation={card.shadow ?? 0}\n sx={{\n p: px(card.padding) ?? 1.5,\n minWidth: 0,\n height: '100%',\n bgcolor: card.background,\n border: `${card.borderWidth ?? 1}px solid`,\n borderColor: card.borderColor ?? 'divider',\n borderRadius: px(card.borderRadius)\n }}\n >\n {title && (\n <Typography\n sx={{\n fontWeight: 700,\n mb: 1,\n color: card.titleColor,\n fontSize: px(card.titleSize),\n textAlign: card.titleAlign\n }}\n >\n {title}\n </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\n return (\n <Box\n sx={{\n display: 'grid',\n gap: current.cards?.gap === undefined ? gap : `${current.cards.gap}px`,\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, ...props } = chart\n return (\n <BarChart {...props} queryLabel={queryLabel} formatDimension={formatter(formatDimension)} />\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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"}
|
|
@@ -440,7 +440,7 @@ const percentDecimals = {
|
|
|
440
440
|
max: 6,
|
|
441
441
|
default: 1,
|
|
442
442
|
label: "Casas do %",
|
|
443
|
-
section: "
|
|
443
|
+
section: "Dados"
|
|
444
444
|
};
|
|
445
445
|
const CHART_FIELDS = {
|
|
446
446
|
kpi: {
|
|
@@ -634,6 +634,12 @@ const CHART_FIELDS = {
|
|
|
634
634
|
label: "Medidas (colunas)",
|
|
635
635
|
section: "Dados"
|
|
636
636
|
},
|
|
637
|
+
columnOrder: {
|
|
638
|
+
kind: "columnOrder",
|
|
639
|
+
label: "Ordem das colunas",
|
|
640
|
+
hint: "Dimensões e medidas em qualquer ordem; vazio = dimensões e depois medidas",
|
|
641
|
+
section: "Dados"
|
|
642
|
+
},
|
|
637
643
|
percentOf: {
|
|
638
644
|
kind: "measures",
|
|
639
645
|
label: "% do total",
|
|
@@ -905,6 +911,7 @@ function fieldError(spec, value) {
|
|
|
905
911
|
case "column": return isName(value) ? null : spec.required ? "é obrigatório" : "precisa ser texto";
|
|
906
912
|
case "dimensions":
|
|
907
913
|
case "measures":
|
|
914
|
+
case "columnOrder":
|
|
908
915
|
if (!Array.isArray(value) || !value.every(isName)) return "precisa ser uma lista de nomes";
|
|
909
916
|
if (spec.required && !value.length) return "precisa de pelo menos um item";
|
|
910
917
|
return new Set(value).size === value.length ? null : "tem item repetido";
|
|
@@ -1033,10 +1040,24 @@ function fieldReferences(fields, item) {
|
|
|
1033
1040
|
}
|
|
1034
1041
|
return refs;
|
|
1035
1042
|
}
|
|
1036
|
-
/**
|
|
1043
|
+
/**
|
|
1044
|
+
* Colunas que o gráfico mostra (para `sortBy`, rótulos): as dimensões e medidas escolhidas nele, na
|
|
1045
|
+
* ordem do campo `columnOrder` (se o tipo tiver) e o resto depois.
|
|
1046
|
+
*/
|
|
1037
1047
|
function chartColumns(chart, types = BUILTIN_CHART_TYPES) {
|
|
1038
1048
|
const { dimensions, measures } = chartReferences(chart, types);
|
|
1039
|
-
return [...dimensions, ...measures];
|
|
1049
|
+
return orderedColumns([.../* @__PURE__ */ new Set([...dimensions, ...measures])], columnOrderOf(chart, types));
|
|
1050
|
+
}
|
|
1051
|
+
/** Valor do campo `columnOrder` do gráfico (o tipo pode não ter). */
|
|
1052
|
+
function columnOrderOf(chart, types = BUILTIN_CHART_TYPES) {
|
|
1053
|
+
const values = chart;
|
|
1054
|
+
for (const [key, spec] of Object.entries(types[chart.type]?.fields ?? {})) if (spec.kind === "columnOrder" && Array.isArray(values[key])) return values[key];
|
|
1055
|
+
}
|
|
1056
|
+
/** `columns` na ordem de `order`; os que não estão nela vão depois, na ordem em que vieram. */
|
|
1057
|
+
function orderedColumns(columns, order) {
|
|
1058
|
+
if (!order?.length) return columns;
|
|
1059
|
+
const first = order.filter((name) => columns.includes(name));
|
|
1060
|
+
return [...first, ...columns.filter((name) => !first.includes(name))];
|
|
1040
1061
|
}
|
|
1041
1062
|
/**
|
|
1042
1063
|
* Dimensões/medidas que o layout usa e o modelo não tem. Não impede salvar (o modelo pode estar
|
|
@@ -1056,6 +1077,9 @@ function layoutModelWarnings(layout, model, types = BUILTIN_CHART_TYPES) {
|
|
|
1056
1077
|
if ((spec.kind === "labels" || spec.kind === "formats") && isRecord(value)) {
|
|
1057
1078
|
for (const column of Object.keys(value)) if (!columns.includes(column)) warnings.push(`${name}: "${column}" (${key}) não é coluna do gráfico`);
|
|
1058
1079
|
}
|
|
1080
|
+
if (spec.kind === "columnOrder" && Array.isArray(value)) {
|
|
1081
|
+
for (const column of value) if (isName(column) && !columns.includes(column)) warnings.push(`${name}: "${column}" (${key}) não é coluna do gráfico`);
|
|
1082
|
+
}
|
|
1059
1083
|
}
|
|
1060
1084
|
}
|
|
1061
1085
|
for (const filter of layout.filters ?? []) if (!model.dimensions[filter.dimension]) warnings.push(`filtro "${filter.label || filter.dimension}": dimensão "${filter.dimension}" não existe`);
|
|
@@ -1158,6 +1182,6 @@ function layoutFileContent(layout) {
|
|
|
1158
1182
|
return `${JSON.stringify(layout, null, 2)}\n`;
|
|
1159
1183
|
}
|
|
1160
1184
|
//#endregion
|
|
1161
|
-
export {
|
|
1185
|
+
export { measureHome as A, AGGREGATION_LABEL as C, modelMeta as D, isAggregate as E, parseColumnRef as M, reachFrom as N, validateModel as O, referencedTables as P, AGGREGATIONS as S, aggregateSql as T, validateLayout as _, FILTER_FIELDS as a, modelObjectCode as b, chartOfType as c, filterReferences as d, isBuiltinChart as f, resolveChartTypes as g, orderedColumns as h, CARD_FIELDS as i, modelEdges as j, joinPlan as k, chartReferences as l, layoutModelWarnings as m, CANVAS_PRESETS as n, chartCardStyle as o, layoutFileContent as p, CARDS_FIELDS as r, chartColumns as s, BUILTIN_CHART_TYPES as t, customChartProps as u, canonicalJson as v, VALUE_FORMATS as w, toModelCode as x, modelImports as y };
|
|
1162
1186
|
|
|
1163
|
-
//# sourceMappingURL=layout-
|
|
1187
|
+
//# sourceMappingURL=layout-QuOYFmp1.js.map
|