@bluemarble/bi 0.6.4 → 0.6.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
- import { a as toModelCode, c as VALUE_FORMATS, f as validateModel, g as parseColumnRef, h as modelEdges, m as measureHome, o as AGGREGATIONS, s as AGGREGATION_LABEL, t as canonicalJson, u as isAggregate, v as referencedTables } from "./codegen-DkfI6UJr.js";
1
+ import { c as VALUE_FORMATS, f as validateModel, g as parseColumnRef, h as modelEdges, m as measureHome, o as AGGREGATIONS, s as AGGREGATION_LABEL, t as canonicalJson, u as isAggregate, v as referencedTables } from "./codegen-LoQzFAle.js";
2
2
  import { n as diffRows } from "./compare-DloZhg1T.js";
3
- import { C as RULE_OPERATOR_LABEL, S as RULE_OPERATORS, _ as tableColumns, a as FILTER_FIELDS, b as COLUMN_VERTICAL_ALIGNS, c as chartOfType, d as filterReferences, h as percentColumn, i as CARD_FIELDS, l as chartReferences, m as layoutModelWarnings, n as CANVAS_PRESETS, p as layoutFileContent, r as CARDS_FIELDS, s as chartColumns, t as BUILTIN_CHART_TYPES, v as validateLayout, w as UNARY_OPERATORS, x as NUMERIC_OPERATORS, y as COLUMN_ALIGNS } from "./layout-nViz3MdU.js";
4
- import { d as useDashboard, f as errorMessage, h as parseLayoutItemKey, m as layoutItemKey, n as INSPECT_ATTRIBUTE, o as formatMeasure, p as LAYOUT_ITEM_ATTRIBUTE, t as ModelDictionary } from "./ModelDictionary-Dib4Vk3i.js";
3
+ import { C as RULE_OPERATORS, E as VALUE_RULE_OPERATORS, S as NUMERIC_OPERATORS, T as UNARY_OPERATORS, a as FILTER_FIELDS, b as COLUMN_ALIGNS, c as chartColumns, f as filterReferences, g as percentColumn, h as layoutModelWarnings, i as CARD_FIELDS, l as chartOfType, n as CANVAS_PRESETS, o as cardsGap, r as CARDS_FIELDS, t as BUILTIN_CHART_TYPES, u as chartReferences, v as tableColumns, w as RULE_OPERATOR_LABEL, x as COLUMN_VERTICAL_ALIGNS, y as validateLayout } from "./layout-CrZ00tB0.js";
4
+ import { C as parseLayoutItemKey, S as layoutItemKey, b as errorMessage, f as SERIES_COLORS, n as INSPECT_ATTRIBUTE, o as formatMeasure, t as ModelDictionary, x as LAYOUT_ITEM_ATTRIBUTE, y as useDashboard } from "./ModelDictionary-DUGFHBo-.js";
5
5
  import { Alert, Autocomplete, Box, Button, Checkbox, Chip, CircularProgress, Collapse, Dialog, DialogActions, DialogContent, DialogTitle, Divider, FormControlLabel, IconButton, List, ListItemButton, ListSubheader, Menu, MenuItem, MenuList, Paper, Popover, Popper, Portal, Switch, Tab, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, TableSortLabel, Tabs, TextField, ThemeProvider, ToggleButton, ToggleButtonGroup, Tooltip, Typography, createTheme } from "@mui/material";
6
6
  import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
7
7
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -1001,10 +1001,21 @@ const chartCardFields = (cards) => Object.fromEntries(Object.entries(CARD_FIELDS
1001
1001
  ...spec,
1002
1002
  default: cards?.[key] ?? spec.default
1003
1003
  }]));
1004
+ /** `cards` como o formulário edita: o `gap` antigo vira `rowGap` e `columnGap`. */
1005
+ const cardsValues = (cards) => {
1006
+ const { gap: _gap, ...rest } = cards ?? {};
1007
+ const space = cardsGap(cards);
1008
+ return nonEmpty({
1009
+ ...rest,
1010
+ ...space.row === void 0 ? {} : { rowGap: space.row },
1011
+ ...space.column === void 0 ? {} : { columnGap: space.column }
1012
+ }) ?? {};
1013
+ };
1004
1014
  const cardsSummary = (cards) => {
1005
- const { gap, ...style } = cards ?? {};
1015
+ const { gap: _gap, rowGap: _row, columnGap: _column, ...style } = cards ?? {};
1016
+ const space = cardsGap(cards);
1006
1017
  const custom = Object.keys(style).length;
1007
- return `espaço ${String(gap ?? CARDS_FIELDS.gap?.default)}px · ${custom ? `${custom} ajuste(s) de estilo` : "estilo padrão"}`;
1018
+ return `espaço ${String(space.row ?? CARDS_FIELDS.rowGap?.default)}×${String(space.column ?? CARDS_FIELDS.columnGap?.default)}px · ${custom ? `${custom} ajuste(s) de estilo` : "estilo padrão"}`;
1008
1019
  };
1009
1020
  /** Campo opcional vazio sai do objeto, para o JSON ficar só com o que foi definido. */
1010
1021
  function withField(object, key, value) {
@@ -1166,7 +1177,7 @@ function LayoutPanel({ devtools, model, capabilities, picked, onHover }) {
1166
1177
  });
1167
1178
  const patchChart = (id, change) => setCharts(charts.map((chart) => chart.id === id ? change(chart) : chart));
1168
1179
  const setCanvas = (next) => update(withField(editing, "canvas", next));
1169
- const setCards = (key, value) => update(withField(editing, "cards", nonEmpty(withField(editing.cards ?? {}, key, value))));
1180
+ const setCards = (key, value) => update(withField(editing, "cards", nonEmpty(withField(cardsValues(editing.cards), key, value))));
1170
1181
  const setFilters = (next) => update({
1171
1182
  ...editing,
1172
1183
  filters: next
@@ -1479,7 +1490,7 @@ function LayoutPanel({ devtools, model, capabilities, picked, onHover }) {
1479
1490
  children: "Estilo padrão dos cards de todos os gráficos; cada gráfico pode sobrepor na seção Card dele. Vazio = padrão do componente."
1480
1491
  }), /* @__PURE__ */ jsx(FieldsForm, {
1481
1492
  fields: CARDS_FIELDS,
1482
- values: editing.cards ?? {},
1493
+ values: cardsValues(editing.cards),
1483
1494
  onSet: setCards,
1484
1495
  model,
1485
1496
  formatters: [],
@@ -1545,11 +1556,7 @@ function LayoutPanel({ devtools, model, capabilities, picked, onHover }) {
1545
1556
  children: errors.length ? "Edições com erro, não aplicadas" : "Edições não aplicadas"
1546
1557
  })]
1547
1558
  }),
1548
- /* @__PURE__ */ jsx(CopyButton, {
1549
- text: layoutFileContent(editing),
1550
- label: "Copiar JSON"
1551
- }),
1552
- /* @__PURE__ */ jsx(ConfirmButton, {
1559
+ !autoApply && /* @__PURE__ */ jsx(ConfirmButton, {
1553
1560
  size: "small",
1554
1561
  disabled: !dirty,
1555
1562
  onConfirm: () => setEditing(reference),
@@ -1559,17 +1566,20 @@ function LayoutPanel({ devtools, model, capabilities, picked, onHover }) {
1559
1566
  confirmLabel: "Desfazer",
1560
1567
  children: "Desfazer"
1561
1568
  }),
1562
- /* @__PURE__ */ jsx(Button, {
1569
+ /* @__PURE__ */ jsx(ConfirmButton, {
1563
1570
  size: "small",
1564
1571
  color: "warning",
1565
1572
  disabled: !entry.draft,
1566
- onClick: () => {
1573
+ onConfirm: () => {
1567
1574
  devtools.store.expectRefetch();
1568
1575
  layouts.setPending(entry.registered.id, null);
1569
1576
  layouts.setDraft(entry.registered.id, null);
1570
1577
  setEditingState(entry.registered);
1571
1578
  },
1572
1579
  title: "Volta a página e o editor ao layout do arquivo",
1580
+ confirmTitle: "Descartar o rascunho?",
1581
+ confirmText: "O rascunho e as edições do editor serão perdidos; a página e o editor voltam ao layout do arquivo.",
1582
+ confirmLabel: "Descartar",
1573
1583
  children: "Descartar rascunho"
1574
1584
  }),
1575
1585
  capabilities?.saveLayout && /* @__PURE__ */ jsx(Button, {
@@ -2155,6 +2165,16 @@ function FieldsForm({ fields, values, onSet: set, onSetMany, model, formatters,
2155
2165
  }
2156
2166
  });
2157
2167
  }
2168
+ case "valueRule": return /* @__PURE__ */ jsx(ValueRuleInput, {
2169
+ rule: value,
2170
+ label: spec.label,
2171
+ onChange: (rule) => set(key, rule)
2172
+ });
2173
+ case "colors": return /* @__PURE__ */ jsx(ColorsInput, {
2174
+ colors: value ?? {},
2175
+ measures: spec.values && values[spec.values] ? null : chosenMeasures,
2176
+ onChange: (next) => set(key, Object.keys(next).length ? next : void 0)
2177
+ });
2158
2178
  case "formatRules": return /* @__PURE__ */ jsx(FormatRulesInput, {
2159
2179
  rules: value ?? [],
2160
2180
  fieldOptions,
@@ -2234,7 +2254,7 @@ function FieldsForm({ fields, values, onSet: set, onSetMany, model, formatters,
2234
2254
  ...pairedFormatters
2235
2255
  ].filter(Boolean));
2236
2256
  const sections = [...new Set(entries.filter(([key]) => !hidden.has(key)).map(([, spec]) => spec.section))];
2237
- const fullRow = (spec) => spec.kind === "dimensions" || spec.kind === "measures" || spec.kind === "formatters" || spec.kind === "formatRules";
2257
+ const fullRow = (spec) => spec.kind === "dimensions" || spec.kind === "measures" || spec.kind === "formatters" || spec.kind === "formatRules" || spec.kind === "colors" || spec.kind === "valueRule";
2238
2258
  const gridColumn = (spec, key) => fullRow(spec) ? "1 / -1" : key === "title" && formColumns > 1 ? "span 2" : void 0;
2239
2259
  return /* @__PURE__ */ jsx(Fragment, { children: sections.map((section) => {
2240
2260
  const inSection = entries.filter(([, spec]) => spec.section === section);
@@ -2248,7 +2268,7 @@ function FieldsForm({ fields, values, onSet: set, onSetMany, model, formatters,
2248
2268
  gridColumn: gridColumn(spec, key),
2249
2269
  alignSelf: spec.kind === "boolean" ? "end" : void 0
2250
2270
  },
2251
- children: spec.kind === "boolean" ? withHint(input(key, spec), spec.hint) : merged?.dimensions === key ? field(merged.percents ? "Dimensões, medidas e %" : "Dimensões e medidas", input(key, spec), `${merged.order ? "Em qualquer ordem: é a ordem das colunas. " : ""}${[
2271
+ children: spec.kind === "boolean" || spec.kind === "valueRule" ? withHint(input(key, spec), spec.hint) : merged?.dimensions === key ? field(merged.percents ? "Dimensões, medidas e %" : "Dimensões e medidas", input(key, spec), `${merged.order ? "Em qualquer ordem: é a ordem das colunas. " : ""}${[
2252
2272
  spec.hint,
2253
2273
  merged.measuresSpec.hint,
2254
2274
  merged.percentsSpec?.hint && `% do total: ${merged.percentsSpec.hint}`
@@ -2657,6 +2677,198 @@ function ColorInput({ value, fallback, onCommit }) {
2657
2677
  })]
2658
2678
  });
2659
2679
  }
2680
+ /**
2681
+ * Regra de um valor (`ValueRule`): a checkbox liga (com "diferente de 0") e desliga (sai do JSON);
2682
+ * ligada, escolhe o operador e o número (e o fim do intervalo no "entre").
2683
+ */
2684
+ function ValueRuleInput({ rule, label, onChange }) {
2685
+ const setOperator = (operator) => {
2686
+ const { to, ...rest } = rule ?? { value: 0 };
2687
+ onChange(operator === "between" ? {
2688
+ ...rest,
2689
+ operator,
2690
+ to: to ?? rest.value
2691
+ } : {
2692
+ ...rest,
2693
+ operator
2694
+ });
2695
+ };
2696
+ return /* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsx(FormControlLabel, {
2697
+ control: /* @__PURE__ */ jsx(Checkbox, {
2698
+ size: "small",
2699
+ checked: !!rule,
2700
+ onChange: (e) => onChange(e.target.checked ? {
2701
+ operator: "!=",
2702
+ value: 0
2703
+ } : void 0)
2704
+ }),
2705
+ label: /* @__PURE__ */ jsx(Typography, {
2706
+ sx: { fontSize: 12 },
2707
+ children: label
2708
+ })
2709
+ }), rule && /* @__PURE__ */ jsxs(Box, {
2710
+ sx: {
2711
+ display: "flex",
2712
+ gap: .5,
2713
+ alignItems: "center",
2714
+ pl: 3.5
2715
+ },
2716
+ children: [
2717
+ /* @__PURE__ */ jsx(Typography, {
2718
+ sx: {
2719
+ fontSize: 12,
2720
+ whiteSpace: "nowrap"
2721
+ },
2722
+ children: "valor"
2723
+ }),
2724
+ /* @__PURE__ */ jsx(TextField, {
2725
+ select: true,
2726
+ size: "small",
2727
+ value: rule.operator,
2728
+ onChange: (e) => setOperator(e.target.value),
2729
+ sx: {
2730
+ ...inputSx$1,
2731
+ minWidth: 130
2732
+ },
2733
+ children: VALUE_RULE_OPERATORS.map((operator) => /* @__PURE__ */ jsx(MenuItem, {
2734
+ value: operator,
2735
+ sx: { fontSize: 12 },
2736
+ children: RULE_OPERATOR_LABEL[operator]
2737
+ }, operator))
2738
+ }),
2739
+ /* @__PURE__ */ jsx(RuleNumber, {
2740
+ value: rule.value,
2741
+ onCommit: (value) => onChange({
2742
+ ...rule,
2743
+ value
2744
+ })
2745
+ }),
2746
+ rule.operator === "between" && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Typography, {
2747
+ sx: { fontSize: 12 },
2748
+ children: "e"
2749
+ }), /* @__PURE__ */ jsx(RuleNumber, {
2750
+ value: rule.to ?? rule.value,
2751
+ onCommit: (to) => onChange({
2752
+ ...rule,
2753
+ to
2754
+ })
2755
+ })] })
2756
+ ]
2757
+ })] });
2758
+ }
2759
+ /** Número digitado (aceita vírgula); só grava quando o texto é um número. */
2760
+ function RuleNumber({ value, onCommit }) {
2761
+ const [typing, setTyping] = useState(null);
2762
+ return /* @__PURE__ */ jsx(TextField, {
2763
+ size: "small",
2764
+ value: typing ?? String(value),
2765
+ error: typing !== null && !Number.isFinite(Number(typing.trim().replace(",", "."))),
2766
+ onChange: (e) => {
2767
+ setTyping(e.target.value);
2768
+ const text = e.target.value.trim().replace(",", ".");
2769
+ const number = Number(text);
2770
+ if (text && Number.isFinite(number)) onCommit(number);
2771
+ },
2772
+ onBlur: () => setTyping(null),
2773
+ sx: {
2774
+ ...inputSx$1,
2775
+ width: 90
2776
+ }
2777
+ });
2778
+ }
2779
+ /**
2780
+ * Cor por série (`{ série: cor }`). `measures`: uma linha por medida do gráfico (padrão: a paleta,
2781
+ * na ordem); `null`: as séries são valores de uma dimensão, que o devtools não conhece — digita o
2782
+ * valor e adiciona.
2783
+ */
2784
+ function ColorsInput({ colors, measures, onChange }) {
2785
+ const [draft, setDraft] = useState("");
2786
+ const palette = (index) => SERIES_COLORS[index % SERIES_COLORS.length];
2787
+ const row = (name, fallback, remove) => /* @__PURE__ */ jsxs(Box, {
2788
+ sx: {
2789
+ display: "flex",
2790
+ gap: .5,
2791
+ alignItems: "center"
2792
+ },
2793
+ children: [
2794
+ /* @__PURE__ */ jsx(Typography, {
2795
+ title: name,
2796
+ sx: {
2797
+ fontFamily: MONO,
2798
+ fontSize: 12,
2799
+ minWidth: 90,
2800
+ maxWidth: 140,
2801
+ overflow: "hidden",
2802
+ textOverflow: "ellipsis",
2803
+ whiteSpace: "nowrap"
2804
+ },
2805
+ children: name
2806
+ }),
2807
+ /* @__PURE__ */ jsx(ColorInput, {
2808
+ value: colors[name],
2809
+ fallback,
2810
+ onCommit: (color) => onChange(withField(colors, name, color))
2811
+ }),
2812
+ remove && /* @__PURE__ */ jsx(IconButton, {
2813
+ size: "small",
2814
+ title: "Tirar a cor",
2815
+ onClick: () => onChange(withField(colors, name, void 0)),
2816
+ children: "✕"
2817
+ })
2818
+ ]
2819
+ }, name);
2820
+ const add = () => {
2821
+ const name = draft.trim();
2822
+ if (!name || colors[name]) return;
2823
+ onChange({
2824
+ ...colors,
2825
+ [name]: palette(Object.keys(colors).length)
2826
+ });
2827
+ setDraft("");
2828
+ };
2829
+ if (measures) return /* @__PURE__ */ jsx(Box, {
2830
+ sx: {
2831
+ display: "flex",
2832
+ flexDirection: "column",
2833
+ gap: .5
2834
+ },
2835
+ children: measures.length ? measures.map((measure, index) => row(measure, palette(index), false)) : /* @__PURE__ */ jsx(Typography, {
2836
+ sx: {
2837
+ fontSize: 12,
2838
+ color: "text.disabled"
2839
+ },
2840
+ children: "sem medidas"
2841
+ })
2842
+ });
2843
+ return /* @__PURE__ */ jsxs(Box, {
2844
+ sx: {
2845
+ display: "flex",
2846
+ flexDirection: "column",
2847
+ gap: .5
2848
+ },
2849
+ children: [Object.keys(colors).map((name, index) => row(name, palette(index), true)), /* @__PURE__ */ jsxs(Box, {
2850
+ sx: {
2851
+ display: "flex",
2852
+ gap: .5,
2853
+ alignItems: "center"
2854
+ },
2855
+ children: [/* @__PURE__ */ jsx(TextField, {
2856
+ size: "small",
2857
+ fullWidth: true,
2858
+ value: draft,
2859
+ placeholder: "Valor da série (ou \"(em branco)\", \"Outros\")",
2860
+ onChange: (e) => setDraft(e.target.value),
2861
+ onKeyDown: (e) => e.key === "Enter" && add(),
2862
+ sx: inputSx$1
2863
+ }), /* @__PURE__ */ jsx(Button, {
2864
+ size: "small",
2865
+ onClick: add,
2866
+ disabled: !draft.trim() || !!colors[draft.trim()],
2867
+ children: "+ cor"
2868
+ })]
2869
+ })]
2870
+ });
2871
+ }
2660
2872
  /** Sem as chaves de colunas que saíram do gráfico; vazio = `undefined` (sai do JSON). */
2661
2873
  function pruned(map, keep) {
2662
2874
  const next = Object.fromEntries(Object.entries(map).filter(([key]) => keep.includes(key)));
@@ -5889,7 +6101,6 @@ function ModelPanel({ devtools, original, capabilities, tables, onTry, onSaved }
5889
6101
  const { store, draft, setDraft } = devtools;
5890
6102
  const { fetcher, model: modelName } = useDashboard();
5891
6103
  const [editor, setEditor] = useState(() => toEditor(draft ?? original));
5892
- const [showCode, setShowCode] = useState(false);
5893
6104
  const [checked, setChecked] = useState(null);
5894
6105
  const [columns, setColumns] = useState(null);
5895
6106
  const [columnErrors, setColumnErrors] = useState({});
@@ -6026,238 +6237,211 @@ function ModelPanel({ devtools, original, capabilities, tables, onTry, onSaved }
6026
6237
  const validationErrors = validation ? Object.entries(validation.errors) : [];
6027
6238
  return /* @__PURE__ */ jsxs(SqlCompletionsContext.Provider, {
6028
6239
  value: completions,
6029
- children: [
6030
- /* @__PURE__ */ jsxs(Box, {
6031
- sx: {
6032
- display: "flex",
6033
- flexDirection: "column",
6034
- height: "100%",
6035
- minHeight: 0
6036
- },
6037
- children: [
6038
- /* @__PURE__ */ jsxs(Box, {
6039
- sx: {
6040
- px: 1.5,
6041
- "& .MuiAlert-root": {
6042
- my: .5,
6043
- py: 0
6044
- }
6045
- },
6046
- children: [
6047
- draft && /* @__PURE__ */ jsxs(Alert, {
6048
- severity: "warning",
6049
- children: [
6050
- "Rascunho aplicado: as consultas desta página estão usando o modelo editado, não o registrado em ",
6051
- /* @__PURE__ */ jsx("code", { children: "src/dashboard/models" }),
6052
- ".",
6053
- capabilities?.saveModel ? " Use \"Salvar no arquivo\" quando terminar." : " Copie o código para o arquivo quando terminar."
6054
- ]
6055
- }),
6056
- actionError && /* @__PURE__ */ jsx(Alert, {
6057
- severity: "error",
6058
- sx: {
6059
- fontFamily: "ui-monospace, SFMono-Regular, Menlo, Consolas, monospace",
6060
- fontSize: 12
6061
- },
6062
- children: actionError
6063
- }),
6064
- !!validationErrors.length && /* @__PURE__ */ jsxs(Alert, {
6065
- severity: "error",
6066
- children: [
6067
- "O banco recusou ",
6068
- validationErrors.length,
6069
- " pedaço(s) do modelo — veja os campos marcados. O rascunho não foi aplicado.",
6070
- validation?.errors.model && /* @__PURE__ */ jsx("div", { children: validation.errors.model })
6071
- ]
6072
- })
6073
- ]
6074
- }),
6075
- /* @__PURE__ */ jsx(Box, {
6076
- sx: {
6077
- flex: 1,
6078
- minHeight: 0,
6079
- borderTop: 1,
6080
- borderColor: "divider"
6081
- },
6082
- children: /* @__PURE__ */ jsx(ModelDiagram, {
6083
- editor,
6084
- setEditor,
6085
- columns,
6086
- errors: {
6087
- ...columnErrors,
6088
- ...validation?.errors
6240
+ children: [/* @__PURE__ */ jsxs(Box, {
6241
+ sx: {
6242
+ display: "flex",
6243
+ flexDirection: "column",
6244
+ height: "100%",
6245
+ minHeight: 0
6246
+ },
6247
+ children: [
6248
+ /* @__PURE__ */ jsxs(Box, {
6249
+ sx: {
6250
+ px: 1.5,
6251
+ "& .MuiAlert-root": {
6252
+ my: .5,
6253
+ py: 0
6254
+ }
6255
+ },
6256
+ children: [
6257
+ draft && /* @__PURE__ */ jsxs(Alert, {
6258
+ severity: "warning",
6259
+ children: [
6260
+ "Rascunho aplicado: as consultas desta página estão usando o modelo editado, não o registrado em ",
6261
+ /* @__PURE__ */ jsx("code", { children: "src/dashboard/models" }),
6262
+ ".",
6263
+ capabilities?.saveModel ? " Use \"Salvar no arquivo\" quando terminar." : " Copie o código para o arquivo quando terminar."
6264
+ ]
6265
+ }),
6266
+ actionError && /* @__PURE__ */ jsx(Alert, {
6267
+ severity: "error",
6268
+ sx: {
6269
+ fontFamily: "ui-monospace, SFMono-Regular, Menlo, Consolas, monospace",
6270
+ fontSize: 12
6089
6271
  },
6090
- warnings: validation?.warnings ?? {},
6091
- loadingColumns: busy === "columns",
6092
- onLoadColumns: loadColumns,
6093
- onTry,
6094
- usage
6272
+ children: actionError
6273
+ }),
6274
+ !!validationErrors.length && /* @__PURE__ */ jsxs(Alert, {
6275
+ severity: "error",
6276
+ children: [
6277
+ "O banco recusou ",
6278
+ validationErrors.length,
6279
+ " pedaço(s) do modelo — veja os campos marcados. O rascunho não foi aplicado.",
6280
+ validation?.errors.model && /* @__PURE__ */ jsx("div", { children: validation.errors.model })
6281
+ ]
6095
6282
  })
6096
- }),
6097
- /* @__PURE__ */ jsxs(Box, {
6098
- sx: {
6099
- borderTop: 1,
6100
- borderColor: "divider",
6101
- p: 1,
6102
- display: "flex",
6103
- alignItems: "center",
6104
- gap: 1,
6105
- flexWrap: "wrap"
6283
+ ]
6284
+ }),
6285
+ /* @__PURE__ */ jsx(Box, {
6286
+ sx: {
6287
+ flex: 1,
6288
+ minHeight: 0,
6289
+ borderTop: 1,
6290
+ borderColor: "divider"
6291
+ },
6292
+ children: /* @__PURE__ */ jsx(ModelDiagram, {
6293
+ editor,
6294
+ setEditor,
6295
+ columns,
6296
+ errors: {
6297
+ ...columnErrors,
6298
+ ...validation?.errors
6106
6299
  },
6107
- children: [
6108
- errors.length ? /* @__PURE__ */ jsx(Tooltip, {
6109
- title: /* @__PURE__ */ jsx(Box, {
6110
- sx: { whiteSpace: "pre-line" },
6111
- children: errors.join("\n")
6112
- }),
6113
- children: /* @__PURE__ */ jsx(Chip, {
6114
- color: "error",
6115
- size: "small",
6116
- label: `${errors.length} erro(s): ${errors[0]}`
6117
- })
6118
- }) : validation && !validationErrors.length ? /* @__PURE__ */ jsx(Chip, {
6119
- color: "success",
6120
- size: "small",
6121
- label: "SQL validado no banco"
6122
- }) : /* @__PURE__ */ jsx(Chip, {
6123
- color: "success",
6124
- size: "small",
6125
- variant: "outlined",
6126
- label: "modelo válido"
6300
+ warnings: validation?.warnings ?? {},
6301
+ loadingColumns: busy === "columns",
6302
+ onLoadColumns: loadColumns,
6303
+ onTry,
6304
+ usage
6305
+ })
6306
+ }),
6307
+ /* @__PURE__ */ jsxs(Box, {
6308
+ sx: {
6309
+ borderTop: 1,
6310
+ borderColor: "divider",
6311
+ p: 1,
6312
+ display: "flex",
6313
+ alignItems: "center",
6314
+ gap: 1,
6315
+ flexWrap: "wrap"
6316
+ },
6317
+ children: [
6318
+ errors.length ? /* @__PURE__ */ jsx(Tooltip, {
6319
+ title: /* @__PURE__ */ jsx(Box, {
6320
+ sx: { whiteSpace: "pre-line" },
6321
+ children: errors.join("\n")
6127
6322
  }),
6128
- !!removed.length && /* @__PURE__ */ jsx(Chip, {
6323
+ children: /* @__PURE__ */ jsx(Chip, {
6324
+ color: "error",
6129
6325
  size: "small",
6130
- color: "warning",
6131
- label: `removidos: ${removed.join(", ")}`
6132
- }),
6133
- /* @__PURE__ */ jsxs(Box, {
6134
- sx: {
6135
- ml: "auto",
6136
- display: "flex",
6137
- gap: 1,
6138
- flexWrap: "wrap",
6139
- alignItems: "center"
6140
- },
6141
- children: [
6142
- /* @__PURE__ */ jsx(AutoApplySwitch, { applying: busy === "apply" }),
6143
- /* @__PURE__ */ jsx(Button, {
6144
- size: "small",
6145
- onClick: () => setShowCode(true),
6146
- children: "Ver código"
6147
- }),
6148
- /* @__PURE__ */ jsx(Button, {
6149
- size: "small",
6150
- onClick: (e) => copyText(toModelCode(edited), e.currentTarget),
6151
- children: "Copiar TS"
6152
- }),
6153
- /* @__PURE__ */ jsx(Button, {
6154
- size: "small",
6155
- disabled: !!errors.length || !!busy,
6156
- onClick: () => act("validate", async () => {
6157
- await validateSql();
6158
- }),
6159
- title: "Executa cada pedaço do modelo no banco com poucas chaves",
6160
- children: busy === "validate" ? "Validando…" : "Validar SQL"
6161
- }),
6162
- /* @__PURE__ */ jsx(ConfirmButton, {
6163
- size: "small",
6164
- disabled: !dirty,
6165
- onConfirm: () => setEditor(toEditor(reference)),
6166
- title: "Desfaz as edições ainda não aplicadas",
6167
- confirmTitle: "Desfazer as edições?",
6168
- confirmText: "As edições do modelo ainda não aplicadas na página serão perdidas; o editor volta ao modelo que a página usa.",
6169
- confirmLabel: "Desfazer",
6170
- children: "Desfazer"
6171
- }),
6172
- /* @__PURE__ */ jsx(Button, {
6173
- size: "small",
6174
- color: "warning",
6175
- disabled: !draft,
6176
- onClick: () => setDraft(null),
6177
- title: "Volta a usar o modelo registrado no servidor",
6178
- children: "Descartar rascunho"
6179
- }),
6180
- capabilities?.saveModel && /* @__PURE__ */ jsx(Button, {
6181
- size: "small",
6182
- variant: "outlined",
6183
- disabled: !differsFromOriginal || !!errors.length || !!busy,
6184
- onClick: previewSave,
6185
- title: `Reescreve src/dashboard/models/${original.name}.ts`,
6186
- children: busy === "save" ? "Gerando…" : "Salvar no arquivo"
6187
- }),
6188
- !autoApply && /* @__PURE__ */ jsx(Button, {
6189
- size: "small",
6190
- variant: "contained",
6191
- disabled: !dirty || !!errors.length || !!busy,
6192
- onClick: apply,
6193
- children: busy === "apply" ? "Validando…" : "Aplicar na página"
6194
- })
6195
- ]
6326
+ label: `${errors.length} erro(s): ${errors[0]}`
6196
6327
  })
6197
- ]
6198
- })
6199
- ]
6200
- }),
6201
- /* @__PURE__ */ jsxs(Dialog, {
6202
- open: showCode,
6203
- onClose: () => setShowCode(false),
6204
- maxWidth: "lg",
6205
- fullWidth: true,
6206
- children: [
6207
- /* @__PURE__ */ jsx(DialogTitle, { children: "Código do modelo" }),
6208
- /* @__PURE__ */ jsx(DialogContent, { children: /* @__PURE__ */ jsx(CodeBlock, {
6209
- code: toModelCode(edited),
6210
- maxHeight: 600
6211
- }) }),
6212
- /* @__PURE__ */ jsx(DialogActions, { children: /* @__PURE__ */ jsx(Button, {
6213
- onClick: () => setShowCode(false),
6214
- children: "Fechar"
6215
- }) })
6216
- ]
6217
- }),
6218
- /* @__PURE__ */ jsxs(Dialog, {
6219
- open: !!save,
6220
- onClose: () => setSave(null),
6221
- maxWidth: "lg",
6222
- fullWidth: true,
6223
- children: [
6224
- /* @__PURE__ */ jsx(DialogTitle, { children: "Salvar no arquivo" }),
6225
- /* @__PURE__ */ jsxs(DialogContent, { children: [
6226
- /* @__PURE__ */ jsx(Typography, {
6227
- sx: {
6228
- fontFamily: MONO,
6229
- fontSize: 12,
6230
- mb: 1
6231
- },
6232
- children: save?.path
6328
+ }) : validation && !validationErrors.length ? /* @__PURE__ */ jsx(Chip, {
6329
+ color: "success",
6330
+ size: "small",
6331
+ label: "SQL validado no banco"
6332
+ }) : /* @__PURE__ */ jsx(Chip, {
6333
+ color: "success",
6334
+ size: "small",
6335
+ variant: "outlined",
6336
+ label: "modelo válido"
6233
6337
  }),
6234
- save?.warnings.map((warning) => /* @__PURE__ */ jsx(Alert, {
6235
- severity: "warning",
6236
- sx: { mb: 1 },
6237
- children: warning
6238
- }, warning)),
6239
- save && /* @__PURE__ */ jsx(FileDiff, { lines: lineDiff(save.previous, save.content) }),
6240
- /* @__PURE__ */ jsx(Typography, {
6338
+ !!removed.length && /* @__PURE__ */ jsx(Chip, {
6339
+ size: "small",
6340
+ color: "warning",
6341
+ label: `removidos: ${removed.join(", ")}`
6342
+ }),
6343
+ /* @__PURE__ */ jsxs(Box, {
6241
6344
  sx: {
6242
- fontSize: 12,
6243
- color: "text.secondary",
6244
- mt: 1
6345
+ ml: "auto",
6346
+ display: "flex",
6347
+ gap: 1,
6348
+ flexWrap: "wrap",
6349
+ alignItems: "center"
6245
6350
  },
6246
- children: "O Next recarrega o modelo sozinho; o rascunho é descartado. O lint-staged formata o arquivo no commit."
6351
+ children: [
6352
+ /* @__PURE__ */ jsx(AutoApplySwitch, { applying: busy === "apply" }),
6353
+ /* @__PURE__ */ jsx(Button, {
6354
+ size: "small",
6355
+ disabled: !!errors.length || !!busy,
6356
+ onClick: () => act("validate", async () => {
6357
+ await validateSql();
6358
+ }),
6359
+ title: "Executa cada pedaço do modelo no banco com poucas chaves",
6360
+ children: busy === "validate" ? "Validando…" : "Validar SQL"
6361
+ }),
6362
+ !autoApply && /* @__PURE__ */ jsx(ConfirmButton, {
6363
+ size: "small",
6364
+ disabled: !dirty,
6365
+ onConfirm: () => setEditor(toEditor(reference)),
6366
+ title: "Desfaz as edições ainda não aplicadas",
6367
+ confirmTitle: "Desfazer as edições?",
6368
+ confirmText: "As edições do modelo ainda não aplicadas na página serão perdidas; o editor volta ao modelo que a página usa.",
6369
+ confirmLabel: "Desfazer",
6370
+ children: "Desfazer"
6371
+ }),
6372
+ /* @__PURE__ */ jsx(ConfirmButton, {
6373
+ size: "small",
6374
+ color: "warning",
6375
+ disabled: !draft,
6376
+ onConfirm: () => setDraft(null),
6377
+ title: "Volta a usar o modelo registrado no servidor",
6378
+ confirmTitle: "Descartar o rascunho?",
6379
+ confirmText: "A página volta a usar o modelo registrado no servidor; as edições do rascunho serão perdidas.",
6380
+ confirmLabel: "Descartar",
6381
+ children: "Descartar rascunho"
6382
+ }),
6383
+ capabilities?.saveModel && /* @__PURE__ */ jsx(Button, {
6384
+ size: "small",
6385
+ variant: "outlined",
6386
+ disabled: !differsFromOriginal || !!errors.length || !!busy,
6387
+ onClick: previewSave,
6388
+ title: `Reescreve src/dashboard/models/${original.name}.ts`,
6389
+ children: busy === "save" ? "Gerando…" : "Salvar no arquivo"
6390
+ }),
6391
+ !autoApply && /* @__PURE__ */ jsx(Button, {
6392
+ size: "small",
6393
+ variant: "contained",
6394
+ disabled: !dirty || !!errors.length || !!busy,
6395
+ onClick: apply,
6396
+ children: busy === "apply" ? "Validando…" : "Aplicar na página"
6397
+ })
6398
+ ]
6247
6399
  })
6248
- ] }),
6249
- /* @__PURE__ */ jsxs(DialogActions, { children: [/* @__PURE__ */ jsx(Button, {
6250
- onClick: () => setSave(null),
6251
- children: "Cancelar"
6252
- }), /* @__PURE__ */ jsx(Button, {
6253
- variant: "contained",
6254
- disabled: !save || save.previous === save.content || !!busy,
6255
- onClick: writeSave,
6256
- children: "Gravar"
6257
- })] })
6258
- ]
6259
- })
6260
- ]
6400
+ ]
6401
+ })
6402
+ ]
6403
+ }), /* @__PURE__ */ jsxs(Dialog, {
6404
+ open: !!save,
6405
+ onClose: () => setSave(null),
6406
+ maxWidth: "lg",
6407
+ fullWidth: true,
6408
+ children: [
6409
+ /* @__PURE__ */ jsx(DialogTitle, { children: "Salvar no arquivo" }),
6410
+ /* @__PURE__ */ jsxs(DialogContent, { children: [
6411
+ /* @__PURE__ */ jsx(Typography, {
6412
+ sx: {
6413
+ fontFamily: MONO,
6414
+ fontSize: 12,
6415
+ mb: 1
6416
+ },
6417
+ children: save?.path
6418
+ }),
6419
+ save?.warnings.map((warning) => /* @__PURE__ */ jsx(Alert, {
6420
+ severity: "warning",
6421
+ sx: { mb: 1 },
6422
+ children: warning
6423
+ }, warning)),
6424
+ save && /* @__PURE__ */ jsx(FileDiff, { lines: lineDiff(save.previous, save.content) }),
6425
+ /* @__PURE__ */ jsx(Typography, {
6426
+ sx: {
6427
+ fontSize: 12,
6428
+ color: "text.secondary",
6429
+ mt: 1
6430
+ },
6431
+ children: "O Next recarrega o modelo sozinho; o rascunho é descartado. O lint-staged formata o arquivo no commit."
6432
+ })
6433
+ ] }),
6434
+ /* @__PURE__ */ jsxs(DialogActions, { children: [/* @__PURE__ */ jsx(Button, {
6435
+ onClick: () => setSave(null),
6436
+ children: "Cancelar"
6437
+ }), /* @__PURE__ */ jsx(Button, {
6438
+ variant: "contained",
6439
+ disabled: !save || save.previous === save.content || !!busy,
6440
+ onClick: writeSave,
6441
+ children: "Gravar"
6442
+ })] })
6443
+ ]
6444
+ })]
6261
6445
  });
6262
6446
  }
6263
6447
  //#endregion
@@ -8197,4 +8381,4 @@ function ToggleButton$1({ draft, loading, problems, inspecting, onOpen }) {
8197
8381
  //#endregion
8198
8382
  export { DashboardDevtools as default };
8199
8383
 
8200
- //# sourceMappingURL=DashboardDevtools-CSRt9lib.js.map
8384
+ //# sourceMappingURL=DashboardDevtools-I00Iz0Z8.js.map