@bluemarble/bi 0.6.1 → 0.6.2
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-xhkgdAkr.js → DashboardDevtools-BT9mJrmJ.js} +460 -384
- package/dist/DashboardDevtools-BT9mJrmJ.js.map +1 -0
- package/dist/{ModelDictionary-B26oLtPH.js → ModelDictionary-BlDeDyAE.js} +2 -2
- package/dist/{ModelDictionary-B26oLtPH.js.map → ModelDictionary-BlDeDyAE.js.map} +1 -1
- package/dist/client/index.js +1 -1
- package/package.json +1 -1
- package/dist/DashboardDevtools-xhkgdAkr.js.map +0 -1
|
@@ -1,11 +1,46 @@
|
|
|
1
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";
|
|
2
2
|
import { n as diffRows } from "./compare-DloZhg1T.js";
|
|
3
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-DAFeHIuP.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-
|
|
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, Tab, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, TableSortLabel, Tabs, TextField, ThemeProvider, ToggleButton, ToggleButtonGroup, Tooltip, Typography, createTheme } from "@mui/material";
|
|
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-BlDeDyAE.js";
|
|
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";
|
|
8
8
|
import { createPortal } from "react-dom";
|
|
9
|
+
//#region src/devtools/autoApply.ts
|
|
10
|
+
/**
|
|
11
|
+
* Preferência "Aplicar automaticamente" dos editores (Layout e Modelo): ligada, cada edição válida
|
|
12
|
+
* vai para a página sozinha, como se clicasse em "Aplicar na página". Uma só para os dois editores,
|
|
13
|
+
* guardada no navegador.
|
|
14
|
+
*/
|
|
15
|
+
const KEY = "bm-dashboard-devtools:auto-apply";
|
|
16
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
17
|
+
function read() {
|
|
18
|
+
try {
|
|
19
|
+
return localStorage.getItem(KEY) === "1";
|
|
20
|
+
} catch {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
let enabled = read();
|
|
25
|
+
function setAutoApply(next) {
|
|
26
|
+
enabled = next;
|
|
27
|
+
try {
|
|
28
|
+
localStorage.setItem(KEY, next ? "1" : "0");
|
|
29
|
+
} catch {}
|
|
30
|
+
for (const listener of listeners) listener();
|
|
31
|
+
}
|
|
32
|
+
const subscribe = (listener) => {
|
|
33
|
+
listeners.add(listener);
|
|
34
|
+
return () => listeners.delete(listener);
|
|
35
|
+
};
|
|
36
|
+
const getSnapshot = () => enabled;
|
|
37
|
+
const useAutoApply = () => useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
38
|
+
/** Espera entre a última edição e o aplicar automático (digitação não aplica a cada tecla). */
|
|
39
|
+
const AUTO_APPLY_DELAY = {
|
|
40
|
+
layout: 500,
|
|
41
|
+
model: 1200
|
|
42
|
+
};
|
|
43
|
+
//#endregion
|
|
9
44
|
//#region src/devtools/sqlHighlight.tsx
|
|
10
45
|
const KEYWORDS$1 = new Set(`SELECT FROM WHERE AND OR NOT IN IS NULL JOIN LEFT RIGHT INNER OUTER CROSS ON AS GROUP BY ORDER
|
|
11
46
|
HAVING LIMIT OFFSET UNION ALL DISTINCT CASE WHEN THEN ELSE END WITH ASC DESC BETWEEN LIKE EXISTS
|
|
@@ -484,6 +519,67 @@ function RowDiffTable({ diffs, expectedLabel = "esperado", actualLabel = "atual"
|
|
|
484
519
|
})
|
|
485
520
|
});
|
|
486
521
|
}
|
|
522
|
+
/**
|
|
523
|
+
* Botão que pede confirmação antes de agir (ações que perdem trabalho, como desfazer edições).
|
|
524
|
+
* Diálogo do MUI, e não `confirm()`: no modo janela separada, ele abre no popup.
|
|
525
|
+
*/
|
|
526
|
+
function ConfirmButton({ confirmTitle, confirmText, confirmLabel = "Confirmar", onConfirm, ...props }) {
|
|
527
|
+
const [open, setOpen] = useState(false);
|
|
528
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Button, {
|
|
529
|
+
...props,
|
|
530
|
+
onClick: () => setOpen(true)
|
|
531
|
+
}), /* @__PURE__ */ jsxs(Dialog, {
|
|
532
|
+
open,
|
|
533
|
+
onClose: () => setOpen(false),
|
|
534
|
+
maxWidth: "xs",
|
|
535
|
+
fullWidth: true,
|
|
536
|
+
children: [
|
|
537
|
+
/* @__PURE__ */ jsx(DialogTitle, {
|
|
538
|
+
sx: { fontSize: 15 },
|
|
539
|
+
children: confirmTitle
|
|
540
|
+
}),
|
|
541
|
+
/* @__PURE__ */ jsx(DialogContent, { children: /* @__PURE__ */ jsx(Typography, {
|
|
542
|
+
sx: { fontSize: 13 },
|
|
543
|
+
children: confirmText
|
|
544
|
+
}) }),
|
|
545
|
+
/* @__PURE__ */ jsxs(DialogActions, { children: [/* @__PURE__ */ jsx(Button, {
|
|
546
|
+
onClick: () => setOpen(false),
|
|
547
|
+
children: "Cancelar"
|
|
548
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
549
|
+
variant: "contained",
|
|
550
|
+
color: "warning",
|
|
551
|
+
autoFocus: true,
|
|
552
|
+
onClick: () => {
|
|
553
|
+
setOpen(false);
|
|
554
|
+
onConfirm();
|
|
555
|
+
},
|
|
556
|
+
children: confirmLabel
|
|
557
|
+
})] })
|
|
558
|
+
]
|
|
559
|
+
})] });
|
|
560
|
+
}
|
|
561
|
+
/** Liga/desliga o "Aplicar automaticamente" (compartilhado entre os editores). */
|
|
562
|
+
function AutoApplySwitch({ applying }) {
|
|
563
|
+
const enabled = useAutoApply();
|
|
564
|
+
return /* @__PURE__ */ jsx(Tooltip, {
|
|
565
|
+
title: "Cada edição válida vai para a página sozinha (como “Aplicar na página”). Desligado, aparece o botão Aplicar.",
|
|
566
|
+
children: /* @__PURE__ */ jsx(FormControlLabel, {
|
|
567
|
+
sx: {
|
|
568
|
+
m: 0,
|
|
569
|
+
mr: .5
|
|
570
|
+
},
|
|
571
|
+
control: /* @__PURE__ */ jsx(Switch, {
|
|
572
|
+
size: "small",
|
|
573
|
+
checked: enabled,
|
|
574
|
+
onChange: (e) => setAutoApply(e.target.checked)
|
|
575
|
+
}),
|
|
576
|
+
label: /* @__PURE__ */ jsxs(Typography, {
|
|
577
|
+
sx: { fontSize: 12 },
|
|
578
|
+
children: ["Aplicar automaticamente", enabled && applying ? " · aplicando…" : ""]
|
|
579
|
+
})
|
|
580
|
+
})
|
|
581
|
+
});
|
|
582
|
+
}
|
|
487
583
|
//#endregion
|
|
488
584
|
//#region src/devtools/FiltersPanel.tsx
|
|
489
585
|
function parseFilters(text) {
|
|
@@ -1003,6 +1099,25 @@ function LayoutPanel({ devtools, model, capabilities, picked, onHover }) {
|
|
|
1003
1099
|
setSelection(parsed.item);
|
|
1004
1100
|
}, [picked]);
|
|
1005
1101
|
const errors = useMemo(() => editing ? validateLayout(editing, chartTypes) : [], [editing, chartTypes]);
|
|
1102
|
+
/** Manda o editor para a página (vira rascunho e a página re-renderiza com ele). */
|
|
1103
|
+
const applyEditing = () => {
|
|
1104
|
+
if (!entry || !editing || validateLayout(editing, chartTypes).length) return;
|
|
1105
|
+
devtools.store.expectRefetch();
|
|
1106
|
+
layouts.setPending(entry.registered.id, null);
|
|
1107
|
+
layouts.setDraft(entry.registered.id, editing);
|
|
1108
|
+
};
|
|
1109
|
+
const autoApply = useAutoApply();
|
|
1110
|
+
const editingKey = canonicalJson(editing);
|
|
1111
|
+
useEffect(() => {
|
|
1112
|
+
if (!autoApply || editingKey === referenceKey || errors.length) return;
|
|
1113
|
+
const timer = setTimeout(applyEditing, AUTO_APPLY_DELAY.layout);
|
|
1114
|
+
return () => clearTimeout(timer);
|
|
1115
|
+
}, [
|
|
1116
|
+
autoApply,
|
|
1117
|
+
editingKey,
|
|
1118
|
+
referenceKey,
|
|
1119
|
+
errors.length
|
|
1120
|
+
]);
|
|
1006
1121
|
const warnings = useMemo(() => {
|
|
1007
1122
|
if (!editing || errors.length) return [];
|
|
1008
1123
|
const list = layoutModelWarnings(editing, model, chartTypes);
|
|
@@ -1044,12 +1159,7 @@ function LayoutPanel({ devtools, model, capabilities, picked, onHover }) {
|
|
|
1044
1159
|
setEditing(next);
|
|
1045
1160
|
setSave(null);
|
|
1046
1161
|
};
|
|
1047
|
-
const apply =
|
|
1048
|
-
if (validateLayout(editing, chartTypes).length) return;
|
|
1049
|
-
devtools.store.expectRefetch();
|
|
1050
|
-
layouts.setPending(entry.registered.id, null);
|
|
1051
|
-
layouts.setDraft(entry.registered.id, editing);
|
|
1052
|
-
};
|
|
1162
|
+
const apply = applyEditing;
|
|
1053
1163
|
const setCharts = (next) => update({
|
|
1054
1164
|
...editing,
|
|
1055
1165
|
charts: next
|
|
@@ -1420,23 +1530,33 @@ function LayoutPanel({ devtools, model, capabilities, picked, onHover }) {
|
|
|
1420
1530
|
borderColor: "divider"
|
|
1421
1531
|
},
|
|
1422
1532
|
children: [
|
|
1423
|
-
|
|
1533
|
+
/* @__PURE__ */ jsxs(Box, {
|
|
1424
1534
|
sx: {
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1535
|
+
mr: "auto",
|
|
1536
|
+
display: "flex",
|
|
1537
|
+
alignItems: "center",
|
|
1538
|
+
gap: 1
|
|
1428
1539
|
},
|
|
1429
|
-
children:
|
|
1540
|
+
children: [/* @__PURE__ */ jsx(AutoApplySwitch, { applying: dirty && !errors.length }), dirty && (!autoApply || !!errors.length) && /* @__PURE__ */ jsx(Typography, {
|
|
1541
|
+
sx: {
|
|
1542
|
+
fontSize: 12,
|
|
1543
|
+
color: "warning.main"
|
|
1544
|
+
},
|
|
1545
|
+
children: errors.length ? "Edições com erro, não aplicadas" : "Edições não aplicadas"
|
|
1546
|
+
})]
|
|
1430
1547
|
}),
|
|
1431
1548
|
/* @__PURE__ */ jsx(CopyButton, {
|
|
1432
1549
|
text: layoutFileContent(editing),
|
|
1433
1550
|
label: "Copiar JSON"
|
|
1434
1551
|
}),
|
|
1435
|
-
/* @__PURE__ */ jsx(
|
|
1552
|
+
/* @__PURE__ */ jsx(ConfirmButton, {
|
|
1436
1553
|
size: "small",
|
|
1437
1554
|
disabled: !dirty,
|
|
1438
|
-
|
|
1555
|
+
onConfirm: () => setEditing(reference),
|
|
1439
1556
|
title: "Desfaz as edições ainda não aplicadas",
|
|
1557
|
+
confirmTitle: "Desfazer as edições?",
|
|
1558
|
+
confirmText: "As edições ainda não aplicadas na página serão perdidas; o editor volta ao que a página mostra.",
|
|
1559
|
+
confirmLabel: "Desfazer",
|
|
1440
1560
|
children: "Desfazer"
|
|
1441
1561
|
}),
|
|
1442
1562
|
/* @__PURE__ */ jsx(Button, {
|
|
@@ -1460,7 +1580,7 @@ function LayoutPanel({ devtools, model, capabilities, picked, onHover }) {
|
|
|
1460
1580
|
title: `Reescreve ${entry.registered.id}.json com o que está no editor`,
|
|
1461
1581
|
children: busy ? "Gerando…" : "Salvar no arquivo"
|
|
1462
1582
|
}),
|
|
1463
|
-
/* @__PURE__ */ jsx(Button, {
|
|
1583
|
+
!autoApply && /* @__PURE__ */ jsx(Button, {
|
|
1464
1584
|
size: "small",
|
|
1465
1585
|
variant: "contained",
|
|
1466
1586
|
disabled: !dirty || !!errors.length,
|
|
@@ -4153,7 +4273,6 @@ function ModelDiagram({ editor, setEditor, columns, errors, warnings, loadingCol
|
|
|
4153
4273
|
});
|
|
4154
4274
|
const [selection, setSelection] = useState(null);
|
|
4155
4275
|
const [panel, setPanel] = useState(loadPanel);
|
|
4156
|
-
const [picking, setPicking] = useState(null);
|
|
4157
4276
|
useEffect(() => {
|
|
4158
4277
|
try {
|
|
4159
4278
|
localStorage.setItem(PANEL_KEY, JSON.stringify(panel));
|
|
@@ -4567,376 +4686,305 @@ function ModelDiagram({ editor, setEditor, columns, errors, warnings, loadingCol
|
|
|
4567
4686
|
height: "100%",
|
|
4568
4687
|
minHeight: 0
|
|
4569
4688
|
},
|
|
4570
|
-
children: [
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
|
|
4599
|
-
|
|
4600
|
-
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
style: {
|
|
4604
|
-
position: "absolute",
|
|
4605
|
-
overflow: "visible",
|
|
4606
|
-
pointerEvents: "none"
|
|
4607
|
-
},
|
|
4608
|
-
"aria-hidden": true,
|
|
4609
|
-
children: [lines.map((line) => /* @__PURE__ */ jsx(RelationshipLine, {
|
|
4610
|
-
line,
|
|
4611
|
-
hovered: hoveredEdge === line.id,
|
|
4612
|
-
onHover: (hovered) => setHoveredEdge(hovered ? line.id : null)
|
|
4613
|
-
}, line.id)), linkPreview && /* @__PURE__ */ jsx("path", {
|
|
4614
|
-
d: linkPreview,
|
|
4615
|
-
fill: "none",
|
|
4616
|
-
stroke: "#F58220",
|
|
4617
|
-
strokeWidth: 2,
|
|
4618
|
-
strokeDasharray: "5 4"
|
|
4619
|
-
})]
|
|
4620
|
-
}), nodes.map((node) => /* @__PURE__ */ jsx(TableCard, {
|
|
4621
|
-
node,
|
|
4622
|
-
position: placed(node),
|
|
4623
|
-
size: sizeOf(node),
|
|
4624
|
-
collapsed: !!collapsed[node.id],
|
|
4625
|
-
selected: !!isSelected(node),
|
|
4626
|
-
linking: !!linking && linking.node.id !== node.id,
|
|
4627
|
-
selectedField: selection?.kind === "dimension" || selection?.kind === "measure" ? selection.uid : null,
|
|
4628
|
-
onToggle: () => setCollapsed((current) => ({
|
|
4629
|
-
...current,
|
|
4630
|
-
[node.id]: !current[node.id]
|
|
4631
|
-
})),
|
|
4632
|
-
onScroll: (top) => setScrolls((current) => ({
|
|
4633
|
-
...current,
|
|
4634
|
-
[node.id]: top
|
|
4635
|
-
})),
|
|
4636
|
-
onHeaderDown: (event) => startMove(event, node),
|
|
4637
|
-
onResizeDown: (event, edges) => startResize(event, node, edges),
|
|
4638
|
-
onResizeReset: () => resetSize(node),
|
|
4639
|
-
onColumnDown: (event, column) => startLink(event, node, column),
|
|
4640
|
-
onFieldClick: (item) => setSelection({
|
|
4641
|
-
kind: item.kind,
|
|
4642
|
-
uid: item.uid
|
|
4643
|
-
}),
|
|
4644
|
-
onAddField: (kind, column) => addField(kind, node.name, column)
|
|
4645
|
-
}, node.id))]
|
|
4646
|
-
}),
|
|
4647
|
-
/* @__PURE__ */ jsxs(Box, {
|
|
4648
|
-
onMouseDown: (event) => event.stopPropagation(),
|
|
4649
|
-
sx: {
|
|
4650
|
-
position: "absolute",
|
|
4651
|
-
top: 8,
|
|
4652
|
-
left: 8,
|
|
4653
|
-
right: 8,
|
|
4654
|
-
display: "flex",
|
|
4655
|
-
gap: .75,
|
|
4656
|
-
flexWrap: "wrap",
|
|
4657
|
-
alignItems: "center",
|
|
4658
|
-
pointerEvents: "none",
|
|
4659
|
-
"& > *": { pointerEvents: "auto" }
|
|
4660
|
-
},
|
|
4661
|
-
children: [
|
|
4662
|
-
/* @__PURE__ */ jsx(Button, {
|
|
4663
|
-
size: "small",
|
|
4664
|
-
variant: "outlined",
|
|
4665
|
-
onClick: addTable,
|
|
4666
|
-
children: "+ Tabela"
|
|
4667
|
-
}),
|
|
4668
|
-
/* @__PURE__ */ jsx(Button, {
|
|
4669
|
-
size: "small",
|
|
4670
|
-
variant: "outlined",
|
|
4671
|
-
disabled: !editor.tables.length,
|
|
4672
|
-
onClick: () => setPicking(editor.tables[0]?.name ?? null),
|
|
4673
|
-
title: "Escolher a tabela e marcar as colunas que viram dimensão",
|
|
4674
|
-
children: "+ Dimensões"
|
|
4675
|
-
}),
|
|
4676
|
-
/* @__PURE__ */ jsx(Button, {
|
|
4677
|
-
size: "small",
|
|
4678
|
-
onClick: onLoadColumns,
|
|
4679
|
-
disabled: loadingColumns,
|
|
4680
|
-
title: "Lê uma linha de cada tabela para listar as colunas",
|
|
4681
|
-
sx: { bgcolor: "#1b1e23" },
|
|
4682
|
-
children: loadingColumns ? "Lendo colunas…" : "Recarregar colunas"
|
|
4683
|
-
}),
|
|
4684
|
-
/* @__PURE__ */ jsxs(Box, {
|
|
4685
|
-
sx: {
|
|
4686
|
-
ml: "auto",
|
|
4687
|
-
display: "flex",
|
|
4688
|
-
gap: .5,
|
|
4689
|
-
alignItems: "center"
|
|
4690
|
-
},
|
|
4691
|
-
children: [
|
|
4692
|
-
/* @__PURE__ */ jsx(Button, {
|
|
4693
|
-
size: "small",
|
|
4694
|
-
onClick: () => {
|
|
4695
|
-
const layout = autoLayout(nodes, sizes);
|
|
4696
|
-
setPositions((current) => Object.fromEntries(Object.entries(layout).map(([id, point]) => [id, {
|
|
4697
|
-
...current[id],
|
|
4698
|
-
...point
|
|
4699
|
-
}])));
|
|
4700
|
-
fitToScreen(layout);
|
|
4701
|
-
},
|
|
4702
|
-
title: "Dimensões em cima, fatos embaixo (troca as posições salvas)",
|
|
4703
|
-
sx: { bgcolor: "#1b1e23" },
|
|
4704
|
-
children: "Organizar"
|
|
4705
|
-
}),
|
|
4706
|
-
/* @__PURE__ */ jsx(Button, {
|
|
4707
|
-
size: "small",
|
|
4708
|
-
onClick: () => fitToScreen(),
|
|
4709
|
-
sx: { bgcolor: "#1b1e23" },
|
|
4710
|
-
children: "Ajustar à tela"
|
|
4711
|
-
}),
|
|
4712
|
-
/* @__PURE__ */ jsx(IconButton, {
|
|
4713
|
-
size: "small",
|
|
4714
|
-
"aria-label": "Diminuir zoom",
|
|
4715
|
-
onClick: () => setView((current) => ({
|
|
4716
|
-
...current,
|
|
4717
|
-
zoom: Math.max(.3, current.zoom - .1)
|
|
4718
|
-
})),
|
|
4719
|
-
children: "−"
|
|
4720
|
-
}),
|
|
4721
|
-
/* @__PURE__ */ jsxs(Typography, {
|
|
4722
|
-
sx: {
|
|
4723
|
-
fontSize: 11,
|
|
4724
|
-
fontFamily: MONO,
|
|
4725
|
-
width: 36,
|
|
4726
|
-
textAlign: "center"
|
|
4727
|
-
},
|
|
4728
|
-
children: [Math.round(view.zoom * 100), "%"]
|
|
4729
|
-
}),
|
|
4730
|
-
/* @__PURE__ */ jsx(IconButton, {
|
|
4731
|
-
size: "small",
|
|
4732
|
-
"aria-label": "Aumentar zoom",
|
|
4733
|
-
onClick: () => setView((current) => ({
|
|
4734
|
-
...current,
|
|
4735
|
-
zoom: Math.min(2, current.zoom + .1)
|
|
4736
|
-
})),
|
|
4737
|
-
children: "+"
|
|
4738
|
-
})
|
|
4739
|
-
]
|
|
4740
|
-
})
|
|
4741
|
-
]
|
|
4742
|
-
}),
|
|
4743
|
-
!nodes.length && /* @__PURE__ */ jsx(Box, {
|
|
4744
|
-
sx: {
|
|
4745
|
-
position: "absolute",
|
|
4746
|
-
inset: 0,
|
|
4747
|
-
display: "flex",
|
|
4748
|
-
alignItems: "center",
|
|
4749
|
-
justifyContent: "center",
|
|
4750
|
-
pointerEvents: "none",
|
|
4751
|
-
color: "text.secondary",
|
|
4752
|
-
fontSize: 13,
|
|
4753
|
-
textAlign: "center",
|
|
4754
|
-
px: 4
|
|
4755
|
-
},
|
|
4756
|
-
children: "Modelo vazio. Adicione as tabelas dimensão (cadastros: navio, calendário…) e fato (lançamentos: pesagens, custos…) e arraste a coluna da fato até a chave da dimensão para relacioná-las."
|
|
4757
|
-
}),
|
|
4758
|
-
!!nodes.length && /* @__PURE__ */ jsx(Typography, {
|
|
4759
|
-
sx: {
|
|
4689
|
+
children: [/* @__PURE__ */ jsxs(Box, {
|
|
4690
|
+
ref: canvas,
|
|
4691
|
+
tabIndex: -1,
|
|
4692
|
+
onMouseDown: startPan,
|
|
4693
|
+
onMouseDownCapture: () => canvas.current?.focus({ preventScroll: true }),
|
|
4694
|
+
onKeyDown: (event) => {
|
|
4695
|
+
if ((event.key === "Delete" || event.key === "Backspace") && event.target === canvas.current) removeSelection();
|
|
4696
|
+
},
|
|
4697
|
+
onWheel,
|
|
4698
|
+
sx: {
|
|
4699
|
+
outline: "none",
|
|
4700
|
+
flex: 1,
|
|
4701
|
+
position: "relative",
|
|
4702
|
+
overflow: "hidden",
|
|
4703
|
+
cursor: "grab",
|
|
4704
|
+
bgcolor: "#15171b",
|
|
4705
|
+
backgroundImage: "radial-gradient(rgba(255,255,255,.07) 1px, transparent 1px)",
|
|
4706
|
+
backgroundSize: `${20 * view.zoom}px ${20 * view.zoom}px`,
|
|
4707
|
+
backgroundPosition: `${view.x}px ${view.y}px`
|
|
4708
|
+
},
|
|
4709
|
+
children: [
|
|
4710
|
+
/* @__PURE__ */ jsxs(Box, {
|
|
4711
|
+
sx: {
|
|
4712
|
+
position: "absolute",
|
|
4713
|
+
left: 0,
|
|
4714
|
+
top: 0,
|
|
4715
|
+
transformOrigin: "0 0",
|
|
4716
|
+
transform: `translate(${view.x}px, ${view.y}px) scale(${view.zoom})`
|
|
4717
|
+
},
|
|
4718
|
+
children: [/* @__PURE__ */ jsxs("svg", {
|
|
4719
|
+
width: 1,
|
|
4720
|
+
height: 1,
|
|
4721
|
+
style: {
|
|
4760
4722
|
position: "absolute",
|
|
4761
|
-
|
|
4762
|
-
bottom: 6,
|
|
4763
|
-
fontSize: 11,
|
|
4764
|
-
color: "text.disabled",
|
|
4723
|
+
overflow: "visible",
|
|
4765
4724
|
pointerEvents: "none"
|
|
4766
4725
|
},
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
|
|
4776
|
-
|
|
4777
|
-
|
|
4778
|
-
display: "flex",
|
|
4779
|
-
flexDirection: "column",
|
|
4780
|
-
minHeight: 0
|
|
4781
|
-
},
|
|
4782
|
-
children: [
|
|
4783
|
-
/* @__PURE__ */ jsx(Box, {
|
|
4784
|
-
onMouseDown: startPanelResize,
|
|
4785
|
-
title: "Arraste para redimensionar",
|
|
4786
|
-
sx: {
|
|
4787
|
-
position: "absolute",
|
|
4788
|
-
left: -3,
|
|
4789
|
-
top: 0,
|
|
4790
|
-
bottom: 0,
|
|
4791
|
-
width: 6,
|
|
4792
|
-
cursor: "ew-resize",
|
|
4793
|
-
zIndex: 2,
|
|
4794
|
-
"&:hover": {
|
|
4795
|
-
bgcolor: "primary.main",
|
|
4796
|
-
opacity: .4
|
|
4797
|
-
}
|
|
4798
|
-
}
|
|
4799
|
-
}),
|
|
4800
|
-
/* @__PURE__ */ jsxs(Box, {
|
|
4801
|
-
sx: {
|
|
4802
|
-
display: "flex",
|
|
4803
|
-
alignItems: "center",
|
|
4804
|
-
px: 1.5,
|
|
4805
|
-
py: .5,
|
|
4806
|
-
borderBottom: 1,
|
|
4807
|
-
borderColor: "divider"
|
|
4808
|
-
},
|
|
4809
|
-
children: [/* @__PURE__ */ jsx(Typography, {
|
|
4810
|
-
sx: {
|
|
4811
|
-
fontSize: 12,
|
|
4812
|
-
fontWeight: 700,
|
|
4813
|
-
color: "text.secondary",
|
|
4814
|
-
flex: 1
|
|
4815
|
-
},
|
|
4816
|
-
children: "Propriedades"
|
|
4817
|
-
}), /* @__PURE__ */ jsx(IconButton, {
|
|
4818
|
-
size: "small",
|
|
4819
|
-
"aria-label": "Recolher propriedades",
|
|
4820
|
-
title: "Recolher",
|
|
4821
|
-
onClick: () => setPanel((current) => ({
|
|
4822
|
-
...current,
|
|
4823
|
-
open: false
|
|
4824
|
-
})),
|
|
4825
|
-
children: "⟩"
|
|
4726
|
+
"aria-hidden": true,
|
|
4727
|
+
children: [lines.map((line) => /* @__PURE__ */ jsx(RelationshipLine, {
|
|
4728
|
+
line,
|
|
4729
|
+
hovered: hoveredEdge === line.id,
|
|
4730
|
+
onHover: (hovered) => setHoveredEdge(hovered ? line.id : null)
|
|
4731
|
+
}, line.id)), linkPreview && /* @__PURE__ */ jsx("path", {
|
|
4732
|
+
d: linkPreview,
|
|
4733
|
+
fill: "none",
|
|
4734
|
+
stroke: "#F58220",
|
|
4735
|
+
strokeWidth: 2,
|
|
4736
|
+
strokeDasharray: "5 4"
|
|
4826
4737
|
})]
|
|
4827
|
-
}),
|
|
4828
|
-
|
|
4829
|
-
|
|
4830
|
-
|
|
4831
|
-
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
|
|
4835
|
-
|
|
4836
|
-
|
|
4837
|
-
|
|
4838
|
-
|
|
4839
|
-
|
|
4840
|
-
|
|
4841
|
-
|
|
4842
|
-
|
|
4843
|
-
|
|
4844
|
-
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
|
|
4848
|
-
|
|
4849
|
-
|
|
4850
|
-
addField,
|
|
4851
|
-
unplaced
|
|
4852
|
-
})
|
|
4853
|
-
})
|
|
4854
|
-
]
|
|
4855
|
-
}) : /* @__PURE__ */ jsx(Box, {
|
|
4856
|
-
component: "button",
|
|
4857
|
-
type: "button",
|
|
4858
|
-
title: "Mostrar as propriedades",
|
|
4859
|
-
onClick: () => setPanel((current) => ({
|
|
4860
|
-
...current,
|
|
4861
|
-
open: true
|
|
4862
|
-
})),
|
|
4863
|
-
sx: {
|
|
4864
|
-
width: 28,
|
|
4865
|
-
flexShrink: 0,
|
|
4866
|
-
border: 0,
|
|
4867
|
-
borderLeft: 1,
|
|
4868
|
-
borderColor: "divider",
|
|
4869
|
-
bgcolor: "background.paper",
|
|
4870
|
-
color: "text.secondary",
|
|
4871
|
-
cursor: "pointer",
|
|
4872
|
-
writingMode: "vertical-rl",
|
|
4873
|
-
fontSize: 12,
|
|
4874
|
-
py: 1,
|
|
4875
|
-
"&:hover": { color: "primary.main" }
|
|
4876
|
-
},
|
|
4877
|
-
children: "⟨ Propriedades"
|
|
4878
|
-
}),
|
|
4879
|
-
/* @__PURE__ */ jsxs(Dialog, {
|
|
4880
|
-
open: picking !== null,
|
|
4881
|
-
onClose: () => setPicking(null),
|
|
4882
|
-
maxWidth: "xs",
|
|
4883
|
-
fullWidth: true,
|
|
4884
|
-
children: [
|
|
4885
|
-
/* @__PURE__ */ jsx(DialogTitle, {
|
|
4886
|
-
sx: { fontSize: 14 },
|
|
4887
|
-
children: "Dimensões"
|
|
4888
|
-
}),
|
|
4889
|
-
/* @__PURE__ */ jsxs(DialogContent, { children: [
|
|
4890
|
-
/* @__PURE__ */ jsxs(Typography, {
|
|
4891
|
-
sx: {
|
|
4892
|
-
fontSize: 12,
|
|
4893
|
-
color: "text.secondary",
|
|
4894
|
-
mb: 1
|
|
4895
|
-
},
|
|
4896
|
-
children: [
|
|
4897
|
-
"Marque as colunas que viram dimensão (filtro e eixo dos gráficos). Para expressões como",
|
|
4898
|
-
" ",
|
|
4899
|
-
/* @__PURE__ */ jsx("code", { children: "YEAR(tabela.data)" }),
|
|
4900
|
-
", use o modo SQL da dimensão."
|
|
4901
|
-
]
|
|
4738
|
+
}), nodes.map((node) => /* @__PURE__ */ jsx(TableCard, {
|
|
4739
|
+
node,
|
|
4740
|
+
position: placed(node),
|
|
4741
|
+
size: sizeOf(node),
|
|
4742
|
+
collapsed: !!collapsed[node.id],
|
|
4743
|
+
selected: !!isSelected(node),
|
|
4744
|
+
linking: !!linking && linking.node.id !== node.id,
|
|
4745
|
+
selectedField: selection?.kind === "dimension" || selection?.kind === "measure" ? selection.uid : null,
|
|
4746
|
+
onToggle: () => setCollapsed((current) => ({
|
|
4747
|
+
...current,
|
|
4748
|
+
[node.id]: !current[node.id]
|
|
4749
|
+
})),
|
|
4750
|
+
onScroll: (top) => setScrolls((current) => ({
|
|
4751
|
+
...current,
|
|
4752
|
+
[node.id]: top
|
|
4753
|
+
})),
|
|
4754
|
+
onHeaderDown: (event) => startMove(event, node),
|
|
4755
|
+
onResizeDown: (event, edges) => startResize(event, node, edges),
|
|
4756
|
+
onResizeReset: () => resetSize(node),
|
|
4757
|
+
onColumnDown: (event, column) => startLink(event, node, column),
|
|
4758
|
+
onFieldClick: (item) => setSelection({
|
|
4759
|
+
kind: item.kind,
|
|
4760
|
+
uid: item.uid
|
|
4902
4761
|
}),
|
|
4903
|
-
|
|
4904
|
-
|
|
4762
|
+
onAddField: (kind, column) => addField(kind, node.name, column)
|
|
4763
|
+
}, node.id))]
|
|
4764
|
+
}),
|
|
4765
|
+
/* @__PURE__ */ jsxs(Box, {
|
|
4766
|
+
onMouseDown: (event) => event.stopPropagation(),
|
|
4767
|
+
sx: {
|
|
4768
|
+
position: "absolute",
|
|
4769
|
+
top: 8,
|
|
4770
|
+
left: 8,
|
|
4771
|
+
right: 8,
|
|
4772
|
+
display: "flex",
|
|
4773
|
+
gap: .75,
|
|
4774
|
+
flexWrap: "wrap",
|
|
4775
|
+
alignItems: "center",
|
|
4776
|
+
pointerEvents: "none",
|
|
4777
|
+
"& > *": { pointerEvents: "auto" }
|
|
4778
|
+
},
|
|
4779
|
+
children: [
|
|
4780
|
+
/* @__PURE__ */ jsx(Button, {
|
|
4905
4781
|
size: "small",
|
|
4906
|
-
|
|
4907
|
-
|
|
4908
|
-
|
|
4909
|
-
|
|
4782
|
+
variant: "outlined",
|
|
4783
|
+
onClick: addTable,
|
|
4784
|
+
children: "+ Tabela"
|
|
4785
|
+
}),
|
|
4786
|
+
/* @__PURE__ */ jsx(Button, {
|
|
4787
|
+
size: "small",
|
|
4788
|
+
onClick: onLoadColumns,
|
|
4789
|
+
disabled: loadingColumns,
|
|
4790
|
+
title: "Lê uma linha de cada tabela para listar as colunas",
|
|
4791
|
+
sx: { bgcolor: "#1b1e23" },
|
|
4792
|
+
children: loadingColumns ? "Lendo colunas…" : "Recarregar colunas"
|
|
4793
|
+
}),
|
|
4794
|
+
/* @__PURE__ */ jsxs(Box, {
|
|
4910
4795
|
sx: {
|
|
4911
|
-
|
|
4912
|
-
|
|
4796
|
+
ml: "auto",
|
|
4797
|
+
display: "flex",
|
|
4798
|
+
gap: .5,
|
|
4799
|
+
alignItems: "center"
|
|
4913
4800
|
},
|
|
4914
|
-
children:
|
|
4915
|
-
|
|
4916
|
-
|
|
4917
|
-
|
|
4918
|
-
|
|
4919
|
-
|
|
4920
|
-
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
|
|
4927
|
-
|
|
4928
|
-
|
|
4929
|
-
|
|
4930
|
-
|
|
4801
|
+
children: [
|
|
4802
|
+
/* @__PURE__ */ jsx(Button, {
|
|
4803
|
+
size: "small",
|
|
4804
|
+
onClick: () => {
|
|
4805
|
+
const layout = autoLayout(nodes, sizes);
|
|
4806
|
+
setPositions((current) => Object.fromEntries(Object.entries(layout).map(([id, point]) => [id, {
|
|
4807
|
+
...current[id],
|
|
4808
|
+
...point
|
|
4809
|
+
}])));
|
|
4810
|
+
fitToScreen(layout);
|
|
4811
|
+
},
|
|
4812
|
+
title: "Dimensões em cima, fatos embaixo (troca as posições salvas)",
|
|
4813
|
+
sx: { bgcolor: "#1b1e23" },
|
|
4814
|
+
children: "Organizar"
|
|
4815
|
+
}),
|
|
4816
|
+
/* @__PURE__ */ jsx(Button, {
|
|
4817
|
+
size: "small",
|
|
4818
|
+
onClick: () => fitToScreen(),
|
|
4819
|
+
sx: { bgcolor: "#1b1e23" },
|
|
4820
|
+
children: "Ajustar à tela"
|
|
4821
|
+
}),
|
|
4822
|
+
/* @__PURE__ */ jsx(IconButton, {
|
|
4823
|
+
size: "small",
|
|
4824
|
+
"aria-label": "Diminuir zoom",
|
|
4825
|
+
onClick: () => setView((current) => ({
|
|
4826
|
+
...current,
|
|
4827
|
+
zoom: Math.max(.3, current.zoom - .1)
|
|
4828
|
+
})),
|
|
4829
|
+
children: "−"
|
|
4830
|
+
}),
|
|
4831
|
+
/* @__PURE__ */ jsxs(Typography, {
|
|
4832
|
+
sx: {
|
|
4833
|
+
fontSize: 11,
|
|
4834
|
+
fontFamily: MONO,
|
|
4835
|
+
width: 36,
|
|
4836
|
+
textAlign: "center"
|
|
4837
|
+
},
|
|
4838
|
+
children: [Math.round(view.zoom * 100), "%"]
|
|
4839
|
+
}),
|
|
4840
|
+
/* @__PURE__ */ jsx(IconButton, {
|
|
4841
|
+
size: "small",
|
|
4842
|
+
"aria-label": "Aumentar zoom",
|
|
4843
|
+
onClick: () => setView((current) => ({
|
|
4844
|
+
...current,
|
|
4845
|
+
zoom: Math.min(2, current.zoom + .1)
|
|
4846
|
+
})),
|
|
4847
|
+
children: "+"
|
|
4848
|
+
})
|
|
4849
|
+
]
|
|
4931
4850
|
})
|
|
4932
|
-
]
|
|
4933
|
-
|
|
4934
|
-
|
|
4935
|
-
|
|
4936
|
-
|
|
4937
|
-
|
|
4938
|
-
|
|
4939
|
-
|
|
4851
|
+
]
|
|
4852
|
+
}),
|
|
4853
|
+
!nodes.length && /* @__PURE__ */ jsx(Box, {
|
|
4854
|
+
sx: {
|
|
4855
|
+
position: "absolute",
|
|
4856
|
+
inset: 0,
|
|
4857
|
+
display: "flex",
|
|
4858
|
+
alignItems: "center",
|
|
4859
|
+
justifyContent: "center",
|
|
4860
|
+
pointerEvents: "none",
|
|
4861
|
+
color: "text.secondary",
|
|
4862
|
+
fontSize: 13,
|
|
4863
|
+
textAlign: "center",
|
|
4864
|
+
px: 4
|
|
4865
|
+
},
|
|
4866
|
+
children: "Modelo vazio. Adicione as tabelas dimensão (cadastros: navio, calendário…) e fato (lançamentos: pesagens, custos…) e arraste a coluna da fato até a chave da dimensão para relacioná-las."
|
|
4867
|
+
}),
|
|
4868
|
+
!!nodes.length && /* @__PURE__ */ jsx(Typography, {
|
|
4869
|
+
sx: {
|
|
4870
|
+
position: "absolute",
|
|
4871
|
+
left: 10,
|
|
4872
|
+
bottom: 6,
|
|
4873
|
+
fontSize: 11,
|
|
4874
|
+
color: "text.disabled",
|
|
4875
|
+
pointerEvents: "none"
|
|
4876
|
+
},
|
|
4877
|
+
children: "Arraste uma coluna até a coluna de outra tabela para relacionar · +◇/+Σ na coluna cria dimensão/medida · Delete remove · Ctrl+roda: zoom"
|
|
4878
|
+
})
|
|
4879
|
+
]
|
|
4880
|
+
}), panel.open ? /* @__PURE__ */ jsxs(Box, {
|
|
4881
|
+
sx: {
|
|
4882
|
+
width: panel.width,
|
|
4883
|
+
flexShrink: 0,
|
|
4884
|
+
borderLeft: 1,
|
|
4885
|
+
borderColor: "divider",
|
|
4886
|
+
position: "relative",
|
|
4887
|
+
display: "flex",
|
|
4888
|
+
flexDirection: "column",
|
|
4889
|
+
minHeight: 0
|
|
4890
|
+
},
|
|
4891
|
+
children: [
|
|
4892
|
+
/* @__PURE__ */ jsx(Box, {
|
|
4893
|
+
onMouseDown: startPanelResize,
|
|
4894
|
+
title: "Arraste para redimensionar",
|
|
4895
|
+
sx: {
|
|
4896
|
+
position: "absolute",
|
|
4897
|
+
left: -3,
|
|
4898
|
+
top: 0,
|
|
4899
|
+
bottom: 0,
|
|
4900
|
+
width: 6,
|
|
4901
|
+
cursor: "ew-resize",
|
|
4902
|
+
zIndex: 2,
|
|
4903
|
+
"&:hover": {
|
|
4904
|
+
bgcolor: "primary.main",
|
|
4905
|
+
opacity: .4
|
|
4906
|
+
}
|
|
4907
|
+
}
|
|
4908
|
+
}),
|
|
4909
|
+
/* @__PURE__ */ jsxs(Box, {
|
|
4910
|
+
sx: {
|
|
4911
|
+
display: "flex",
|
|
4912
|
+
alignItems: "center",
|
|
4913
|
+
px: 1.5,
|
|
4914
|
+
py: .5,
|
|
4915
|
+
borderBottom: 1,
|
|
4916
|
+
borderColor: "divider"
|
|
4917
|
+
},
|
|
4918
|
+
children: [/* @__PURE__ */ jsx(Typography, {
|
|
4919
|
+
sx: {
|
|
4920
|
+
fontSize: 12,
|
|
4921
|
+
fontWeight: 700,
|
|
4922
|
+
color: "text.secondary",
|
|
4923
|
+
flex: 1
|
|
4924
|
+
},
|
|
4925
|
+
children: "Propriedades"
|
|
4926
|
+
}), /* @__PURE__ */ jsx(IconButton, {
|
|
4927
|
+
size: "small",
|
|
4928
|
+
"aria-label": "Recolher propriedades",
|
|
4929
|
+
title: "Recolher",
|
|
4930
|
+
onClick: () => setPanel((current) => ({
|
|
4931
|
+
...current,
|
|
4932
|
+
open: false
|
|
4933
|
+
})),
|
|
4934
|
+
children: "⟩"
|
|
4935
|
+
})]
|
|
4936
|
+
}),
|
|
4937
|
+
/* @__PURE__ */ jsx(Box, {
|
|
4938
|
+
sx: {
|
|
4939
|
+
overflow: "auto",
|
|
4940
|
+
flex: 1,
|
|
4941
|
+
p: 1.5
|
|
4942
|
+
},
|
|
4943
|
+
children: /* @__PURE__ */ jsx(Properties, {
|
|
4944
|
+
editor,
|
|
4945
|
+
selection,
|
|
4946
|
+
columns,
|
|
4947
|
+
errors,
|
|
4948
|
+
warnings,
|
|
4949
|
+
usage,
|
|
4950
|
+
onSelect: setSelection,
|
|
4951
|
+
onTry,
|
|
4952
|
+
setEditor,
|
|
4953
|
+
patchTable,
|
|
4954
|
+
patchRelationship,
|
|
4955
|
+
patchDimension,
|
|
4956
|
+
patchMeasure,
|
|
4957
|
+
removeTable,
|
|
4958
|
+
commitRename,
|
|
4959
|
+
addField,
|
|
4960
|
+
unplaced
|
|
4961
|
+
})
|
|
4962
|
+
})
|
|
4963
|
+
]
|
|
4964
|
+
}) : /* @__PURE__ */ jsx(Box, {
|
|
4965
|
+
component: "button",
|
|
4966
|
+
type: "button",
|
|
4967
|
+
title: "Mostrar as propriedades",
|
|
4968
|
+
onClick: () => setPanel((current) => ({
|
|
4969
|
+
...current,
|
|
4970
|
+
open: true
|
|
4971
|
+
})),
|
|
4972
|
+
sx: {
|
|
4973
|
+
width: 28,
|
|
4974
|
+
flexShrink: 0,
|
|
4975
|
+
border: 0,
|
|
4976
|
+
borderLeft: 1,
|
|
4977
|
+
borderColor: "divider",
|
|
4978
|
+
bgcolor: "background.paper",
|
|
4979
|
+
color: "text.secondary",
|
|
4980
|
+
cursor: "pointer",
|
|
4981
|
+
writingMode: "vertical-rl",
|
|
4982
|
+
fontSize: 12,
|
|
4983
|
+
py: 1,
|
|
4984
|
+
"&:hover": { color: "primary.main" }
|
|
4985
|
+
},
|
|
4986
|
+
children: "⟨ Propriedades"
|
|
4987
|
+
})]
|
|
4940
4988
|
});
|
|
4941
4989
|
}
|
|
4942
4990
|
/** Curva com tangentes horizontais (saída e chegada pelas laterais dos cards). */
|
|
@@ -5844,7 +5892,12 @@ function ModelPanel({ devtools, original, capabilities, tables, onTry, onSaved }
|
|
|
5844
5892
|
const [busy, setBusy] = useState(null);
|
|
5845
5893
|
const [actionError, setActionError] = useState(null);
|
|
5846
5894
|
const [save, setSave] = useState(null);
|
|
5847
|
-
|
|
5895
|
+
const applied = useRef(null);
|
|
5896
|
+
useEffect(() => {
|
|
5897
|
+
const next = draft ?? original;
|
|
5898
|
+
if (draft && canonicalJson(draft) === applied.current) return;
|
|
5899
|
+
setEditor((current) => same(fromEditor(current), next) ? current : toEditor(next));
|
|
5900
|
+
}, [draft, original]);
|
|
5848
5901
|
const errors = useMemo(() => validateEditor(editor), [editor]);
|
|
5849
5902
|
const edited = useMemo(() => fromEditor(editor), [editor]);
|
|
5850
5903
|
const structure = useMemo(() => canonicalJson(withoutDiagram(edited)), [edited]);
|
|
@@ -5916,8 +5969,26 @@ function ModelPanel({ devtools, original, capabilities, tables, onTry, onSaved }
|
|
|
5916
5969
|
const apply = () => act("apply", async () => {
|
|
5917
5970
|
const result = canonicalJson(withoutDiagram(reference)) === structure ? null : await validateSql();
|
|
5918
5971
|
if (result && Object.keys(result.errors).length) return;
|
|
5972
|
+
applied.current = differsFromOriginal ? canonicalJson(edited) : null;
|
|
5919
5973
|
setDraft(differsFromOriginal ? edited : null);
|
|
5920
5974
|
});
|
|
5975
|
+
const autoApply = useAutoApply();
|
|
5976
|
+
const editedKey = canonicalJson(edited);
|
|
5977
|
+
const attempted = useRef(null);
|
|
5978
|
+
useEffect(() => {
|
|
5979
|
+
if (!autoApply || !dirty || errors.length || busy || attempted.current === editedKey) return;
|
|
5980
|
+
const timer = setTimeout(() => {
|
|
5981
|
+
attempted.current = editedKey;
|
|
5982
|
+
apply();
|
|
5983
|
+
}, AUTO_APPLY_DELAY.model);
|
|
5984
|
+
return () => clearTimeout(timer);
|
|
5985
|
+
}, [
|
|
5986
|
+
autoApply,
|
|
5987
|
+
editedKey,
|
|
5988
|
+
dirty,
|
|
5989
|
+
errors.length,
|
|
5990
|
+
busy
|
|
5991
|
+
]);
|
|
5921
5992
|
const previewSave = () => act("save", async () => {
|
|
5922
5993
|
const result = await fetcher({
|
|
5923
5994
|
model: modelName,
|
|
@@ -6060,9 +6131,11 @@ function ModelPanel({ devtools, original, capabilities, tables, onTry, onSaved }
|
|
|
6060
6131
|
ml: "auto",
|
|
6061
6132
|
display: "flex",
|
|
6062
6133
|
gap: 1,
|
|
6063
|
-
flexWrap: "wrap"
|
|
6134
|
+
flexWrap: "wrap",
|
|
6135
|
+
alignItems: "center"
|
|
6064
6136
|
},
|
|
6065
6137
|
children: [
|
|
6138
|
+
/* @__PURE__ */ jsx(AutoApplySwitch, { applying: busy === "apply" }),
|
|
6066
6139
|
/* @__PURE__ */ jsx(Button, {
|
|
6067
6140
|
size: "small",
|
|
6068
6141
|
onClick: () => setShowCode(true),
|
|
@@ -6082,11 +6155,14 @@ function ModelPanel({ devtools, original, capabilities, tables, onTry, onSaved }
|
|
|
6082
6155
|
title: "Executa cada pedaço do modelo no banco com poucas chaves",
|
|
6083
6156
|
children: busy === "validate" ? "Validando…" : "Validar SQL"
|
|
6084
6157
|
}),
|
|
6085
|
-
/* @__PURE__ */ jsx(
|
|
6158
|
+
/* @__PURE__ */ jsx(ConfirmButton, {
|
|
6086
6159
|
size: "small",
|
|
6087
6160
|
disabled: !dirty,
|
|
6088
|
-
|
|
6161
|
+
onConfirm: () => setEditor(toEditor(reference)),
|
|
6089
6162
|
title: "Desfaz as edições ainda não aplicadas",
|
|
6163
|
+
confirmTitle: "Desfazer as edições?",
|
|
6164
|
+
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.",
|
|
6165
|
+
confirmLabel: "Desfazer",
|
|
6090
6166
|
children: "Desfazer"
|
|
6091
6167
|
}),
|
|
6092
6168
|
/* @__PURE__ */ jsx(Button, {
|
|
@@ -6105,7 +6181,7 @@ function ModelPanel({ devtools, original, capabilities, tables, onTry, onSaved }
|
|
|
6105
6181
|
title: `Reescreve src/dashboard/models/${original.name}.ts`,
|
|
6106
6182
|
children: busy === "save" ? "Gerando…" : "Salvar no arquivo"
|
|
6107
6183
|
}),
|
|
6108
|
-
/* @__PURE__ */ jsx(Button, {
|
|
6184
|
+
!autoApply && /* @__PURE__ */ jsx(Button, {
|
|
6109
6185
|
size: "small",
|
|
6110
6186
|
variant: "contained",
|
|
6111
6187
|
disabled: !dirty || !!errors.length || !!busy,
|
|
@@ -8111,4 +8187,4 @@ function ToggleButton$1({ draft, loading, problems, inspecting, onOpen }) {
|
|
|
8111
8187
|
//#endregion
|
|
8112
8188
|
export { DashboardDevtools as default };
|
|
8113
8189
|
|
|
8114
|
-
//# sourceMappingURL=DashboardDevtools-
|
|
8190
|
+
//# sourceMappingURL=DashboardDevtools-BT9mJrmJ.js.map
|