@devtable/dashboard 2.0.0 → 2.3.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.
Files changed (41) hide show
  1. package/dist/api-caller/index.d.ts +11 -3
  2. package/dist/api-caller/types.d.ts +11 -0
  3. package/dist/contexts/filter-values-context.d.ts +4 -0
  4. package/dist/contexts/index.d.ts +1 -0
  5. package/dist/dashboard.es.js +1521 -850
  6. package/dist/dashboard.umd.js +12 -23
  7. package/dist/definition-editor/global-variables-guide.d.ts +8 -0
  8. package/dist/filter/filter-checkbox/editor.d.ts +10 -0
  9. package/dist/filter/filter-checkbox/render.d.ts +9 -0
  10. package/dist/filter/filter-date-range/editor.d.ts +10 -0
  11. package/dist/filter/filter-date-range/render.d.ts +9 -0
  12. package/dist/filter/filter-multi-select/editor.d.ts +11 -0
  13. package/dist/filter/filter-multi-select/render.d.ts +9 -0
  14. package/dist/filter/filter-query-field/index.d.ts +8 -0
  15. package/dist/filter/filter-query-field/select-data-source.d.ts +8 -0
  16. package/dist/filter/filter-select/editor.d.ts +11 -0
  17. package/dist/filter/filter-select/render.d.ts +9 -0
  18. package/dist/filter/filter-settings/filter-setting.d.ts +11 -0
  19. package/dist/filter/filter-settings/filter-settings.d.ts +8 -0
  20. package/dist/filter/filter-settings/index.d.ts +10 -0
  21. package/dist/filter/filter-settings/preview-filter.d.ts +11 -0
  22. package/dist/filter/filter-settings/types.d.ts +4 -0
  23. package/dist/filter/filter-text-input/editor.d.ts +10 -0
  24. package/dist/filter/filter-text-input/render.d.ts +9 -0
  25. package/dist/filter/filter.d.ts +9 -0
  26. package/dist/filter/index.d.ts +9 -0
  27. package/dist/main/actions.d.ts +4 -2
  28. package/dist/main/use-filters.d.ts +8 -0
  29. package/dist/panel/panel-description.d.ts +1 -3
  30. package/dist/style.css +1 -1
  31. package/dist/types/dashboard.d.ts +2 -0
  32. package/dist/types/filter.d.ts +39 -0
  33. package/dist/types/index.d.ts +1 -0
  34. package/dist/utils/sql.d.ts +5 -3
  35. package/dist/utils/template/editor.d.ts +1 -1
  36. package/package.json +19 -18
  37. package/dist/definition-editor/query-editor/context-and-snippets.d.ts +0 -5
  38. package/dist/definition-editor/sql-snippet-editor/context-info.d.ts +0 -5
  39. package/dist/definition-editor/sql-snippet-editor/guide.d.ts +0 -2
  40. package/dist/panel/viz/text/index.d.ts +0 -9
  41. package/dist/panel/viz/text/panel.d.ts +0 -3
@@ -7,11 +7,11 @@ var __publicField = (obj, key, value) => {
7
7
  import React from "react";
8
8
  import _ from "lodash";
9
9
  import RGL, { WidthProvider } from "react-grid-layout";
10
- import { Popover, Tooltip, Group, Text, ActionIcon, Box, Button, TextInput, LoadingOverlay, Table, Select, useMantineTheme, ColorSwatch, Switch, Slider, SegmentedControl, NumberInput, ColorInput, Divider, Accordion, JsonInput, Modal, AppShell, Tabs, Menu, Container, Textarea } from "@mantine/core";
10
+ import { Modal, Tooltip, ActionIcon, Stack, Group, Text, Box, Button, TextInput, LoadingOverlay, Table, Select, useMantineTheme, ColorSwatch, Switch, Slider, SegmentedControl, NumberInput, ColorInput, Divider, Accordion, JsonInput, AppShell, Tabs, Menu, Container, Textarea, Checkbox, MultiSelect, SimpleGrid } from "@mantine/core";
11
11
  import { useRequest } from "ahooks";
12
12
  import axios from "axios";
13
13
  import { useModals, ModalsProvider } from "@mantine/modals";
14
- import { InfoCircle, DeviceFloppy, Refresh, Trash, PlaylistAdd, ArrowsMaximize, Settings, Copy, PlayerPlay, Resize, Paint, Database, Recycle, Share, ArrowLeft } from "tabler-icons-react";
14
+ import { InfoCircle, DeviceFloppy, Refresh, Trash, PlaylistAdd, ArrowsMaximize, Settings, Copy, PlayerPlay, Resize, Paint, Calendar, Recycle, Filter as Filter$1, Database, Share, ArrowLeft } from "tabler-icons-react";
15
15
  import RichTextEditor, { RichTextEditor as RichTextEditor$1 } from "@mantine/rte";
16
16
  import { useInputState, useElementSize, randomId } from "@mantine/hooks";
17
17
  import ReactEChartsCore from "echarts-for-react/lib/core";
@@ -23,15 +23,16 @@ import { GridComponent, LegendComponent, TooltipComponent, VisualMapComponent }
23
23
  import numbro from "numbro";
24
24
  import "echarts-gl";
25
25
  import { useForm, Controller, useFieldArray } from "react-hook-form";
26
- import { useForm as useForm$1, formList } from "@mantine/form";
26
+ import { useForm as useForm$1 } from "@mantine/form";
27
27
  import { Prism } from "@mantine/prism";
28
+ import { DateRangePicker } from "@mantine/dates";
28
29
  var DashboardMode = /* @__PURE__ */ ((DashboardMode2) => {
29
30
  DashboardMode2["Use"] = "use";
30
31
  DashboardMode2["Layout"] = "layout";
31
32
  DashboardMode2["Edit"] = "edit";
32
33
  return DashboardMode2;
33
34
  })(DashboardMode || {});
34
- const initialContext$4 = {
35
+ const initialContext$5 = {
35
36
  layoutFrozen: false,
36
37
  freezeLayout: () => {
37
38
  },
@@ -40,7 +41,7 @@ const initialContext$4 = {
40
41
  inLayoutMode: false,
41
42
  inUseMode: true
42
43
  };
43
- const LayoutStateContext = React.createContext(initialContext$4);
44
+ const LayoutStateContext = React.createContext(initialContext$5);
44
45
  function explainSQLSnippet(snippet, context) {
45
46
  const names = Object.keys(context);
46
47
  const vals = Object.values(context);
@@ -63,16 +64,16 @@ function formatSQL(sql, params) {
63
64
  throw error;
64
65
  }
65
66
  }
66
- function getSQLParams(context, definitions) {
67
+ function getSQLParams(context, definitions, filterValues) {
67
68
  const sqlSnippetRecord = definitions.sqlSnippets.reduce((ret, curr) => {
68
69
  ret[curr.key] = formatSQL(curr.value, context);
69
70
  return ret;
70
71
  }, {});
71
- return _.merge({}, sqlSnippetRecord, context);
72
+ return _.merge({}, sqlSnippetRecord, context, { filters: filterValues });
72
73
  }
73
- function explainSQL(sql, context, definitions) {
74
+ function explainSQL(sql, context, definitions, filterValues) {
74
75
  try {
75
- const params = getSQLParams(context, definitions);
76
+ const params = getSQLParams(context, definitions, filterValues);
76
77
  return formatSQL(sql, params);
77
78
  } catch (error) {
78
79
  console.error(error);
@@ -106,14 +107,26 @@ const APIClient = {
106
107
  };
107
108
  }
108
109
  };
109
- const queryBySQL = ({ context, definitions, title, query }) => async () => {
110
+ const queryByStaticSQL = ({ type, key, sql }) => async () => {
111
+ if (!type || !key || !sql) {
112
+ return [];
113
+ }
114
+ try {
115
+ const res = await APIClient.getRequest("POST")("/query", { type, key, query: sql });
116
+ return res;
117
+ } catch (error) {
118
+ console.error(error);
119
+ return [];
120
+ }
121
+ };
122
+ const queryBySQL = ({ context, definitions, title, query, filterValues }) => async () => {
110
123
  if (!query || !query.sql) {
111
124
  return [];
112
125
  }
113
126
  const { type, key, sql } = query;
114
127
  const needParams = sql.includes("$");
115
128
  try {
116
- const params = getSQLParams(context, definitions);
129
+ const params = getSQLParams(context, definitions, filterValues);
117
130
  const formattedSQL = formatSQL(sql, params);
118
131
  if (needParams) {
119
132
  console.groupCollapsed(`Final SQL for: ${title}`);
@@ -129,17 +142,27 @@ const queryBySQL = ({ context, definitions, title, query }) => async () => {
129
142
  };
130
143
  async function listDataSources() {
131
144
  try {
132
- const res = await APIClient.getRequest("POST")("/datasource/list", {});
133
- return res;
145
+ const res = await APIClient.getRequest("POST")("/datasource/list", {
146
+ filter: {},
147
+ sort: {
148
+ field: "create_time",
149
+ order: "ASC"
150
+ },
151
+ pagination: {
152
+ page: 1,
153
+ pagesize: 100
154
+ }
155
+ });
156
+ return res.data;
134
157
  } catch (error) {
135
158
  console.error(error);
136
- return {};
159
+ return [];
137
160
  }
138
161
  }
139
- const initialContext$3 = {};
140
- const initialContextInfoContext = initialContext$3;
141
- const ContextInfoContext = React.createContext(initialContext$3);
142
- const initialContext$2 = {
162
+ const initialContext$4 = {};
163
+ const initialContextInfoContext = initialContext$4;
164
+ const ContextInfoContext = React.createContext(initialContext$4);
165
+ const initialContext$3 = {
143
166
  id: "",
144
167
  data: [],
145
168
  loading: false,
@@ -161,16 +184,16 @@ const initialContext$2 = {
161
184
  refreshData: () => {
162
185
  }
163
186
  };
164
- const PanelContext = React.createContext(initialContext$2);
165
- const initialContext$1 = {
187
+ const PanelContext = React.createContext(initialContext$3);
188
+ const initialContext$2 = {
166
189
  addPanel: _.noop,
167
190
  duplidatePanel: _.noop,
168
191
  removePanelByID: _.noop,
169
192
  viewPanelInFullScreen: _.noop,
170
193
  inFullScreen: false
171
194
  };
172
- const DashboardActionContext = React.createContext(initialContext$1);
173
- const initialContext = {
195
+ const DashboardActionContext = React.createContext(initialContext$2);
196
+ const initialContext$1 = {
174
197
  sqlSnippets: [],
175
198
  setSQLSnippets: () => {
176
199
  },
@@ -178,7 +201,10 @@ const initialContext = {
178
201
  setQueries: () => {
179
202
  }
180
203
  };
181
- const DefinitionContext = React.createContext(initialContext);
204
+ const DefinitionContext = React.createContext(initialContext$1);
205
+ const initialContext = {};
206
+ const initialFilterValuesContext = initialContext;
207
+ const FilterValuesContext = React.createContext(initialContext);
182
208
  var jsxRuntime = { exports: {} };
183
209
  var reactJsxRuntime_production_min = {};
184
210
  /**
@@ -212,15 +238,13 @@ reactJsxRuntime_production_min.jsxs = q;
212
238
  const jsx = jsxRuntime.exports.jsx;
213
239
  const jsxs = jsxRuntime.exports.jsxs;
214
240
  const Fragment = jsxRuntime.exports.Fragment;
215
- function DescriptionPopover({
216
- position = "bottom",
217
- trigger = "hover"
218
- }) {
241
+ function DescriptionPopover({}) {
219
242
  const {
220
243
  freezeLayout
221
244
  } = React.useContext(LayoutStateContext);
222
245
  const [opened, setOpened] = React.useState(false);
223
246
  const {
247
+ title,
224
248
  description
225
249
  } = React.useContext(PanelContext);
226
250
  React.useEffect(() => {
@@ -229,45 +253,36 @@ function DescriptionPopover({
229
253
  if (!description || description === "<p><br></p>") {
230
254
  return null;
231
255
  }
232
- const target = trigger === "click" ? /* @__PURE__ */ jsx(Tooltip, {
233
- label: "Click to see description",
234
- openDelay: 500,
235
- children: /* @__PURE__ */ jsx(InfoCircle, {
236
- size: 20,
237
- onClick: () => setOpened((v) => !v),
238
- style: {
239
- verticalAlign: "baseline",
240
- cursor: "pointer"
241
- }
242
- })
243
- }) : /* @__PURE__ */ jsx(InfoCircle, {
244
- size: 20,
245
- onMouseEnter: () => setOpened(true),
246
- onMouseLeave: () => setOpened(false),
247
- style: {
248
- verticalAlign: "baseline",
249
- cursor: "pointer"
250
- }
251
- });
252
- return /* @__PURE__ */ jsx(Popover, {
253
- opened,
254
- onClose: () => setOpened(false),
255
- withCloseButton: trigger === "click",
256
- withArrow: true,
257
- trapFocus: true,
258
- closeOnEscape: false,
259
- placement: "center",
260
- position,
261
- target,
262
- width: "40vw",
263
- children: /* @__PURE__ */ jsx(RichTextEditor, {
264
- readOnly: true,
265
- value: description,
266
- onChange: _.noop,
267
- sx: {
268
- border: "none"
269
- }
270
- })
256
+ return /* @__PURE__ */ jsxs(Fragment, {
257
+ children: [/* @__PURE__ */ jsx(Modal, {
258
+ opened,
259
+ onClose: () => setOpened(false),
260
+ title,
261
+ withCloseButton: false,
262
+ children: /* @__PURE__ */ jsx(RichTextEditor, {
263
+ readOnly: true,
264
+ value: description,
265
+ onChange: _.noop,
266
+ sx: {
267
+ border: "none"
268
+ }
269
+ })
270
+ }), /* @__PURE__ */ jsx(Tooltip, {
271
+ label: "Click to see description",
272
+ position: "top-start",
273
+ children: /* @__PURE__ */ jsx(ActionIcon, {
274
+ variant: "subtle",
275
+ color: "blue",
276
+ onClick: () => setOpened((v) => !v),
277
+ sx: {
278
+ verticalAlign: "baseline",
279
+ cursor: "pointer"
280
+ },
281
+ children: /* @__PURE__ */ jsx(InfoCircle, {
282
+ size: 20
283
+ })
284
+ })
285
+ })]
271
286
  });
272
287
  }
273
288
  function EditDescription() {
@@ -283,8 +298,7 @@ function EditDescription() {
283
298
  }
284
299
  setDescription(value);
285
300
  }, [changed, value]);
286
- return /* @__PURE__ */ jsxs(Group, {
287
- direction: "column",
301
+ return /* @__PURE__ */ jsxs(Stack, {
288
302
  sx: {
289
303
  flexGrow: 1
290
304
  },
@@ -293,7 +307,7 @@ function EditDescription() {
293
307
  children: [/* @__PURE__ */ jsx(Text, {
294
308
  children: "Description"
295
309
  }), /* @__PURE__ */ jsx(ActionIcon, {
296
- variant: "hover",
310
+ variant: "subtle",
297
311
  color: "blue",
298
312
  disabled: !changed,
299
313
  onClick: submit,
@@ -357,10 +371,7 @@ function PreviewPanel() {
357
371
  title
358
372
  } = React.useContext(PanelContext);
359
373
  return /* @__PURE__ */ jsx(ErrorBoundary, {
360
- children: /* @__PURE__ */ jsxs(Group, {
361
- direction: "column",
362
- grow: true,
363
- noWrap: true,
374
+ children: /* @__PURE__ */ jsxs(Stack, {
364
375
  mx: "auto",
365
376
  mt: "xl",
366
377
  p: "5px",
@@ -380,10 +391,7 @@ function PreviewPanel() {
380
391
  flexShrink: 0
381
392
  },
382
393
  children: [/* @__PURE__ */ jsx(Group, {
383
- children: /* @__PURE__ */ jsx(DescriptionPopover, {
384
- position: "bottom",
385
- trigger: "hover"
386
- })
394
+ children: /* @__PURE__ */ jsx(DescriptionPopover, {})
387
395
  }), /* @__PURE__ */ jsx(Group, {
388
396
  grow: true,
389
397
  position: "center",
@@ -429,7 +437,7 @@ function EditTitle() {
429
437
  children: [/* @__PURE__ */ jsx(Text, {
430
438
  children: "Panel Title"
431
439
  }), /* @__PURE__ */ jsx(ActionIcon, {
432
- variant: "hover",
440
+ variant: "subtle",
433
441
  color: "blue",
434
442
  disabled: !changed,
435
443
  onClick: submit,
@@ -442,16 +450,13 @@ function EditTitle() {
442
450
  }
443
451
  function PanelConfig({}) {
444
452
  return /* @__PURE__ */ jsxs(Group, {
445
- direction: "row",
446
453
  grow: true,
447
454
  noWrap: true,
448
455
  align: "stretch",
449
456
  sx: {
450
457
  height: "100%"
451
458
  },
452
- children: [/* @__PURE__ */ jsxs(Group, {
453
- grow: true,
454
- direction: "column",
459
+ children: [/* @__PURE__ */ jsxs(Stack, {
455
460
  sx: {
456
461
  width: "40%",
457
462
  flexShrink: 0,
@@ -473,6 +478,7 @@ function DataPreview({
473
478
  id
474
479
  }) {
475
480
  const definitions = React.useContext(DefinitionContext);
481
+ const filterValues = React.useContext(FilterValuesContext);
476
482
  const contextInfo = React.useContext(ContextInfoContext);
477
483
  const query = React.useMemo(() => {
478
484
  return definitions.queries.find((d) => d.id === id);
@@ -484,10 +490,11 @@ function DataPreview({
484
490
  } = useRequest(queryBySQL({
485
491
  context: contextInfo,
486
492
  definitions,
493
+ filterValues,
487
494
  title: id,
488
495
  query
489
496
  }), {
490
- refreshDeps: [contextInfo, definitions, query]
497
+ refreshDeps: [contextInfo, definitions, query, filterValues]
491
498
  });
492
499
  if (loading) {
493
500
  return /* @__PURE__ */ jsx(LoadingOverlay, {
@@ -498,10 +505,8 @@ function DataPreview({
498
505
  if (data.length === 0) {
499
506
  return /* @__PURE__ */ jsx(Table, {});
500
507
  }
501
- return /* @__PURE__ */ jsxs(Group, {
508
+ return /* @__PURE__ */ jsxs(Stack, {
502
509
  my: "xl",
503
- direction: "column",
504
- grow: true,
505
510
  sx: {
506
511
  border: "1px solid #eee"
507
512
  },
@@ -525,7 +530,7 @@ function DataPreview({
525
530
  })]
526
531
  }), /* @__PURE__ */ jsx(ActionIcon, {
527
532
  mr: 15,
528
- variant: "hover",
533
+ variant: "subtle",
529
534
  color: "blue",
530
535
  disabled: loading,
531
536
  onClick: refresh,
@@ -579,10 +584,7 @@ function PickQuery({}) {
579
584
  label: d.id
580
585
  }));
581
586
  }, [queries]);
582
- return /* @__PURE__ */ jsxs(Group, {
583
- direction: "column",
584
- grow: true,
585
- noWrap: true,
587
+ return /* @__PURE__ */ jsxs(Stack, {
586
588
  children: [/* @__PURE__ */ jsxs(Group, {
587
589
  position: "left",
588
590
  sx: {
@@ -1518,39 +1520,6 @@ function VizTable({
1518
1520
  })]
1519
1521
  });
1520
1522
  }
1521
- function interpolateString(template, params = {}) {
1522
- const extendedParams = {
1523
- ...params,
1524
- numbro
1525
- };
1526
- const names = Object.keys(extendedParams);
1527
- const vals = Object.values(extendedParams);
1528
- try {
1529
- return new Function(...names, `return \`${template}\`;`)(...vals);
1530
- } catch (error) {
1531
- return error.message;
1532
- }
1533
- }
1534
- function VizText({
1535
- conf: {
1536
- paragraphs
1537
- },
1538
- data
1539
- }) {
1540
- return /* @__PURE__ */ jsx(Fragment, {
1541
- children: paragraphs.map(({
1542
- template,
1543
- size,
1544
- ...rest
1545
- }, index2) => /* @__PURE__ */ jsx(Text, {
1546
- ...rest,
1547
- sx: {
1548
- fontSize: size
1549
- },
1550
- children: interpolateString(template, data[0])
1551
- }, `${template}---${index2}`))
1552
- });
1553
- }
1554
1523
  echarts.use([GridComponent, VisualMapComponent, LegendComponent, TooltipComponent, CanvasRenderer]);
1555
1524
  function VizBar3D({
1556
1525
  conf,
@@ -1753,10 +1722,6 @@ function renderViz(width, height, data, viz) {
1753
1722
  return /* @__PURE__ */ jsx(VizTable, {
1754
1723
  ...props
1755
1724
  });
1756
- case "text":
1757
- return /* @__PURE__ */ jsx(VizText, {
1758
- ...props
1759
- });
1760
1725
  case "stats":
1761
1726
  return /* @__PURE__ */ jsx(VizStats, {
1762
1727
  ...props
@@ -1788,6 +1753,7 @@ function Viz({
1788
1753
  width,
1789
1754
  height
1790
1755
  } = useElementSize();
1756
+ const empty = React.useMemo(() => !Array.isArray(data) || data.length === 0, [data]);
1791
1757
  const needData = !typesDontNeedData.includes(viz.type);
1792
1758
  if (!needData) {
1793
1759
  return /* @__PURE__ */ jsx("div", {
@@ -1798,7 +1764,6 @@ function Viz({
1798
1764
  })
1799
1765
  });
1800
1766
  }
1801
- const empty = React.useMemo(() => !Array.isArray(data) || data.length === 0, [data]);
1802
1767
  if (loading) {
1803
1768
  return /* @__PURE__ */ jsx("div", {
1804
1769
  className: "viz-root",
@@ -1891,11 +1856,9 @@ function VizBar3DPanel({
1891
1856
  } = useForm({
1892
1857
  defaultValues
1893
1858
  });
1894
- return /* @__PURE__ */ jsx(Group, {
1895
- direction: "column",
1859
+ return /* @__PURE__ */ jsx(Stack, {
1896
1860
  mt: "md",
1897
1861
  spacing: "xs",
1898
- grow: true,
1899
1862
  children: /* @__PURE__ */ jsxs("form", {
1900
1863
  onSubmit: handleSubmit(setConf),
1901
1864
  children: [/* @__PURE__ */ jsx(Text, {
@@ -2085,7 +2048,6 @@ function BarFields({
2085
2048
  index: index2
2086
2049
  }) {
2087
2050
  return /* @__PURE__ */ jsxs(Group, {
2088
- direction: "row",
2089
2051
  grow: true,
2090
2052
  align: "top",
2091
2053
  children: [/* @__PURE__ */ jsx(Controller, {
@@ -2134,7 +2096,6 @@ function LineFields({
2134
2096
  index: index2
2135
2097
  }) {
2136
2098
  return /* @__PURE__ */ jsxs(Group, {
2137
- direction: "row",
2138
2099
  grow: true,
2139
2100
  align: "center",
2140
2101
  children: [/* @__PURE__ */ jsx(Controller, {
@@ -2183,7 +2144,6 @@ function ScatterFields({
2183
2144
  index: index2
2184
2145
  }) {
2185
2146
  return /* @__PURE__ */ jsx(Group, {
2186
- direction: "row",
2187
2147
  grow: true,
2188
2148
  align: "center",
2189
2149
  children: /* @__PURE__ */ jsx(Controller, {
@@ -2191,9 +2151,7 @@ function ScatterFields({
2191
2151
  control,
2192
2152
  render: ({
2193
2153
  field
2194
- }) => /* @__PURE__ */ jsxs(Group, {
2195
- direction: "column",
2196
- noWrap: true,
2154
+ }) => /* @__PURE__ */ jsxs(Stack, {
2197
2155
  sx: {
2198
2156
  flexGrow: 1
2199
2157
  },
@@ -2267,9 +2225,7 @@ function SeriesItemField({
2267
2225
  data
2268
2226
  }) {
2269
2227
  const type = seriesItem.type;
2270
- return /* @__PURE__ */ jsxs(Group, {
2271
- direction: "column",
2272
- grow: true,
2228
+ return /* @__PURE__ */ jsxs(Stack, {
2273
2229
  my: 0,
2274
2230
  p: "md",
2275
2231
  pr: 40,
@@ -2277,10 +2233,7 @@ function SeriesItemField({
2277
2233
  border: "1px solid #eee",
2278
2234
  position: "relative"
2279
2235
  },
2280
- children: [/* @__PURE__ */ jsx(Group, {
2281
- direction: "column",
2282
- grow: true,
2283
- noWrap: true,
2236
+ children: [/* @__PURE__ */ jsx(Stack, {
2284
2237
  children: /* @__PURE__ */ jsx(Controller, {
2285
2238
  name: `series.${index2}.type`,
2286
2239
  control,
@@ -2318,7 +2271,6 @@ function SeriesItemField({
2318
2271
  ...field
2319
2272
  })
2320
2273
  }), /* @__PURE__ */ jsxs(Group, {
2321
- direction: "row",
2322
2274
  grow: true,
2323
2275
  noWrap: true,
2324
2276
  children: [/* @__PURE__ */ jsx(Controller, {
@@ -2384,9 +2336,7 @@ function SeriesItemField({
2384
2336
  data: labelPositions,
2385
2337
  ...field
2386
2338
  })
2387
- }), /* @__PURE__ */ jsxs(Group, {
2388
- direction: "column",
2389
- grow: true,
2339
+ }), /* @__PURE__ */ jsxs(Stack, {
2390
2340
  spacing: 4,
2391
2341
  children: [/* @__PURE__ */ jsx(Text, {
2392
2342
  size: "sm",
@@ -2402,7 +2352,7 @@ function SeriesItemField({
2402
2352
  })]
2403
2353
  }), /* @__PURE__ */ jsx(ActionIcon, {
2404
2354
  color: "red",
2405
- variant: "hover",
2355
+ variant: "subtle",
2406
2356
  onClick: () => remove(index2),
2407
2357
  sx: {
2408
2358
  position: "absolute",
@@ -2457,9 +2407,7 @@ function SeriesField({
2457
2407
  value: index2.toString()
2458
2408
  }));
2459
2409
  }, [getValues]);
2460
- return /* @__PURE__ */ jsxs(Group, {
2461
- direction: "column",
2462
- grow: true,
2410
+ return /* @__PURE__ */ jsxs(Stack, {
2463
2411
  children: [controlledFields.map((seriesItem, index2) => /* @__PURE__ */ jsx(SeriesItemField, {
2464
2412
  control,
2465
2413
  index: index2,
@@ -2505,13 +2453,9 @@ function _NumbroFormatSelector({
2505
2453
  trimMantissa: event.currentTarget.checked
2506
2454
  });
2507
2455
  };
2508
- return /* @__PURE__ */ jsx(Group, {
2509
- direction: "column",
2510
- grow: true,
2511
- noWrap: true,
2456
+ return /* @__PURE__ */ jsx(Stack, {
2512
2457
  ref,
2513
2458
  children: /* @__PURE__ */ jsxs(Group, {
2514
- direction: "row",
2515
2459
  grow: true,
2516
2460
  children: [/* @__PURE__ */ jsx(Select, {
2517
2461
  label: "Format",
@@ -2547,9 +2491,7 @@ function YAxisField({
2547
2491
  index: index2,
2548
2492
  remove
2549
2493
  }) {
2550
- return /* @__PURE__ */ jsxs(Group, {
2551
- direction: "column",
2552
- grow: true,
2494
+ return /* @__PURE__ */ jsxs(Stack, {
2553
2495
  my: 0,
2554
2496
  p: "md",
2555
2497
  pr: 40,
@@ -2558,7 +2500,6 @@ function YAxisField({
2558
2500
  position: "relative"
2559
2501
  },
2560
2502
  children: [/* @__PURE__ */ jsx(Group, {
2561
- direction: "row",
2562
2503
  grow: true,
2563
2504
  noWrap: true,
2564
2505
  children: /* @__PURE__ */ jsx(Controller, {
@@ -2575,10 +2516,7 @@ function YAxisField({
2575
2516
  ...field
2576
2517
  })
2577
2518
  })
2578
- }), /* @__PURE__ */ jsx(Group, {
2579
- direction: "column",
2580
- grow: true,
2581
- noWrap: true,
2519
+ }), /* @__PURE__ */ jsx(Stack, {
2582
2520
  children: /* @__PURE__ */ jsx(Controller, {
2583
2521
  name: `y_axes.${index2}.label_formatter`,
2584
2522
  control,
@@ -2590,7 +2528,7 @@ function YAxisField({
2590
2528
  })
2591
2529
  }), /* @__PURE__ */ jsx(ActionIcon, {
2592
2530
  color: "red",
2593
- variant: "hover",
2531
+ variant: "subtle",
2594
2532
  onClick: () => remove(index2),
2595
2533
  sx: {
2596
2534
  position: "absolute",
@@ -2627,9 +2565,7 @@ function YAxesField({
2627
2565
  name: "",
2628
2566
  label_formatter: defaultNumbroFormat
2629
2567
  });
2630
- return /* @__PURE__ */ jsxs(Group, {
2631
- direction: "column",
2632
- grow: true,
2568
+ return /* @__PURE__ */ jsxs(Stack, {
2633
2569
  children: [controlledFields.map((field, index2) => /* @__PURE__ */ jsx(YAxisField, {
2634
2570
  control,
2635
2571
  index: index2,
@@ -2666,9 +2602,7 @@ function RegressionField({
2666
2602
  data
2667
2603
  }) {
2668
2604
  const method = regressionItem.transform.config.method;
2669
- return /* @__PURE__ */ jsxs(Group, {
2670
- direction: "column",
2671
- grow: true,
2605
+ return /* @__PURE__ */ jsxs(Stack, {
2672
2606
  my: 0,
2673
2607
  p: "md",
2674
2608
  pr: 40,
@@ -2690,7 +2624,6 @@ function RegressionField({
2690
2624
  ...field
2691
2625
  })
2692
2626
  }), /* @__PURE__ */ jsxs(Group, {
2693
- direction: "row",
2694
2627
  grow: true,
2695
2628
  noWrap: true,
2696
2629
  children: [/* @__PURE__ */ jsx(Controller, {
@@ -2738,7 +2671,6 @@ function RegressionField({
2738
2671
  }
2739
2672
  })]
2740
2673
  }), /* @__PURE__ */ jsxs(Group, {
2741
- direction: "row",
2742
2674
  grow: true,
2743
2675
  noWrap: true,
2744
2676
  children: [/* @__PURE__ */ jsx(Controller, {
@@ -2767,9 +2699,7 @@ function RegressionField({
2767
2699
  ...field
2768
2700
  })
2769
2701
  })]
2770
- }), /* @__PURE__ */ jsxs(Group, {
2771
- direction: "column",
2772
- grow: true,
2702
+ }), /* @__PURE__ */ jsxs(Stack, {
2773
2703
  spacing: 4,
2774
2704
  children: [/* @__PURE__ */ jsx(Text, {
2775
2705
  size: "sm",
@@ -2785,7 +2715,7 @@ function RegressionField({
2785
2715
  })]
2786
2716
  }), /* @__PURE__ */ jsx(ActionIcon, {
2787
2717
  color: "red",
2788
- variant: "hover",
2718
+ variant: "subtle",
2789
2719
  onClick: () => remove(index2),
2790
2720
  sx: {
2791
2721
  position: "absolute",
@@ -2844,9 +2774,7 @@ function RegressionsField({
2844
2774
  color: "#666666"
2845
2775
  }
2846
2776
  });
2847
- return /* @__PURE__ */ jsxs(Group, {
2848
- direction: "column",
2849
- grow: true,
2777
+ return /* @__PURE__ */ jsxs(Stack, {
2850
2778
  children: [controlledFields.map((regressionItem, index2) => /* @__PURE__ */ jsx(RegressionField, {
2851
2779
  regressionItem,
2852
2780
  control,
@@ -2999,9 +2927,7 @@ function _MantineFontWeightSlider({
2999
2927
  onChange(match.label);
3000
2928
  }
3001
2929
  }, [mark]);
3002
- return /* @__PURE__ */ jsxs(Group, {
3003
- direction: "column",
3004
- grow: true,
2930
+ return /* @__PURE__ */ jsxs(Stack, {
3005
2931
  spacing: 0,
3006
2932
  mt: "sm",
3007
2933
  mb: "lg",
@@ -3118,11 +3044,11 @@ const TemplateInput = React.forwardRef(function TemplateInput2({
3118
3044
  ...rest
3119
3045
  });
3120
3046
  });
3121
- function TemplateVariableField({
3047
+ const TemplateVariableField = React.forwardRef(function _TemplateVariableField({
3122
3048
  value,
3123
3049
  onChange,
3124
3050
  data
3125
- }) {
3051
+ }, _ref) {
3126
3052
  const colorType = value.color.type;
3127
3053
  const handleChange = (path, newValue) => {
3128
3054
  const v = _.cloneDeep(value);
@@ -3141,7 +3067,6 @@ function TemplateVariableField({
3141
3067
  label: "Data",
3142
3068
  labelPosition: "center"
3143
3069
  }), /* @__PURE__ */ jsxs(Group, {
3144
- direction: "row",
3145
3070
  grow: true,
3146
3071
  noWrap: true,
3147
3072
  children: [/* @__PURE__ */ jsx(TextInput, {
@@ -3167,9 +3092,7 @@ function TemplateVariableField({
3167
3092
  my: "xs",
3168
3093
  label: "Typography",
3169
3094
  labelPosition: "center"
3170
- }), /* @__PURE__ */ jsx(Group, {
3171
- direction: "column",
3172
- grow: true,
3095
+ }), /* @__PURE__ */ jsx(Stack, {
3173
3096
  children: /* @__PURE__ */ jsx(TextInput, {
3174
3097
  label: "Font Size",
3175
3098
  placeholder: "10px, 1em, 1rem, 100%...",
@@ -3197,9 +3120,7 @@ function TemplateVariableField({
3197
3120
  my: "xs",
3198
3121
  label: "Style",
3199
3122
  labelPosition: "center"
3200
- }), /* @__PURE__ */ jsxs(Group, {
3201
- direction: "column",
3202
- grow: true,
3123
+ }), /* @__PURE__ */ jsxs(Stack, {
3203
3124
  children: [/* @__PURE__ */ jsx(Select, {
3204
3125
  label: "Color Type",
3205
3126
  data: [{
@@ -3227,16 +3148,14 @@ function TemplateVariableField({
3227
3148
  })]
3228
3149
  })]
3229
3150
  });
3230
- }
3151
+ });
3231
3152
  function VariableField$1({
3232
3153
  control,
3233
3154
  index: index2,
3234
3155
  remove,
3235
3156
  data
3236
3157
  }) {
3237
- return /* @__PURE__ */ jsxs(Group, {
3238
- direction: "column",
3239
- grow: true,
3158
+ return /* @__PURE__ */ jsxs(Stack, {
3240
3159
  my: "sm",
3241
3160
  p: 0,
3242
3161
  sx: {
@@ -3256,7 +3175,7 @@ function VariableField$1({
3256
3175
  })
3257
3176
  }), /* @__PURE__ */ jsx(ActionIcon, {
3258
3177
  color: "red",
3259
- variant: "hover",
3178
+ variant: "subtle",
3260
3179
  onClick: () => remove(index2),
3261
3180
  sx: {
3262
3181
  position: "absolute",
@@ -3291,13 +3210,8 @@ function StatsField({
3291
3210
  };
3292
3211
  });
3293
3212
  const add = () => append(getANewVariable());
3294
- return /* @__PURE__ */ jsxs(Group, {
3295
- direction: "column",
3296
- grow: true,
3297
- children: [/* @__PURE__ */ jsxs(Group, {
3298
- direction: "column",
3299
- grow: true,
3300
- noWrap: true,
3213
+ return /* @__PURE__ */ jsxs(Stack, {
3214
+ children: [/* @__PURE__ */ jsxs(Stack, {
3301
3215
  spacing: 0,
3302
3216
  children: [/* @__PURE__ */ jsx(Controller, {
3303
3217
  name: "stats.templates.top",
@@ -3431,11 +3345,9 @@ function VizCartesianChartPanel({
3431
3345
  const changed = React.useMemo(() => {
3432
3346
  return !_.isEqual(values, conf);
3433
3347
  }, [values, conf]);
3434
- return /* @__PURE__ */ jsx(Group, {
3435
- direction: "column",
3348
+ return /* @__PURE__ */ jsx(Stack, {
3436
3349
  mt: "md",
3437
3350
  spacing: "xs",
3438
- grow: true,
3439
3351
  children: /* @__PURE__ */ jsxs("form", {
3440
3352
  onSubmit: handleSubmit(setConf),
3441
3353
  children: [/* @__PURE__ */ jsxs(Group, {
@@ -3459,16 +3371,11 @@ function VizCartesianChartPanel({
3459
3371
  })
3460
3372
  })]
3461
3373
  }), /* @__PURE__ */ jsxs(Accordion, {
3462
- offsetIcon: false,
3463
3374
  multiple: true,
3464
- initialState: {
3465
- 0: true,
3466
- 1: true
3467
- },
3375
+ value: ["X Axis", "Y Axes"],
3468
3376
  children: [/* @__PURE__ */ jsx(Accordion.Item, {
3469
- label: "X Axis",
3377
+ value: "X Axis",
3470
3378
  children: /* @__PURE__ */ jsxs(Group, {
3471
- direction: "row",
3472
3379
  grow: true,
3473
3380
  noWrap: true,
3474
3381
  children: [/* @__PURE__ */ jsx(Controller, {
@@ -3500,13 +3407,13 @@ function VizCartesianChartPanel({
3500
3407
  })]
3501
3408
  })
3502
3409
  }), /* @__PURE__ */ jsx(Accordion.Item, {
3503
- label: "Y Axes",
3410
+ value: "Y Axes",
3504
3411
  children: /* @__PURE__ */ jsx(YAxesField, {
3505
3412
  control,
3506
3413
  watch
3507
3414
  })
3508
3415
  }), /* @__PURE__ */ jsx(Accordion.Item, {
3509
- label: "Series",
3416
+ value: "Series",
3510
3417
  children: /* @__PURE__ */ jsx(SeriesField, {
3511
3418
  control,
3512
3419
  watch,
@@ -3514,7 +3421,7 @@ function VizCartesianChartPanel({
3514
3421
  data
3515
3422
  })
3516
3423
  }), /* @__PURE__ */ jsx(Accordion.Item, {
3517
- label: "Regression Lines",
3424
+ value: "Regression Lines",
3518
3425
  children: /* @__PURE__ */ jsx(RegressionsField, {
3519
3426
  control,
3520
3427
  watch,
@@ -3522,7 +3429,7 @@ function VizCartesianChartPanel({
3522
3429
  data
3523
3430
  })
3524
3431
  }), /* @__PURE__ */ jsx(Accordion.Item, {
3525
- label: "Stats",
3432
+ value: "Stats",
3526
3433
  children: /* @__PURE__ */ jsx(StatsField, {
3527
3434
  control,
3528
3435
  watch,
@@ -3547,11 +3454,9 @@ function VizPiePanel({
3547
3454
  value_field
3548
3455
  }
3549
3456
  });
3550
- return /* @__PURE__ */ jsx(Group, {
3551
- direction: "column",
3457
+ return /* @__PURE__ */ jsx(Stack, {
3552
3458
  mt: "md",
3553
3459
  spacing: "xs",
3554
- grow: true,
3555
3460
  children: /* @__PURE__ */ jsxs("form", {
3556
3461
  onSubmit: form.onSubmit(setConf),
3557
3462
  children: [/* @__PURE__ */ jsxs(Group, {
@@ -3571,11 +3476,9 @@ function VizPiePanel({
3571
3476
  size: 20
3572
3477
  })
3573
3478
  })]
3574
- }), /* @__PURE__ */ jsxs(Group, {
3575
- direction: "column",
3479
+ }), /* @__PURE__ */ jsxs(Stack, {
3576
3480
  mt: "md",
3577
3481
  spacing: "xs",
3578
- grow: true,
3579
3482
  p: "md",
3580
3483
  mb: "sm",
3581
3484
  sx: {
@@ -3628,11 +3531,9 @@ function VizRichTextPanel({
3628
3531
  const changed = React.useMemo(() => {
3629
3532
  return !_.isEqual(values, conf);
3630
3533
  }, [values, conf]);
3631
- return /* @__PURE__ */ jsx(Group, {
3632
- direction: "column",
3534
+ return /* @__PURE__ */ jsx(Stack, {
3633
3535
  mt: "md",
3634
3536
  spacing: "xs",
3635
- grow: true,
3636
3537
  children: /* @__PURE__ */ jsxs("form", {
3637
3538
  onSubmit: handleSubmit(setConf),
3638
3539
  children: [/* @__PURE__ */ jsxs(Group, {
@@ -3711,9 +3612,7 @@ function VariableField({
3711
3612
  remove,
3712
3613
  data
3713
3614
  }) {
3714
- return /* @__PURE__ */ jsxs(Group, {
3715
- direction: "column",
3716
- grow: true,
3615
+ return /* @__PURE__ */ jsxs(Stack, {
3717
3616
  my: "sm",
3718
3617
  p: 0,
3719
3618
  sx: {
@@ -3733,7 +3632,7 @@ function VariableField({
3733
3632
  })
3734
3633
  }), /* @__PURE__ */ jsx(ActionIcon, {
3735
3634
  color: "red",
3736
- variant: "hover",
3635
+ variant: "subtle",
3737
3636
  onClick: () => remove(index2),
3738
3637
  sx: {
3739
3638
  position: "absolute",
@@ -3767,9 +3666,7 @@ function VariablesField({
3767
3666
  };
3768
3667
  });
3769
3668
  const add = () => append(getANewVariable());
3770
- return /* @__PURE__ */ jsxs(Group, {
3771
- direction: "column",
3772
- grow: true,
3669
+ return /* @__PURE__ */ jsxs(Stack, {
3773
3670
  children: [controlledFields.map((_variableItem, index2) => /* @__PURE__ */ jsx(VariableField, {
3774
3671
  control,
3775
3672
  index: index2,
@@ -3845,12 +3742,9 @@ function VizStatsPanel({
3845
3742
  const changed = React.useMemo(() => {
3846
3743
  return !_.isEqual(values, conf);
3847
3744
  }, [values, conf]);
3848
- return /* @__PURE__ */ jsx(Group, {
3849
- direction: "column",
3745
+ return /* @__PURE__ */ jsx(Stack, {
3850
3746
  mt: "md",
3851
3747
  spacing: "xs",
3852
- grow: true,
3853
- noWrap: true,
3854
3748
  children: /* @__PURE__ */ jsxs("form", {
3855
3749
  onSubmit: handleSubmit(setConf),
3856
3750
  children: [/* @__PURE__ */ jsxs(Group, {
@@ -3914,11 +3808,9 @@ function SunburstPanel({
3914
3808
  value_field
3915
3809
  }
3916
3810
  });
3917
- return /* @__PURE__ */ jsx(Group, {
3918
- direction: "column",
3811
+ return /* @__PURE__ */ jsx(Stack, {
3919
3812
  mt: "md",
3920
3813
  spacing: "xs",
3921
- grow: true,
3922
3814
  children: /* @__PURE__ */ jsxs("form", {
3923
3815
  onSubmit: form.onSubmit(setConf),
3924
3816
  children: [/* @__PURE__ */ jsxs(Group, {
@@ -3938,11 +3830,9 @@ function SunburstPanel({
3938
3830
  size: 20
3939
3831
  })
3940
3832
  })]
3941
- }), /* @__PURE__ */ jsxs(Group, {
3942
- direction: "column",
3833
+ }), /* @__PURE__ */ jsxs(Stack, {
3943
3834
  mt: "md",
3944
3835
  spacing: "xs",
3945
- grow: true,
3946
3836
  p: "md",
3947
3837
  mb: "sm",
3948
3838
  sx: {
@@ -3994,7 +3884,7 @@ function VizTablePanel({
3994
3884
  initialValues: {
3995
3885
  id_field: "id",
3996
3886
  use_raw_columns: true,
3997
- columns: formList(columns != null ? columns : []),
3887
+ columns: columns != null ? columns : [],
3998
3888
  fontSize: "sm",
3999
3889
  horizontalSpacing: "sm",
4000
3890
  verticalSpacing: "sm",
@@ -4003,16 +3893,14 @@ function VizTablePanel({
4003
3893
  ...restConf
4004
3894
  }
4005
3895
  });
4006
- const addColumn = () => form.addListItem("columns", {
3896
+ const addColumn = () => form.insertListItem("columns", {
4007
3897
  label: randomId(),
4008
3898
  value_field: "value",
4009
3899
  value_type: ValueType.string
4010
3900
  });
4011
- return /* @__PURE__ */ jsx(Group, {
4012
- direction: "column",
3901
+ return /* @__PURE__ */ jsx(Stack, {
4013
3902
  mt: "md",
4014
3903
  spacing: "xs",
4015
- grow: true,
4016
3904
  children: /* @__PURE__ */ jsxs("form", {
4017
3905
  onSubmit: form.onSubmit(setConf),
4018
3906
  children: [/* @__PURE__ */ jsxs(Group, {
@@ -4032,11 +3920,9 @@ function VizTablePanel({
4032
3920
  size: 20
4033
3921
  })
4034
3922
  })]
4035
- }), /* @__PURE__ */ jsxs(Group, {
4036
- direction: "column",
3923
+ }), /* @__PURE__ */ jsxs(Stack, {
4037
3924
  mt: "md",
4038
3925
  spacing: "xs",
4039
- grow: true,
4040
3926
  p: "md",
4041
3927
  mb: "sm",
4042
3928
  sx: {
@@ -4092,9 +3978,7 @@ function VizTablePanel({
4092
3978
  },
4093
3979
  ...form.getInputProps("fontSize")
4094
3980
  })
4095
- }), /* @__PURE__ */ jsxs(Group, {
4096
- direction: "column",
4097
- grow: true,
3981
+ }), /* @__PURE__ */ jsxs(Stack, {
4098
3982
  children: [/* @__PURE__ */ jsx(Text, {
4099
3983
  children: "Other"
4100
3984
  }), /* @__PURE__ */ jsxs(Group, {
@@ -4113,11 +3997,9 @@ function VizTablePanel({
4113
3997
  })]
4114
3998
  })]
4115
3999
  })]
4116
- }), /* @__PURE__ */ jsxs(Group, {
4117
- direction: "column",
4000
+ }), /* @__PURE__ */ jsxs(Stack, {
4118
4001
  mt: "xs",
4119
4002
  spacing: "xs",
4120
- grow: true,
4121
4003
  p: "md",
4122
4004
  mb: "xl",
4123
4005
  sx: {
@@ -4129,16 +4011,12 @@ function VizTablePanel({
4129
4011
  ...form.getInputProps("use_raw_columns", {
4130
4012
  type: "checkbox"
4131
4013
  })
4132
- }), !form.values.use_raw_columns && /* @__PURE__ */ jsxs(Group, {
4133
- direction: "column",
4134
- grow: true,
4014
+ }), !form.values.use_raw_columns && /* @__PURE__ */ jsxs(Stack, {
4135
4015
  children: [/* @__PURE__ */ jsx(Text, {
4136
4016
  mt: "xl",
4137
4017
  mb: 0,
4138
4018
  children: "Custom Columns"
4139
- }), form.values.columns.map((item, index2) => /* @__PURE__ */ jsxs(Group, {
4140
- direction: "column",
4141
- grow: true,
4019
+ }), form.values.columns.map((_item, index2) => /* @__PURE__ */ jsxs(Stack, {
4142
4020
  my: 0,
4143
4021
  p: "md",
4144
4022
  pr: 40,
@@ -4155,22 +4033,22 @@ function VizTablePanel({
4155
4033
  sx: {
4156
4034
  flex: 1
4157
4035
  },
4158
- ...form.getListInputProps("columns", index2, "label")
4036
+ ...form.getInputProps(`columns.${index2}.label`)
4159
4037
  }), /* @__PURE__ */ jsx(DataFieldSelector, {
4160
4038
  label: "Value Field",
4161
4039
  required: true,
4162
4040
  data,
4163
- ...form.getListInputProps("columns", index2, "value_field")
4041
+ ...form.getInputProps(`columns.${index2}.value_field`)
4164
4042
  }), /* @__PURE__ */ jsx(ValueTypeSelector, {
4165
4043
  label: "Value Type",
4166
4044
  sx: {
4167
4045
  flex: 1
4168
4046
  },
4169
- ...form.getListInputProps("columns", index2, "value_type")
4047
+ ...form.getInputProps(`columns.${index2}.value_type`)
4170
4048
  })]
4171
4049
  }), /* @__PURE__ */ jsx(ActionIcon, {
4172
4050
  color: "red",
4173
- variant: "hover",
4051
+ variant: "subtle",
4174
4052
  onClick: () => form.removeListItem("columns", index2),
4175
4053
  sx: {
4176
4054
  position: "absolute",
@@ -4203,152 +4081,7 @@ function VizTablePanel({
4203
4081
  })
4204
4082
  });
4205
4083
  }
4206
- const sampleParagraphs = [{
4207
- align: "center",
4208
- size: "xl",
4209
- weight: "bold",
4210
- color: "black",
4211
- template: "Time: ${new Date().toISOString()}"
4212
- }, {
4213
- align: "center",
4214
- size: "md",
4215
- weight: "bold",
4216
- color: "red",
4217
- template: "Platform: ${navigator.userAgentData.platform}."
4218
- }];
4219
- function VizTextPanel({
4220
- conf,
4221
- setConf
4222
- }) {
4223
- var _a;
4224
- const form = useForm$1({
4225
- initialValues: {
4226
- paragraphs: formList((_a = conf.paragraphs) != null ? _a : sampleParagraphs)
4227
- }
4228
- });
4229
- const addParagraph = () => form.addListItem("paragraphs", {
4230
- ...sampleParagraphs[0],
4231
- template: randomId()
4232
- });
4233
- return /* @__PURE__ */ jsx(Group, {
4234
- direction: "column",
4235
- mt: "md",
4236
- spacing: "xs",
4237
- grow: true,
4238
- children: /* @__PURE__ */ jsxs("form", {
4239
- onSubmit: form.onSubmit(setConf),
4240
- children: [form.values.paragraphs.length === 0 && /* @__PURE__ */ jsx(Text, {
4241
- color: "dimmed",
4242
- align: "center",
4243
- children: "Empty"
4244
- }), /* @__PURE__ */ jsxs(Group, {
4245
- position: "apart",
4246
- mb: "xs",
4247
- sx: {
4248
- " + .mantine-Group-root": {
4249
- marginTop: 0
4250
- }
4251
- },
4252
- children: [/* @__PURE__ */ jsx(Text, {
4253
- children: "Paragraphs"
4254
- }), /* @__PURE__ */ jsx(ActionIcon, {
4255
- type: "submit",
4256
- mr: 5,
4257
- variant: "filled",
4258
- color: "blue",
4259
- children: /* @__PURE__ */ jsx(DeviceFloppy, {
4260
- size: 20
4261
- })
4262
- })]
4263
- }), form.values.paragraphs.map((item, index2) => /* @__PURE__ */ jsxs(Group, {
4264
- direction: "column",
4265
- grow: true,
4266
- my: 0,
4267
- p: "md",
4268
- pr: 40,
4269
- sx: {
4270
- border: "1px solid #eee",
4271
- position: "relative"
4272
- },
4273
- children: [/* @__PURE__ */ jsx(TextInput, {
4274
- placeholder: "Time: ${new Date().toISOString()}",
4275
- label: "Content Template",
4276
- required: true,
4277
- sx: {
4278
- flex: 1
4279
- },
4280
- ...form.getListInputProps("paragraphs", index2, "template")
4281
- }), /* @__PURE__ */ jsxs(Group, {
4282
- direction: "column",
4283
- grow: true,
4284
- children: [/* @__PURE__ */ jsx(Text, {
4285
- children: "Color"
4286
- }), /* @__PURE__ */ jsx(MantineColorSelector, {
4287
- ...form.getListInputProps("paragraphs", index2, "color")
4288
- })]
4289
- }), /* @__PURE__ */ jsx(Group, {
4290
- direction: "column",
4291
- grow: true,
4292
- children: /* @__PURE__ */ jsx(TextInput, {
4293
- label: "Font Size",
4294
- placeholder: "10px, 1em, 1rem, 100%...",
4295
- sx: {
4296
- flex: 1
4297
- },
4298
- ...form.getListInputProps("paragraphs", index2, "size")
4299
- })
4300
- }), /* @__PURE__ */ jsx(Group, {
4301
- position: "apart",
4302
- grow: true,
4303
- sx: {
4304
- "> *": {
4305
- flexGrow: 1,
4306
- maxWidth: "100%"
4307
- }
4308
- },
4309
- children: /* @__PURE__ */ jsx(MantineFontWeightSlider, {
4310
- label: "Font Weight",
4311
- ...form.getListInputProps("paragraphs", index2, "weight")
4312
- })
4313
- }), /* @__PURE__ */ jsx(ActionIcon, {
4314
- color: "red",
4315
- variant: "hover",
4316
- onClick: () => form.removeListItem("paragraphs", index2),
4317
- sx: {
4318
- position: "absolute",
4319
- top: 15,
4320
- right: 5
4321
- },
4322
- children: /* @__PURE__ */ jsx(Trash, {
4323
- size: 16
4324
- })
4325
- })]
4326
- }, index2)), /* @__PURE__ */ jsx(Group, {
4327
- position: "center",
4328
- mt: "md",
4329
- children: /* @__PURE__ */ jsx(Button, {
4330
- onClick: addParagraph,
4331
- children: "Add a Paragraph"
4332
- })
4333
- }), /* @__PURE__ */ jsx(Text, {
4334
- size: "sm",
4335
- weight: 500,
4336
- mt: "md",
4337
- children: "Current Configuration:"
4338
- }), /* @__PURE__ */ jsx(Prism, {
4339
- language: "json",
4340
- colorScheme: "dark",
4341
- noCopy: true,
4342
- children: JSON.stringify(form.values, null, 2)
4343
- })]
4344
- })
4345
- });
4346
- }
4347
4084
  const types = [{
4348
- value: "text",
4349
- label: "Text",
4350
- Panel: VizTextPanel
4351
- }, {
4352
4085
  value: "stats",
4353
4086
  label: "Stats",
4354
4087
  Panel: VizStatsPanel
@@ -4438,17 +4171,13 @@ function EditVizConf() {
4438
4171
  }
4439
4172
  function VizConfig({}) {
4440
4173
  return /* @__PURE__ */ jsxs(Group, {
4441
- direction: "row",
4442
4174
  grow: true,
4443
4175
  noWrap: true,
4444
4176
  align: "stretch",
4445
4177
  sx: {
4446
4178
  height: "100%"
4447
4179
  },
4448
- children: [/* @__PURE__ */ jsx(Group, {
4449
- grow: true,
4450
- direction: "column",
4451
- noWrap: true,
4180
+ children: [/* @__PURE__ */ jsx(Stack, {
4452
4181
  sx: {
4453
4182
  width: "40%",
4454
4183
  flexShrink: 0,
@@ -4500,23 +4229,38 @@ function PanelSettingsModal({
4500
4229
  },
4501
4230
  main: {
4502
4231
  height: "100%",
4503
- width: "100%"
4232
+ width: "100%",
4233
+ padding: "16px"
4504
4234
  }
4505
4235
  },
4506
4236
  padding: "md",
4507
4237
  children: /* @__PURE__ */ jsxs(Tabs, {
4508
- initialTab: 2,
4509
- children: [/* @__PURE__ */ jsxs(Tabs.Tab, {
4510
- label: "Data",
4238
+ defaultValue: "Visualization",
4239
+ children: [/* @__PURE__ */ jsxs(Tabs.List, {
4240
+ children: [/* @__PURE__ */ jsx(Tabs.Tab, {
4241
+ value: "Data",
4242
+ children: "Data"
4243
+ }), /* @__PURE__ */ jsx(Tabs.Tab, {
4244
+ value: "Panel",
4245
+ children: "Panel"
4246
+ }), /* @__PURE__ */ jsx(Tabs.Tab, {
4247
+ value: "Visualization",
4248
+ children: "Visualization"
4249
+ })]
4250
+ }), /* @__PURE__ */ jsxs(Tabs.Panel, {
4251
+ value: "Data",
4252
+ pt: "sm",
4511
4253
  children: [/* @__PURE__ */ jsx(LoadingOverlay, {
4512
4254
  visible: loading,
4513
4255
  exitTransitionDuration: 0
4514
4256
  }), /* @__PURE__ */ jsx(PickQuery, {})]
4515
- }), /* @__PURE__ */ jsx(Tabs.Tab, {
4516
- label: "Panel",
4257
+ }), /* @__PURE__ */ jsx(Tabs.Panel, {
4258
+ value: "Panel",
4259
+ pt: "sm",
4517
4260
  children: /* @__PURE__ */ jsx(PanelConfig, {})
4518
- }), /* @__PURE__ */ jsx(Tabs.Tab, {
4519
- label: "Visualization",
4261
+ }), /* @__PURE__ */ jsx(Tabs.Panel, {
4262
+ value: "Visualization",
4263
+ pt: "sm",
4520
4264
  children: /* @__PURE__ */ jsx(VizConfig, {})
4521
4265
  })]
4522
4266
  })
@@ -4579,47 +4323,49 @@ function PanelTitleBar({}) {
4579
4323
  flexGrow: 1
4580
4324
  },
4581
4325
  children: /* @__PURE__ */ jsxs(Menu, {
4582
- control: /* @__PURE__ */ jsx(Text, {
4583
- lineClamp: 1,
4584
- weight: "bold",
4585
- children: title
4586
- }),
4587
- placement: "center",
4588
- children: [/* @__PURE__ */ jsx(Menu.Item, {
4589
- onClick: refreshData,
4590
- icon: /* @__PURE__ */ jsx(Refresh, {
4591
- size: 14
4592
- }),
4593
- children: "Refresh"
4594
- }), !inFullScreen && /* @__PURE__ */ jsx(Menu.Item, {
4595
- onClick: enterFullScreen,
4596
- icon: /* @__PURE__ */ jsx(ArrowsMaximize, {
4597
- size: 14
4598
- }),
4599
- children: "Full Screen"
4600
- }), inEditMode && /* @__PURE__ */ jsxs(Fragment, {
4601
- children: [/* @__PURE__ */ jsx(Divider, {
4602
- label: "Edit",
4603
- labelPosition: "center"
4604
- }), /* @__PURE__ */ jsx(Menu.Item, {
4605
- onClick: open,
4606
- icon: /* @__PURE__ */ jsx(Settings, {
4607
- size: 14
4608
- }),
4609
- children: "Settings"
4610
- }), /* @__PURE__ */ jsx(Menu.Item, {
4611
- onClick: duplicate,
4612
- icon: /* @__PURE__ */ jsx(Copy, {
4326
+ children: [/* @__PURE__ */ jsx(Menu.Target, {
4327
+ children: /* @__PURE__ */ jsx(Text, {
4328
+ lineClamp: 1,
4329
+ weight: "bold",
4330
+ children: title
4331
+ })
4332
+ }), /* @__PURE__ */ jsxs(Menu.Dropdown, {
4333
+ children: [/* @__PURE__ */ jsx(Menu.Item, {
4334
+ onClick: refreshData,
4335
+ icon: /* @__PURE__ */ jsx(Refresh, {
4613
4336
  size: 14
4614
4337
  }),
4615
- children: "Duplicate"
4616
- }), /* @__PURE__ */ jsx(Menu.Item, {
4617
- color: "red",
4618
- onClick: remove,
4619
- icon: /* @__PURE__ */ jsx(Trash, {
4338
+ children: "Refresh"
4339
+ }), !inFullScreen && /* @__PURE__ */ jsx(Menu.Item, {
4340
+ onClick: enterFullScreen,
4341
+ icon: /* @__PURE__ */ jsx(ArrowsMaximize, {
4620
4342
  size: 14
4621
4343
  }),
4622
- children: "Delete"
4344
+ children: "Full Screen"
4345
+ }), inEditMode && /* @__PURE__ */ jsxs(Fragment, {
4346
+ children: [/* @__PURE__ */ jsx(Divider, {
4347
+ label: "Edit",
4348
+ labelPosition: "center"
4349
+ }), /* @__PURE__ */ jsx(Menu.Item, {
4350
+ onClick: open,
4351
+ icon: /* @__PURE__ */ jsx(Settings, {
4352
+ size: 14
4353
+ }),
4354
+ children: "Settings"
4355
+ }), /* @__PURE__ */ jsx(Menu.Item, {
4356
+ onClick: duplicate,
4357
+ icon: /* @__PURE__ */ jsx(Copy, {
4358
+ size: 14
4359
+ }),
4360
+ children: "Duplicate"
4361
+ }), /* @__PURE__ */ jsx(Menu.Item, {
4362
+ color: "red",
4363
+ onClick: remove,
4364
+ icon: /* @__PURE__ */ jsx(Trash, {
4365
+ size: 14
4366
+ }),
4367
+ children: "Delete"
4368
+ })]
4623
4369
  })]
4624
4370
  })]
4625
4371
  })
@@ -4640,6 +4386,7 @@ function Panel({
4640
4386
  id
4641
4387
  }) {
4642
4388
  const contextInfo = React.useContext(ContextInfoContext);
4389
+ const filterValues = React.useContext(FilterValuesContext);
4643
4390
  const definitions = React.useContext(DefinitionContext);
4644
4391
  const [title, setTitle] = React.useState(initialTitle);
4645
4392
  const [description, setDescription] = React.useState(initialDesc);
@@ -4668,10 +4415,11 @@ function Panel({
4668
4415
  } = useRequest(queryBySQL({
4669
4416
  context: contextInfo,
4670
4417
  definitions,
4418
+ filterValues,
4671
4419
  title,
4672
4420
  query
4673
4421
  }), {
4674
- refreshDeps: [contextInfo, definitions, query]
4422
+ refreshDeps: [contextInfo, definitions, query, filterValues]
4675
4423
  });
4676
4424
  const refreshData = refresh;
4677
4425
  return /* @__PURE__ */ jsx(PanelContext.Provider, {
@@ -4725,7 +4473,7 @@ function DashboardLayout({
4725
4473
  }, [panels, setPanels]);
4726
4474
  return /* @__PURE__ */ jsx(ReactGridLayout$1, {
4727
4475
  onLayoutChange,
4728
- className,
4476
+ className: `dashboard-layout ${className}`,
4729
4477
  rowHeight,
4730
4478
  isDraggable,
4731
4479
  isResizable,
@@ -4751,9 +4499,10 @@ function DashboardLayout({
4751
4499
  }
4752
4500
  function renderLabel(icon, postfix) {
4753
4501
  return /* @__PURE__ */ jsxs(Text, {
4502
+ size: "xs",
4754
4503
  sx: {
4755
4504
  svg: {
4756
- verticalAlign: "text-bottom"
4505
+ verticalAlign: "bottom"
4757
4506
  }
4758
4507
  },
4759
4508
  children: [icon, " ", postfix]
@@ -4764,6 +4513,7 @@ function ModeToggler({
4764
4513
  setMode
4765
4514
  }) {
4766
4515
  return /* @__PURE__ */ jsx(SegmentedControl, {
4516
+ size: "xs",
4767
4517
  value: mode,
4768
4518
  onChange: setMode,
4769
4519
  data: [{
@@ -4774,50 +4524,58 @@ function ModeToggler({
4774
4524
  }, {
4775
4525
  label: renderLabel(/* @__PURE__ */ jsx(Resize, {
4776
4526
  size: 20
4777
- }), "Layout"),
4527
+ }), "Edit Layout"),
4778
4528
  value: DashboardMode.Layout
4779
4529
  }, {
4780
4530
  label: renderLabel(/* @__PURE__ */ jsx(Paint, {
4781
4531
  size: 20
4782
- }), "Content"),
4532
+ }), "Edit Content"),
4783
4533
  value: DashboardMode.Edit
4784
4534
  }]
4785
4535
  });
4786
4536
  }
4787
4537
  const example = `
4788
- -- You may reference context data or SQL snippets *by name*
4789
- -- in SQL or VizConfig.
4538
+ -- You may reference global variables in SQL or VizConfig.
4790
4539
  SELECT *
4791
4540
  FROM commit
4792
4541
  WHERE
4793
- -- context data
4794
- author_time BETWEEN '\${timeRange?.[0].toISOString()}' AND '\${timeRange?.[1].toISOString()}'
4542
+ -- context
4543
+ user_id IS '\${context.currentUserID}'
4544
+ -- filters
4545
+ author_time BETWEEN '\${filters.timeRange?.[0].toISOString()}' AND '\${filters.timeRange?.[1].toISOString()}'
4795
4546
  -- SQL snippets
4796
- AND \${author_email_condition}
4797
- \${order_by_clause}
4547
+ AND \${sql_snippets.author_email_condition}
4548
+ \${sql_snippets.order_by_clause}
4798
4549
  `;
4799
- function ContextAndSnippets({}) {
4550
+ function GlobalVariablesGuide({
4551
+ showSQLSnippets = true,
4552
+ sx = {}
4553
+ }) {
4800
4554
  const contextInfo = React.useContext(ContextInfoContext);
4555
+ const filterValues = React.useContext(FilterValuesContext);
4801
4556
  const {
4802
4557
  sqlSnippets
4803
4558
  } = React.useContext(DefinitionContext);
4804
- const snippets = React.useMemo(() => {
4805
- const snippets2 = sqlSnippets.reduce((prev, curr) => {
4806
- prev[curr.key] = curr.value;
4807
- return prev;
4808
- }, {});
4809
- return JSON.stringify(snippets2, null, 2);
4810
- }, [sqlSnippets]);
4811
- const context = React.useMemo(() => {
4812
- return JSON.stringify(contextInfo, null, 2);
4813
- }, [contextInfo]);
4814
- return /* @__PURE__ */ jsxs(Group, {
4815
- direction: "column",
4816
- grow: true,
4559
+ const variablesString = React.useMemo(() => {
4560
+ const ret = {
4561
+ context: contextInfo,
4562
+ filters: filterValues
4563
+ };
4564
+ if (showSQLSnippets) {
4565
+ const sql_snippets = sqlSnippets.reduce((prev, curr) => {
4566
+ prev[curr.key] = curr.value;
4567
+ return prev;
4568
+ }, {});
4569
+ ret.sql_snippets = sql_snippets;
4570
+ }
4571
+ return JSON.stringify(ret, null, 2);
4572
+ }, [contextInfo, sqlSnippets, filterValues, showSQLSnippets]);
4573
+ return /* @__PURE__ */ jsxs(Stack, {
4817
4574
  sx: {
4818
4575
  border: "1px solid #eee",
4819
4576
  maxWidth: "40%",
4820
- overflow: "hidden"
4577
+ overflow: "hidden",
4578
+ ...sx
4821
4579
  },
4822
4580
  children: [/* @__PURE__ */ jsx(Group, {
4823
4581
  position: "left",
@@ -4830,10 +4588,9 @@ function ContextAndSnippets({}) {
4830
4588
  },
4831
4589
  children: /* @__PURE__ */ jsx(Text, {
4832
4590
  weight: 500,
4833
- children: "Context"
4591
+ children: "Global Variables"
4834
4592
  })
4835
- }), /* @__PURE__ */ jsxs(Group, {
4836
- direction: "column",
4593
+ }), /* @__PURE__ */ jsxs(Stack, {
4837
4594
  px: "md",
4838
4595
  pb: "md",
4839
4596
  sx: {
@@ -4852,21 +4609,7 @@ function ContextAndSnippets({}) {
4852
4609
  sx: {
4853
4610
  flexGrow: 0
4854
4611
  },
4855
- children: "Avaiable context"
4856
- }), /* @__PURE__ */ jsx(Prism, {
4857
- language: "json",
4858
- sx: {
4859
- width: "100%"
4860
- },
4861
- noCopy: true,
4862
- colorScheme: "dark",
4863
- children: context
4864
- }), /* @__PURE__ */ jsx(Text, {
4865
- weight: 500,
4866
- sx: {
4867
- flexGrow: 0
4868
- },
4869
- children: "Avaiable SQL Snippets"
4612
+ children: "Current Values"
4870
4613
  }), /* @__PURE__ */ jsx(Prism, {
4871
4614
  language: "json",
4872
4615
  sx: {
@@ -4874,7 +4617,7 @@ function ContextAndSnippets({}) {
4874
4617
  },
4875
4618
  noCopy: true,
4876
4619
  colorScheme: "dark",
4877
- children: snippets
4620
+ children: variablesString
4878
4621
  })]
4879
4622
  })]
4880
4623
  });
@@ -4883,10 +4626,11 @@ function PreviewSQL({
4883
4626
  value
4884
4627
  }) {
4885
4628
  const context = React.useContext(ContextInfoContext);
4629
+ const filterValues = React.useContext(FilterValuesContext);
4886
4630
  const definition = React.useContext(DefinitionContext);
4887
4631
  const explained = React.useMemo(() => {
4888
- return explainSQL(value, context, definition);
4889
- }, [value, context, definition]);
4632
+ return explainSQL(value, context, definition, filterValues);
4633
+ }, [value, context, definition, filterValues]);
4890
4634
  return /* @__PURE__ */ jsx(Prism, {
4891
4635
  language: "sql",
4892
4636
  colorScheme: "light",
@@ -4910,30 +4654,35 @@ function QueryForm({
4910
4654
  form.reset();
4911
4655
  }, [value]);
4912
4656
  const {
4913
- data: querySources = {},
4657
+ data: querySources = [],
4914
4658
  loading
4915
4659
  } = useRequest(listDataSources, {
4916
4660
  refreshDeps: []
4917
4661
  }, []);
4918
4662
  const querySourceTypeOptions = React.useMemo(() => {
4919
- return Object.keys(querySources).map((k2) => ({
4920
- label: k2,
4921
- value: k2
4663
+ const types2 = Array.from(new Set(querySources.map(({
4664
+ type
4665
+ }) => type)));
4666
+ return types2.map((type) => ({
4667
+ label: type,
4668
+ value: type
4922
4669
  }));
4923
4670
  }, [querySources]);
4924
4671
  const querySourceKeyOptions = React.useMemo(() => {
4925
- const sources = querySources[form.values.type];
4672
+ const sources = querySources.filter(({
4673
+ type
4674
+ }) => type === form.values.type);
4926
4675
  if (!sources) {
4927
4676
  return [];
4928
4677
  }
4929
- return sources.map((k2) => ({
4930
- label: k2,
4931
- value: k2
4678
+ return sources.map(({
4679
+ key
4680
+ }) => ({
4681
+ label: key,
4682
+ value: key
4932
4683
  }));
4933
4684
  }, [querySources, form.values.type]);
4934
- return /* @__PURE__ */ jsx(Group, {
4935
- direction: "column",
4936
- grow: true,
4685
+ return /* @__PURE__ */ jsx(Stack, {
4937
4686
  sx: {
4938
4687
  border: "1px solid #eee",
4939
4688
  flexGrow: 1
@@ -4961,9 +4710,7 @@ function QueryForm({
4961
4710
  size: 20
4962
4711
  })
4963
4712
  })]
4964
- }), /* @__PURE__ */ jsxs(Group, {
4965
- direction: "column",
4966
- grow: true,
4713
+ }), /* @__PURE__ */ jsxs(Stack, {
4967
4714
  my: 0,
4968
4715
  p: "md",
4969
4716
  pr: 40,
@@ -4996,8 +4743,18 @@ function QueryForm({
4996
4743
  ...form.getInputProps("key")
4997
4744
  })]
4998
4745
  }), /* @__PURE__ */ jsxs(Tabs, {
4999
- children: [/* @__PURE__ */ jsx(Tabs.Tab, {
5000
- label: "SQL",
4746
+ defaultValue: "SQL",
4747
+ children: [/* @__PURE__ */ jsxs(Tabs.List, {
4748
+ children: [/* @__PURE__ */ jsx(Tabs.Tab, {
4749
+ value: "SQL",
4750
+ children: "SQL"
4751
+ }), /* @__PURE__ */ jsx(Tabs.Tab, {
4752
+ value: "Preview",
4753
+ children: "Preview"
4754
+ })]
4755
+ }), /* @__PURE__ */ jsx(Tabs.Panel, {
4756
+ value: "SQL",
4757
+ pt: "sm",
5001
4758
  children: /* @__PURE__ */ jsx(Textarea, {
5002
4759
  autosize: true,
5003
4760
  minRows: 12,
@@ -5005,8 +4762,9 @@ function QueryForm({
5005
4762
  ...form.getInputProps("sql"),
5006
4763
  className: "code-textarea"
5007
4764
  })
5008
- }), /* @__PURE__ */ jsx(Tabs.Tab, {
5009
- label: "Preview",
4765
+ }), /* @__PURE__ */ jsx(Tabs.Panel, {
4766
+ value: "Preview",
4767
+ pt: "sm",
5010
4768
  children: /* @__PURE__ */ jsx(PreviewSQL, {
5011
4769
  value: form.values.sql
5012
4770
  })
@@ -5141,14 +4899,11 @@ function EditQueries({}) {
5141
4899
  },
5142
4900
  padding: "md",
5143
4901
  children: [/* @__PURE__ */ jsxs(Group, {
5144
- direction: "row",
5145
4902
  position: "apart",
5146
4903
  grow: true,
5147
4904
  align: "stretch",
5148
4905
  noWrap: true,
5149
- children: [/* @__PURE__ */ jsxs(Group, {
5150
- direction: "column",
5151
- grow: true,
4906
+ children: [/* @__PURE__ */ jsxs(Stack, {
5152
4907
  sx: {
5153
4908
  flexGrow: 1,
5154
4909
  maxWidth: "calc(60% - 16px)"
@@ -5160,73 +4915,12 @@ function EditQueries({}) {
5160
4915
  id,
5161
4916
  setID
5162
4917
  })]
5163
- }), /* @__PURE__ */ jsx(ContextAndSnippets, {})]
4918
+ }), /* @__PURE__ */ jsx(GlobalVariablesGuide, {})]
5164
4919
  }), /* @__PURE__ */ jsx(DataPreview, {
5165
4920
  id
5166
4921
  })]
5167
4922
  });
5168
4923
  }
5169
- function ContextInfo({}) {
5170
- const contextInfo = React.useContext(ContextInfoContext);
5171
- const sampleSQL2 = `SELECT *
5172
- FROM commit
5173
- WHERE author_time BETWEEN '\${timeRange?.[0].toISOString()}' AND '\${timeRange?.[1].toISOString()}'`;
5174
- return /* @__PURE__ */ jsxs(Group, {
5175
- direction: "column",
5176
- grow: true,
5177
- sx: {
5178
- border: "1px solid #eee",
5179
- overflow: "hidden"
5180
- },
5181
- children: [/* @__PURE__ */ jsx(Group, {
5182
- position: "left",
5183
- pl: "md",
5184
- py: "md",
5185
- sx: {
5186
- borderBottom: "1px solid #eee",
5187
- background: "#efefef",
5188
- flexGrow: 0
5189
- },
5190
- children: /* @__PURE__ */ jsx(Text, {
5191
- weight: 500,
5192
- children: "Context"
5193
- })
5194
- }), /* @__PURE__ */ jsxs(Group, {
5195
- direction: "column",
5196
- px: "md",
5197
- pb: "md",
5198
- sx: {
5199
- width: "100%"
5200
- },
5201
- children: [/* @__PURE__ */ jsx(Prism, {
5202
- language: "sql",
5203
- sx: {
5204
- width: "100%"
5205
- },
5206
- noCopy: true,
5207
- colorScheme: "dark",
5208
- children: `-- You may refer context data *by name*
5209
- -- in SQL or VizConfig.
5210
-
5211
- ${sampleSQL2}`
5212
- }), /* @__PURE__ */ jsx(Text, {
5213
- weight: 500,
5214
- sx: {
5215
- flexGrow: 0
5216
- },
5217
- children: "Avaiable context entries"
5218
- }), /* @__PURE__ */ jsx(Prism, {
5219
- language: "json",
5220
- sx: {
5221
- width: "100%"
5222
- },
5223
- noCopy: true,
5224
- colorScheme: "dark",
5225
- children: JSON.stringify(contextInfo, null, 2)
5226
- })]
5227
- })]
5228
- });
5229
- }
5230
4924
  function PreviewSnippet({
5231
4925
  value
5232
4926
  }) {
@@ -5234,10 +4928,7 @@ function PreviewSnippet({
5234
4928
  const explained = React.useMemo(() => {
5235
4929
  return explainSQLSnippet(value, context);
5236
4930
  }, [value, context]);
5237
- return /* @__PURE__ */ jsxs(Group, {
5238
- direction: "column",
5239
- noWrap: true,
5240
- grow: true,
4931
+ return /* @__PURE__ */ jsxs(Stack, {
5241
4932
  children: [/* @__PURE__ */ jsx(Text, {
5242
4933
  children: "Preview"
5243
4934
  }), /* @__PURE__ */ jsx(Prism, {
@@ -5254,12 +4945,12 @@ function SQLSnippetsEditor({}) {
5254
4945
  setSQLSnippets
5255
4946
  } = React.useContext(DefinitionContext);
5256
4947
  const initialValues = React.useMemo(() => ({
5257
- snippets: formList(sqlSnippets != null ? sqlSnippets : [])
4948
+ snippets: sqlSnippets != null ? sqlSnippets : []
5258
4949
  }), [sqlSnippets]);
5259
4950
  const form = useForm$1({
5260
4951
  initialValues
5261
4952
  });
5262
- const addSnippet = () => form.addListItem("snippets", {
4953
+ const addSnippet = () => form.insertListItem("snippets", {
5263
4954
  key: randomId(),
5264
4955
  value: ""
5265
4956
  });
@@ -5269,9 +4960,7 @@ function SQLSnippetsEditor({}) {
5269
4960
  }) => {
5270
4961
  setSQLSnippets(snippets);
5271
4962
  };
5272
- return /* @__PURE__ */ jsx(Group, {
5273
- direction: "column",
5274
- grow: true,
4963
+ return /* @__PURE__ */ jsx(Stack, {
5275
4964
  sx: {
5276
4965
  border: "1px solid #eee",
5277
4966
  flexGrow: 1
@@ -5304,16 +4993,12 @@ function SQLSnippetsEditor({}) {
5304
4993
  px: "md",
5305
4994
  pb: "md",
5306
4995
  pt: "md",
5307
- children: /* @__PURE__ */ jsxs(Group, {
5308
- direction: "column",
4996
+ children: /* @__PURE__ */ jsxs(Stack, {
5309
4997
  sx: {
5310
4998
  width: "100%",
5311
4999
  position: "relative"
5312
5000
  },
5313
- grow: true,
5314
- children: [form.values.snippets.map((_item, index2) => /* @__PURE__ */ jsxs(Group, {
5315
- direction: "column",
5316
- grow: true,
5001
+ children: [form.values.snippets.map((_item, index2) => /* @__PURE__ */ jsxs(Stack, {
5317
5002
  my: 0,
5318
5003
  p: "md",
5319
5004
  pr: 40,
@@ -5324,18 +5009,18 @@ function SQLSnippetsEditor({}) {
5324
5009
  children: [/* @__PURE__ */ jsx(TextInput, {
5325
5010
  label: "Key",
5326
5011
  required: true,
5327
- ...form.getListInputProps("snippets", index2, "key")
5012
+ ...form.getInputProps(`snippets.${index2}.key`)
5328
5013
  }), /* @__PURE__ */ jsx(Textarea, {
5329
5014
  minRows: 3,
5330
5015
  label: "Value",
5331
5016
  required: true,
5332
- ...form.getListInputProps("snippets", index2, "value"),
5017
+ ...form.getInputProps(`snippets.${index2}.value`),
5333
5018
  className: "code-textarea"
5334
5019
  }), /* @__PURE__ */ jsx(PreviewSnippet, {
5335
5020
  value: form.values.snippets[index2].value
5336
5021
  }), /* @__PURE__ */ jsx(ActionIcon, {
5337
5022
  color: "red",
5338
- variant: "hover",
5023
+ variant: "subtle",
5339
5024
  onClick: () => form.removeListItem("snippets", index2),
5340
5025
  sx: {
5341
5026
  position: "absolute",
@@ -5365,57 +5050,6 @@ function SQLSnippetsEditor({}) {
5365
5050
  })
5366
5051
  });
5367
5052
  }
5368
- const sampleSQL = `SELECT *
5369
- FROM commit
5370
- WHERE \${author_time_condition}`;
5371
- function SQLSnippetGuide() {
5372
- return /* @__PURE__ */ jsxs(Group, {
5373
- direction: "column",
5374
- grow: true,
5375
- sx: {
5376
- border: "1px solid #eee",
5377
- overflow: "hidden"
5378
- },
5379
- children: [/* @__PURE__ */ jsx(Group, {
5380
- position: "left",
5381
- pl: "md",
5382
- py: "md",
5383
- sx: {
5384
- borderBottom: "1px solid #eee",
5385
- background: "#efefef",
5386
- flexGrow: 0
5387
- },
5388
- children: /* @__PURE__ */ jsx(Text, {
5389
- weight: 500,
5390
- children: "Guide"
5391
- })
5392
- }), /* @__PURE__ */ jsx(Group, {
5393
- direction: "column",
5394
- px: "md",
5395
- pb: "md",
5396
- sx: {
5397
- width: "100%"
5398
- },
5399
- children: /* @__PURE__ */ jsx(Prism, {
5400
- language: "sql",
5401
- sx: {
5402
- width: "100%"
5403
- },
5404
- noCopy: true,
5405
- trim: false,
5406
- colorScheme: "dark",
5407
- children: `-- You may refer context data *by name*
5408
- -- in SQL or VizConfig.
5409
-
5410
- ${sampleSQL}
5411
-
5412
- -- where author_time_condition is:
5413
- author_time BETWEEN '\${timeRange?.[0].toISOString()}' AND '\${timeRange?.[1].toISOString()}'
5414
- `
5415
- })
5416
- })]
5417
- });
5418
- }
5419
5053
  function EditSQLSnippets({}) {
5420
5054
  return /* @__PURE__ */ jsx(AppShell, {
5421
5055
  sx: {
@@ -5433,19 +5067,12 @@ function EditSQLSnippets({}) {
5433
5067
  },
5434
5068
  padding: "md",
5435
5069
  children: /* @__PURE__ */ jsxs(Group, {
5436
- direction: "row",
5437
5070
  position: "apart",
5438
5071
  grow: true,
5439
5072
  align: "stretch",
5440
5073
  noWrap: true,
5441
- children: [/* @__PURE__ */ jsx(SQLSnippetsEditor, {}), /* @__PURE__ */ jsxs(Group, {
5442
- direction: "column",
5443
- grow: true,
5444
- noWrap: true,
5445
- sx: {
5446
- maxWidth: "40%"
5447
- },
5448
- children: [/* @__PURE__ */ jsx(SQLSnippetGuide, {}), /* @__PURE__ */ jsx(ContextInfo, {})]
5074
+ children: [/* @__PURE__ */ jsx(SQLSnippetsEditor, {}), /* @__PURE__ */ jsx(GlobalVariablesGuide, {
5075
+ showSQLSnippets: false
5449
5076
  })]
5450
5077
  })
5451
5078
  });
@@ -5471,11 +5098,22 @@ function DataEditorModal({
5471
5098
  e.stopPropagation();
5472
5099
  },
5473
5100
  children: /* @__PURE__ */ jsxs(Tabs, {
5474
- children: [/* @__PURE__ */ jsx(Tabs.Tab, {
5475
- label: "SQL Snippet",
5101
+ defaultValue: "Queries",
5102
+ children: [/* @__PURE__ */ jsxs(Tabs.List, {
5103
+ children: [/* @__PURE__ */ jsx(Tabs.Tab, {
5104
+ value: "SQL Snippet",
5105
+ children: "SQL Snippet"
5106
+ }), /* @__PURE__ */ jsx(Tabs.Tab, {
5107
+ value: "Queries",
5108
+ children: "Queries"
5109
+ })]
5110
+ }), /* @__PURE__ */ jsx(Tabs.Panel, {
5111
+ value: "SQL Snippet",
5112
+ pt: "sm",
5476
5113
  children: /* @__PURE__ */ jsx(EditSQLSnippets, {})
5477
- }), /* @__PURE__ */ jsx(Tabs.Tab, {
5478
- label: "Queries",
5114
+ }), /* @__PURE__ */ jsx(Tabs.Panel, {
5115
+ value: "Queries",
5116
+ pt: "sm",
5479
5117
  children: /* @__PURE__ */ jsx(EditQueries, {})
5480
5118
  })]
5481
5119
  })
@@ -5515,114 +5153,1044 @@ function ViewSchemaModal({
5515
5153
  })
5516
5154
  });
5517
5155
  }
5518
- function DashboardActions({
5519
- mode,
5520
- setMode,
5521
- hasChanges,
5522
- saveChanges,
5523
- revertChanges,
5524
- getCurrentSchema
5156
+ function FilterEditorCheckbox({
5157
+ field,
5158
+ index: index2,
5159
+ control
5525
5160
  }) {
5526
- const {
5527
- addPanel
5528
- } = React.useContext(DashboardActionContext);
5529
- const {
5530
- inLayoutMode,
5531
- inEditMode,
5532
- inUseMode
5533
- } = React.useContext(LayoutStateContext);
5534
- const [dataEditorOpened, setDataEditorOpened] = React.useState(false);
5535
- const openQueries = () => setDataEditorOpened(true);
5536
- const closeQueries = () => setDataEditorOpened(false);
5537
- const [schemaOpened, setSchemaOpened] = React.useState(false);
5538
- const openSchema = () => setSchemaOpened(true);
5539
- const closeSchema = () => setSchemaOpened(false);
5540
- return /* @__PURE__ */ jsxs(Group, {
5541
- position: "apart",
5542
- pt: "sm",
5543
- pb: "xs",
5544
- children: [/* @__PURE__ */ jsx(Group, {
5545
- position: "left",
5546
- children: /* @__PURE__ */ jsx(ModeToggler, {
5547
- mode,
5548
- setMode
5161
+ return /* @__PURE__ */ jsx(Fragment, {
5162
+ children: /* @__PURE__ */ jsx(Controller, {
5163
+ name: `filters.${index2}.config.default_value`,
5164
+ control,
5165
+ render: ({
5166
+ field: field2
5167
+ }) => /* @__PURE__ */ jsx(Checkbox, {
5168
+ checked: field2.value,
5169
+ onChange: (e) => field2.onChange(e.currentTarget.checked),
5170
+ label: "Default Checked"
5549
5171
  })
5550
- }), /* @__PURE__ */ jsxs(Group, {
5551
- position: "right",
5552
- children: [!inUseMode && /* @__PURE__ */ jsx(Button, {
5553
- variant: "default",
5554
- size: "sm",
5555
- onClick: addPanel,
5556
- leftIcon: /* @__PURE__ */ jsx(PlaylistAdd, {
5557
- size: 20
5558
- }),
5559
- children: "Add a Panel"
5560
- }), inEditMode && /* @__PURE__ */ jsx(Button, {
5561
- variant: "default",
5562
- size: "sm",
5563
- onClick: openQueries,
5564
- leftIcon: /* @__PURE__ */ jsx(Database, {
5565
- size: 20
5566
- }),
5567
- children: "Data Settings"
5568
- }), !inUseMode && /* @__PURE__ */ jsx(Button, {
5569
- variant: "default",
5570
- size: "sm",
5571
- onClick: saveChanges,
5572
- disabled: !hasChanges,
5573
- leftIcon: /* @__PURE__ */ jsx(DeviceFloppy, {
5574
- size: 20
5575
- }),
5576
- children: "Save Changes"
5577
- }), !inUseMode && /* @__PURE__ */ jsx(Button, {
5578
- color: "red",
5579
- size: "sm",
5580
- disabled: !hasChanges,
5581
- onClick: revertChanges,
5582
- leftIcon: /* @__PURE__ */ jsx(Recycle, {
5583
- size: 20
5584
- }),
5585
- children: "Revert Changes"
5586
- }), /* @__PURE__ */ jsxs(Menu, {
5587
- control: /* @__PURE__ */ jsx(Button, {
5588
- variant: "default",
5589
- size: "sm",
5590
- leftIcon: /* @__PURE__ */ jsx(Share, {
5591
- size: 20
5592
- }),
5593
- children: "Export"
5594
- }),
5595
- children: [/* @__PURE__ */ jsx(Menu.Item, {
5596
- disabled: true,
5597
- children: "Download Data"
5598
- }), /* @__PURE__ */ jsx(Menu.Item, {
5599
- onClick: openSchema,
5600
- children: "View Schema"
5601
- })]
5172
+ })
5173
+ });
5174
+ }
5175
+ const inputFormatOptions = [{
5176
+ label: "2022",
5177
+ value: "YYYY"
5178
+ }, {
5179
+ label: "2022-01",
5180
+ value: "YYYY-MM"
5181
+ }, {
5182
+ label: "2022-01-01",
5183
+ value: "YYYY-MM-DD"
5184
+ }];
5185
+ function FilterEditorDateRange({
5186
+ field,
5187
+ index: index2,
5188
+ control
5189
+ }) {
5190
+ return /* @__PURE__ */ jsxs(Fragment, {
5191
+ children: [/* @__PURE__ */ jsxs(Group, {
5192
+ children: [/* @__PURE__ */ jsx(Controller, {
5193
+ name: `filters.${index2}.config.required`,
5194
+ control,
5195
+ render: ({
5196
+ field: field2
5197
+ }) => /* @__PURE__ */ jsx(Checkbox, {
5198
+ checked: field2.value,
5199
+ onChange: (e) => field2.onChange(e.currentTarget.checked),
5200
+ label: "Required"
5201
+ })
5202
+ }), /* @__PURE__ */ jsx(Controller, {
5203
+ name: `filters.${index2}.config.clearable`,
5204
+ control,
5205
+ render: ({
5206
+ field: field2
5207
+ }) => /* @__PURE__ */ jsx(Checkbox, {
5208
+ checked: field2.value,
5209
+ onChange: (e) => field2.onChange(e.currentTarget.checked),
5210
+ label: "Clearable"
5211
+ })
5602
5212
  })]
5603
- }), /* @__PURE__ */ jsx(DataEditorModal, {
5604
- opened: dataEditorOpened,
5605
- close: closeQueries
5606
- }), /* @__PURE__ */ jsx(ViewSchemaModal, {
5607
- opened: schemaOpened,
5608
- close: closeSchema,
5609
- getCurrentSchema
5213
+ }), /* @__PURE__ */ jsx(Controller, {
5214
+ name: `filters.${index2}.config.inputFormat`,
5215
+ control,
5216
+ render: ({
5217
+ field: field2
5218
+ }) => /* @__PURE__ */ jsx(Select, {
5219
+ data: inputFormatOptions,
5220
+ label: "Display Format",
5221
+ ...field2
5222
+ })
5610
5223
  })]
5611
5224
  });
5612
5225
  }
5613
- function FullScreenPanel({
5614
- panel,
5615
- exitFullScreen
5616
- }) {
5226
+ function SelectDataSource({
5227
+ value,
5228
+ onChange
5229
+ }) {
5230
+ const {
5231
+ data: querySources = [],
5232
+ loading
5233
+ } = useRequest(listDataSources, {
5234
+ refreshDeps: []
5235
+ }, []);
5236
+ const querySourceTypeOptions = React.useMemo(() => {
5237
+ const types2 = Array.from(new Set(querySources.map(({
5238
+ type
5239
+ }) => type)));
5240
+ return types2.map((type) => ({
5241
+ label: type,
5242
+ value: type
5243
+ }));
5244
+ }, [querySources]);
5245
+ const querySourceKeyOptions = React.useMemo(() => {
5246
+ const sources = querySources.filter(({
5247
+ type
5248
+ }) => type === value.type);
5249
+ if (!sources) {
5250
+ return [];
5251
+ }
5252
+ return sources.map(({
5253
+ key
5254
+ }) => ({
5255
+ label: key,
5256
+ value: key
5257
+ }));
5258
+ }, [querySources, value.type]);
5259
+ return /* @__PURE__ */ jsxs(Group, {
5260
+ grow: true,
5261
+ children: [/* @__PURE__ */ jsx(Select, {
5262
+ label: "Data Source Type",
5263
+ data: querySourceTypeOptions,
5264
+ sx: {
5265
+ flex: 1
5266
+ },
5267
+ disabled: loading,
5268
+ value: value.type,
5269
+ onChange: (type) => {
5270
+ onChange({
5271
+ ...value,
5272
+ type
5273
+ });
5274
+ }
5275
+ }), /* @__PURE__ */ jsx(Select, {
5276
+ label: "Data Source Key",
5277
+ data: querySourceKeyOptions,
5278
+ sx: {
5279
+ flex: 1
5280
+ },
5281
+ disabled: loading,
5282
+ value: value.key,
5283
+ onChange: (key) => {
5284
+ onChange({
5285
+ ...value,
5286
+ key
5287
+ });
5288
+ }
5289
+ })]
5290
+ });
5291
+ }
5292
+ const FilterQueryField = React.forwardRef(function _FilterQueryField({
5293
+ value,
5294
+ onChange
5295
+ }, _ref) {
5296
+ return /* @__PURE__ */ jsxs(Stack, {
5297
+ my: 0,
5298
+ children: [/* @__PURE__ */ jsx(SelectDataSource, {
5299
+ value,
5300
+ onChange
5301
+ }), /* @__PURE__ */ jsxs(Tabs, {
5302
+ defaultValue: "SQL",
5303
+ children: [/* @__PURE__ */ jsxs(Tabs.List, {
5304
+ children: [/* @__PURE__ */ jsx(Tabs.Tab, {
5305
+ value: "SQL",
5306
+ children: "SQL"
5307
+ }), /* @__PURE__ */ jsx(Tabs.Tab, {
5308
+ value: "Preview",
5309
+ children: "Preview"
5310
+ })]
5311
+ }), /* @__PURE__ */ jsx(Tabs.Panel, {
5312
+ value: "SQL",
5313
+ pt: "sm",
5314
+ children: /* @__PURE__ */ jsx(Textarea, {
5315
+ autosize: true,
5316
+ minRows: 12,
5317
+ maxRows: 24,
5318
+ className: "code-textarea",
5319
+ value: value.sql,
5320
+ onChange: (e) => {
5321
+ onChange({
5322
+ ...value,
5323
+ sql: e.currentTarget.value
5324
+ });
5325
+ },
5326
+ placeholder: "SELECT name AS label, id AS value"
5327
+ })
5328
+ }), /* @__PURE__ */ jsx(Tabs.Panel, {
5329
+ value: "Preview",
5330
+ pt: "sm",
5331
+ children: /* @__PURE__ */ jsx(PreviewSQL, {
5332
+ value: value.sql
5333
+ })
5334
+ })]
5335
+ })]
5336
+ });
5337
+ });
5338
+ function FilterEditorMultiSelect({
5339
+ field,
5340
+ index: index2,
5341
+ control,
5342
+ watch
5343
+ }) {
5344
+ const {
5345
+ fields: staticOptionFields,
5346
+ append,
5347
+ remove
5348
+ } = useFieldArray({
5349
+ control,
5350
+ name: `filters.${index2}.config.static_options`
5351
+ });
5352
+ const watchedStaticOptions = watch(`filters.${index2}.config.static_options`);
5353
+ const addStaticOption = () => {
5354
+ append({
5355
+ label: "",
5356
+ value: ""
5357
+ });
5358
+ };
5359
+ const optionsForDefaultValue = [{
5360
+ label: "No default selection",
5361
+ value: ""
5362
+ }, ...watchedStaticOptions];
5363
+ return /* @__PURE__ */ jsxs(Fragment, {
5364
+ children: [/* @__PURE__ */ jsx(Divider, {
5365
+ label: "Configure options",
5366
+ labelPosition: "center"
5367
+ }), staticOptionFields.length > 0 && /* @__PURE__ */ jsx(Controller, {
5368
+ name: `filters.${index2}.config.default_value`,
5369
+ control,
5370
+ render: ({
5371
+ field: field2
5372
+ }) => /* @__PURE__ */ jsx(MultiSelect, {
5373
+ label: "Default Selection",
5374
+ data: optionsForDefaultValue,
5375
+ ...field2
5376
+ })
5377
+ }), staticOptionFields.map((_optionField, optionIndex) => /* @__PURE__ */ jsxs(Group, {
5378
+ sx: {
5379
+ position: "relative"
5380
+ },
5381
+ pr: "40px",
5382
+ children: [/* @__PURE__ */ jsx(Controller, {
5383
+ name: `filters.${index2}.config.static_options.${optionIndex}.label`,
5384
+ control,
5385
+ render: ({
5386
+ field: field2
5387
+ }) => /* @__PURE__ */ jsx(TextInput, {
5388
+ label: "Label",
5389
+ required: true,
5390
+ ...field2,
5391
+ sx: {
5392
+ flexGrow: 1
5393
+ }
5394
+ })
5395
+ }), /* @__PURE__ */ jsx(Controller, {
5396
+ name: `filters.${index2}.config.static_options.${optionIndex}.value`,
5397
+ control,
5398
+ render: ({
5399
+ field: field2
5400
+ }) => /* @__PURE__ */ jsx(TextInput, {
5401
+ label: "Value",
5402
+ required: true,
5403
+ ...field2,
5404
+ sx: {
5405
+ flexGrow: 1
5406
+ }
5407
+ })
5408
+ }), /* @__PURE__ */ jsx(ActionIcon, {
5409
+ color: "red",
5410
+ variant: "subtle",
5411
+ onClick: () => remove(optionIndex),
5412
+ sx: {
5413
+ position: "absolute",
5414
+ top: 28,
5415
+ right: 5
5416
+ },
5417
+ children: /* @__PURE__ */ jsx(Trash, {
5418
+ size: 16
5419
+ })
5420
+ })]
5421
+ })), /* @__PURE__ */ jsx(Button, {
5422
+ size: "xs",
5423
+ color: "blue",
5424
+ leftIcon: /* @__PURE__ */ jsx(PlaylistAdd, {
5425
+ size: 20
5426
+ }),
5427
+ onClick: addStaticOption,
5428
+ sx: {
5429
+ width: "50%"
5430
+ },
5431
+ mx: "auto",
5432
+ children: "Add an Option"
5433
+ }), /* @__PURE__ */ jsx(Divider, {
5434
+ label: "Or fetch options from database",
5435
+ labelPosition: "center"
5436
+ }), /* @__PURE__ */ jsx(Controller, {
5437
+ name: `filters.${index2}.config.options_query`,
5438
+ control,
5439
+ render: ({
5440
+ field: field2
5441
+ }) => /* @__PURE__ */ jsx(FilterQueryField, {
5442
+ ...field2
5443
+ })
5444
+ })]
5445
+ });
5446
+ }
5447
+ function FilterEditorSelect({
5448
+ field,
5449
+ index: index2,
5450
+ control,
5451
+ watch
5452
+ }) {
5453
+ const {
5454
+ fields: staticOptionFields,
5455
+ append,
5456
+ remove
5457
+ } = useFieldArray({
5458
+ control,
5459
+ name: `filters.${index2}.config.static_options`
5460
+ });
5461
+ const watchedStaticOptions = watch(`filters.${index2}.config.static_options`);
5462
+ const addStaticOption = () => {
5463
+ append({
5464
+ label: "",
5465
+ value: ""
5466
+ });
5467
+ };
5468
+ const optionsForDefaultValue = [{
5469
+ label: "No default selection",
5470
+ value: ""
5471
+ }, ...watchedStaticOptions];
5472
+ return /* @__PURE__ */ jsxs(Fragment, {
5473
+ children: [/* @__PURE__ */ jsx(Controller, {
5474
+ name: `filters.${index2}.config.required`,
5475
+ control,
5476
+ render: ({
5477
+ field: field2
5478
+ }) => /* @__PURE__ */ jsx(Checkbox, {
5479
+ checked: field2.value,
5480
+ onChange: (e) => field2.onChange(e.currentTarget.checked),
5481
+ label: "Required"
5482
+ })
5483
+ }), /* @__PURE__ */ jsx(Divider, {
5484
+ label: "Configure options",
5485
+ labelPosition: "center"
5486
+ }), staticOptionFields.length > 0 && /* @__PURE__ */ jsx(Controller, {
5487
+ name: `filters.${index2}.config.default_value`,
5488
+ control,
5489
+ render: ({
5490
+ field: field2
5491
+ }) => /* @__PURE__ */ jsx(Select, {
5492
+ label: "Default Selection",
5493
+ data: optionsForDefaultValue,
5494
+ ...field2
5495
+ })
5496
+ }), staticOptionFields.map((_optionField, optionIndex) => /* @__PURE__ */ jsxs(Group, {
5497
+ sx: {
5498
+ position: "relative"
5499
+ },
5500
+ pr: "40px",
5501
+ children: [/* @__PURE__ */ jsx(Controller, {
5502
+ name: `filters.${index2}.config.static_options.${optionIndex}.label`,
5503
+ control,
5504
+ render: ({
5505
+ field: field2
5506
+ }) => /* @__PURE__ */ jsx(TextInput, {
5507
+ label: "Label",
5508
+ required: true,
5509
+ ...field2,
5510
+ sx: {
5511
+ flexGrow: 1
5512
+ }
5513
+ })
5514
+ }), /* @__PURE__ */ jsx(Controller, {
5515
+ name: `filters.${index2}.config.static_options.${optionIndex}.value`,
5516
+ control,
5517
+ render: ({
5518
+ field: field2
5519
+ }) => /* @__PURE__ */ jsx(TextInput, {
5520
+ label: "Value",
5521
+ required: true,
5522
+ ...field2,
5523
+ sx: {
5524
+ flexGrow: 1
5525
+ }
5526
+ })
5527
+ }), /* @__PURE__ */ jsx(ActionIcon, {
5528
+ color: "red",
5529
+ variant: "subtle",
5530
+ onClick: () => remove(optionIndex),
5531
+ sx: {
5532
+ position: "absolute",
5533
+ top: 28,
5534
+ right: 5
5535
+ },
5536
+ children: /* @__PURE__ */ jsx(Trash, {
5537
+ size: 16
5538
+ })
5539
+ })]
5540
+ })), /* @__PURE__ */ jsx(Button, {
5541
+ size: "xs",
5542
+ color: "blue",
5543
+ leftIcon: /* @__PURE__ */ jsx(PlaylistAdd, {
5544
+ size: 20
5545
+ }),
5546
+ onClick: addStaticOption,
5547
+ sx: {
5548
+ width: "50%"
5549
+ },
5550
+ mx: "auto",
5551
+ children: "Add an Option"
5552
+ }), /* @__PURE__ */ jsx(Divider, {
5553
+ label: "Or fetch options from database",
5554
+ labelPosition: "center"
5555
+ }), /* @__PURE__ */ jsx(Controller, {
5556
+ name: `filters.${index2}.config.options_query`,
5557
+ control,
5558
+ render: ({
5559
+ field: field2
5560
+ }) => /* @__PURE__ */ jsx(FilterQueryField, {
5561
+ ...field2
5562
+ })
5563
+ })]
5564
+ });
5565
+ }
5566
+ function FilterEditorTextInput({
5567
+ field,
5568
+ index: index2,
5569
+ control
5570
+ }) {
5571
+ return /* @__PURE__ */ jsxs(Fragment, {
5572
+ children: [/* @__PURE__ */ jsx(Controller, {
5573
+ name: `filters.${index2}.config.default_value`,
5574
+ control,
5575
+ render: ({
5576
+ field: field2
5577
+ }) => /* @__PURE__ */ jsx(TextInput, {
5578
+ label: "Default Value",
5579
+ ...field2
5580
+ })
5581
+ }), /* @__PURE__ */ jsx(Controller, {
5582
+ name: `filters.${index2}.config.required`,
5583
+ control,
5584
+ render: ({
5585
+ field: field2
5586
+ }) => /* @__PURE__ */ jsx(Checkbox, {
5587
+ checked: field2.value,
5588
+ onChange: (e) => field2.onChange(e.currentTarget.checked),
5589
+ label: "Required"
5590
+ })
5591
+ })]
5592
+ });
5593
+ }
5594
+ function FilterCheckbox({
5595
+ label,
5596
+ config: {
5597
+ default_value,
5598
+ ...rest
5599
+ },
5600
+ value,
5601
+ onChange
5602
+ }) {
5603
+ return /* @__PURE__ */ jsxs(Box, {
5604
+ children: [/* @__PURE__ */ jsx(Text, {
5605
+ children: "\xA0"
5606
+ }), /* @__PURE__ */ jsx(Checkbox, {
5607
+ label,
5608
+ checked: value,
5609
+ onChange: (event) => onChange(event.currentTarget.checked),
5610
+ ...rest
5611
+ })]
5612
+ });
5613
+ }
5614
+ function FilterDateRange({
5615
+ label,
5616
+ config,
5617
+ value,
5618
+ onChange
5619
+ }) {
5620
+ return /* @__PURE__ */ jsx(DateRangePicker, {
5621
+ label,
5622
+ value,
5623
+ onChange,
5624
+ icon: /* @__PURE__ */ jsx(Calendar, {
5625
+ size: 16
5626
+ }),
5627
+ sx: {
5628
+ minWidth: "14em"
5629
+ },
5630
+ ...config
5631
+ });
5632
+ }
5633
+ function FilterMultiSelect({
5634
+ label,
5635
+ config,
5636
+ value,
5637
+ onChange
5638
+ }) {
5639
+ const usingRemoteOptions = !!config.options_query.sql;
5640
+ const {
5641
+ data: remoteOptions = [],
5642
+ loading
5643
+ } = useRequest(queryByStaticSQL(config.options_query), {
5644
+ refreshDeps: [config.options_query, usingRemoteOptions]
5645
+ });
5646
+ return /* @__PURE__ */ jsx(MultiSelect, {
5647
+ label,
5648
+ data: usingRemoteOptions ? remoteOptions : config.static_options,
5649
+ disabled: usingRemoteOptions ? loading : false,
5650
+ value,
5651
+ onChange
5652
+ });
5653
+ }
5654
+ function FilterSelect({
5655
+ label,
5656
+ config,
5657
+ value,
5658
+ onChange
5659
+ }) {
5660
+ const usingRemoteOptions = !!config.options_query.sql;
5661
+ const {
5662
+ data: remoteOptions = [],
5663
+ loading
5664
+ } = useRequest(queryByStaticSQL(config.options_query), {
5665
+ refreshDeps: [config.options_query, usingRemoteOptions]
5666
+ });
5667
+ return /* @__PURE__ */ jsx(Select, {
5668
+ label,
5669
+ data: usingRemoteOptions ? remoteOptions : config.static_options,
5670
+ disabled: usingRemoteOptions ? loading : false,
5671
+ value,
5672
+ onChange
5673
+ });
5674
+ }
5675
+ function FilterTextInput({
5676
+ label,
5677
+ config,
5678
+ value,
5679
+ onChange
5680
+ }) {
5681
+ return /* @__PURE__ */ jsx(TextInput, {
5682
+ label,
5683
+ value,
5684
+ onChange,
5685
+ ...config
5686
+ });
5687
+ }
5688
+ function renderFilter({
5689
+ type,
5690
+ config,
5691
+ ...rest
5692
+ }, formFieldProps) {
5693
+ switch (type) {
5694
+ case "select":
5695
+ return /* @__PURE__ */ jsx(FilterSelect, {
5696
+ ...rest,
5697
+ ...formFieldProps,
5698
+ config
5699
+ });
5700
+ case "multi-select":
5701
+ return /* @__PURE__ */ jsx(FilterMultiSelect, {
5702
+ ...rest,
5703
+ ...formFieldProps,
5704
+ config
5705
+ });
5706
+ case "text-input":
5707
+ return /* @__PURE__ */ jsx(FilterTextInput, {
5708
+ ...rest,
5709
+ ...formFieldProps,
5710
+ config
5711
+ });
5712
+ case "date-range":
5713
+ return /* @__PURE__ */ jsx(FilterDateRange, {
5714
+ ...rest,
5715
+ ...formFieldProps,
5716
+ config
5717
+ });
5718
+ case "checkbox":
5719
+ return /* @__PURE__ */ jsx(FilterCheckbox, {
5720
+ ...rest,
5721
+ ...formFieldProps,
5722
+ config
5723
+ });
5724
+ default:
5725
+ return null;
5726
+ }
5727
+ }
5728
+ const Filter = React.forwardRef(function _Filter({
5729
+ filter,
5730
+ ...formFieldProps
5731
+ }, ref) {
5732
+ return /* @__PURE__ */ jsx("div", {
5733
+ className: "filter-root",
5734
+ ref,
5735
+ children: /* @__PURE__ */ jsx(ErrorBoundary, {
5736
+ children: renderFilter(filter, formFieldProps)
5737
+ })
5738
+ });
5739
+ });
5740
+ function PreviewFilter({
5741
+ filter,
5742
+ index: index2,
5743
+ watch
5744
+ }) {
5745
+ const defaultValue = filter.config.default_value;
5746
+ const [value, setValue] = React.useState(defaultValue);
5747
+ React.useEffect(() => {
5748
+ setValue(defaultValue);
5749
+ }, [defaultValue]);
5750
+ return /* @__PURE__ */ jsxs(Box, {
5751
+ sx: {
5752
+ maxWidth: "30em"
5753
+ },
5754
+ children: [/* @__PURE__ */ jsx(Text, {
5755
+ pb: "md",
5756
+ color: "gray",
5757
+ children: "Preview"
5758
+ }), /* @__PURE__ */ jsx(Filter, {
5759
+ filter,
5760
+ value,
5761
+ onChange: setValue
5762
+ }), /* @__PURE__ */ jsx("pre", {
5763
+ children: JSON.stringify(filter, null, 4)
5764
+ })]
5765
+ });
5766
+ }
5767
+ const editors = {
5768
+ "select": FilterEditorSelect,
5769
+ "multi-select": FilterEditorMultiSelect,
5770
+ "text-input": FilterEditorTextInput,
5771
+ "checkbox": FilterEditorCheckbox,
5772
+ "date-range": FilterEditorDateRange
5773
+ };
5774
+ const filterTypeOptions = [{
5775
+ label: "Select",
5776
+ value: "select"
5777
+ }, {
5778
+ label: "Multi Select",
5779
+ value: "multi-select"
5780
+ }, {
5781
+ label: "Text Input",
5782
+ value: "text-input"
5783
+ }, {
5784
+ label: "Checkbox",
5785
+ value: "checkbox"
5786
+ }, {
5787
+ label: "Date Range",
5788
+ value: "date-range"
5789
+ }];
5790
+ function FilterSetting({
5791
+ field,
5792
+ index: index2,
5793
+ control,
5794
+ watch
5795
+ }) {
5796
+ const FilterEditor = React.useMemo(() => {
5797
+ return editors[field.type];
5798
+ }, [field.type]);
5799
+ return /* @__PURE__ */ jsxs(SimpleGrid, {
5800
+ cols: 2,
5801
+ children: [/* @__PURE__ */ jsxs(Box, {
5802
+ pl: "md",
5803
+ children: [/* @__PURE__ */ jsx(Text, {
5804
+ pb: "md",
5805
+ color: "gray",
5806
+ children: "Edit"
5807
+ }), /* @__PURE__ */ jsxs(Stack, {
5808
+ sx: {
5809
+ maxWidth: "30em"
5810
+ },
5811
+ children: [/* @__PURE__ */ jsx(Controller, {
5812
+ name: `filters.${index2}.order`,
5813
+ control,
5814
+ render: ({
5815
+ field: field2
5816
+ }) => /* @__PURE__ */ jsx(TextInput, {
5817
+ label: "Placement Order",
5818
+ required: true,
5819
+ ...field2
5820
+ })
5821
+ }), /* @__PURE__ */ jsx(Controller, {
5822
+ name: `filters.${index2}.key`,
5823
+ control,
5824
+ render: ({
5825
+ field: field2
5826
+ }) => /* @__PURE__ */ jsx(TextInput, {
5827
+ label: "Key",
5828
+ placeholder: "A unique key to refer",
5829
+ required: true,
5830
+ ...field2
5831
+ })
5832
+ }), /* @__PURE__ */ jsx(Controller, {
5833
+ name: `filters.${index2}.label`,
5834
+ control,
5835
+ render: ({
5836
+ field: field2
5837
+ }) => /* @__PURE__ */ jsx(TextInput, {
5838
+ label: "Label",
5839
+ placeholder: "Label for this field",
5840
+ required: true,
5841
+ ...field2
5842
+ })
5843
+ }), /* @__PURE__ */ jsx(Controller, {
5844
+ name: `filters.${index2}.type`,
5845
+ control,
5846
+ render: ({
5847
+ field: field2
5848
+ }) => /* @__PURE__ */ jsx(Select, {
5849
+ label: "Widget",
5850
+ data: filterTypeOptions,
5851
+ required: true,
5852
+ ...field2
5853
+ })
5854
+ }), /* @__PURE__ */ jsx(FilterEditor, {
5855
+ field,
5856
+ index: index2,
5857
+ control,
5858
+ watch
5859
+ })]
5860
+ })]
5861
+ }), /* @__PURE__ */ jsx(PreviewFilter, {
5862
+ filter: field,
5863
+ index: index2,
5864
+ watch
5865
+ })]
5866
+ });
5867
+ }
5868
+ function FilterSettings({
5869
+ filters,
5870
+ setFilters
5871
+ }) {
5872
+ var _a;
5873
+ const {
5874
+ control,
5875
+ handleSubmit,
5876
+ watch,
5877
+ setValue
5878
+ } = useForm({
5879
+ defaultValues: {
5880
+ filters: filters != null ? filters : []
5881
+ }
5882
+ });
5883
+ const {
5884
+ fields,
5885
+ append,
5886
+ remove,
5887
+ replace
5888
+ } = useFieldArray({
5889
+ control,
5890
+ name: "filters"
5891
+ });
5892
+ const watchFieldArray = watch("filters");
5893
+ const controlledFields = fields.map((field, index2) => {
5894
+ return {
5895
+ ...field,
5896
+ ...watchFieldArray[index2]
5897
+ };
5898
+ });
5899
+ const addFilter = () => {
5900
+ const key = randomId();
5901
+ const filter = {
5902
+ key,
5903
+ label: key,
5904
+ order: filters.length + 1,
5905
+ type: "text-input",
5906
+ config: {
5907
+ required: false,
5908
+ default_value: ""
5909
+ }
5910
+ };
5911
+ append(filter);
5912
+ };
5913
+ const removeFilter = (index2) => {
5914
+ remove(index2);
5915
+ };
5916
+ const revert = React.useCallback(() => {
5917
+ replace(filters);
5918
+ }, [filters]);
5919
+ const notChanged = _.isEqual(filters, watchFieldArray);
5920
+ const submit = React.useCallback(({
5921
+ filters: filters2
5922
+ }) => {
5923
+ setFilters(filters2);
5924
+ }, [setFilters]);
5925
+ return /* @__PURE__ */ jsx(Group, {
5926
+ sx: {
5927
+ height: "90vh",
5928
+ maxHeight: "calc(100vh - 185px)"
5929
+ },
5930
+ p: 0,
5931
+ children: /* @__PURE__ */ jsxs("form", {
5932
+ onSubmit: handleSubmit(submit),
5933
+ style: {
5934
+ height: "100%",
5935
+ width: "100%"
5936
+ },
5937
+ children: [/* @__PURE__ */ jsxs(Group, {
5938
+ sx: {
5939
+ position: "absolute",
5940
+ top: "16px",
5941
+ right: "16px"
5942
+ },
5943
+ children: [/* @__PURE__ */ jsx(Button, {
5944
+ size: "xs",
5945
+ color: "green",
5946
+ leftIcon: /* @__PURE__ */ jsx(DeviceFloppy, {
5947
+ size: 20
5948
+ }),
5949
+ type: "submit",
5950
+ disabled: notChanged,
5951
+ children: "Save Changes"
5952
+ }), /* @__PURE__ */ jsx(Button, {
5953
+ size: "xs",
5954
+ color: "red",
5955
+ leftIcon: /* @__PURE__ */ jsx(Recycle, {
5956
+ size: 20
5957
+ }),
5958
+ disabled: notChanged,
5959
+ onClick: revert,
5960
+ children: "Revert Changes"
5961
+ })]
5962
+ }), /* @__PURE__ */ jsx(Tabs, {
5963
+ orientation: "vertical",
5964
+ defaultValue: (_a = controlledFields[0]) == null ? void 0 : _a.id,
5965
+ children: /* @__PURE__ */ jsxs(Group, {
5966
+ sx: {
5967
+ height: "100%"
5968
+ },
5969
+ children: [/* @__PURE__ */ jsxs(Stack, {
5970
+ sx: {
5971
+ height: "100%"
5972
+ },
5973
+ children: [/* @__PURE__ */ jsx(Tabs.List, {
5974
+ position: "left",
5975
+ sx: {
5976
+ flexGrow: 1
5977
+ },
5978
+ children: controlledFields.map((field, index2) => /* @__PURE__ */ jsx(Tabs.Tab, {
5979
+ value: field.id,
5980
+ children: field.label
5981
+ }, field.id))
5982
+ }), /* @__PURE__ */ jsx(Button, {
5983
+ size: "xs",
5984
+ color: "blue",
5985
+ leftIcon: /* @__PURE__ */ jsx(PlaylistAdd, {
5986
+ size: 20
5987
+ }),
5988
+ onClick: addFilter,
5989
+ children: "Add a Filter"
5990
+ })]
5991
+ }), /* @__PURE__ */ jsx(Box, {
5992
+ sx: {
5993
+ flexGrow: 1,
5994
+ height: "100%"
5995
+ },
5996
+ children: controlledFields.map((field, index2) => /* @__PURE__ */ jsx(Tabs.Panel, {
5997
+ value: field.id,
5998
+ sx: {
5999
+ height: "100%"
6000
+ },
6001
+ children: /* @__PURE__ */ jsxs(Stack, {
6002
+ sx: {
6003
+ height: "100%"
6004
+ },
6005
+ spacing: "sm",
6006
+ children: [/* @__PURE__ */ jsx(Box, {
6007
+ sx: {
6008
+ flexGrow: 1,
6009
+ maxHeight: "calc(100% - 52px)",
6010
+ overflow: "scroll"
6011
+ },
6012
+ children: /* @__PURE__ */ jsx(FilterSetting, {
6013
+ field,
6014
+ index: index2,
6015
+ control,
6016
+ watch
6017
+ })
6018
+ }), /* @__PURE__ */ jsx(Group, {
6019
+ position: "right",
6020
+ pt: 10,
6021
+ children: /* @__PURE__ */ jsx(Button, {
6022
+ size: "xs",
6023
+ color: "red",
6024
+ leftIcon: /* @__PURE__ */ jsx(Trash, {
6025
+ size: 20
6026
+ }),
6027
+ onClick: () => removeFilter(index2),
6028
+ children: "Delete this filter"
6029
+ })
6030
+ })]
6031
+ })
6032
+ }, field.id))
6033
+ })]
6034
+ })
6035
+ })]
6036
+ })
6037
+ });
6038
+ }
6039
+ function FilterSettingsModal({
6040
+ opened,
6041
+ close,
6042
+ filters,
6043
+ setFilters
6044
+ }) {
6045
+ const {
6046
+ freezeLayout
6047
+ } = React.useContext(LayoutStateContext);
6048
+ React.useEffect(() => {
6049
+ freezeLayout(opened);
6050
+ }, [opened]);
6051
+ return /* @__PURE__ */ jsx(Modal, {
6052
+ size: "96vw",
6053
+ overflow: "inside",
6054
+ opened,
6055
+ onClose: close,
6056
+ title: "Filters",
6057
+ trapFocus: true,
6058
+ onDragStart: (e) => {
6059
+ e.stopPropagation();
6060
+ },
6061
+ withCloseButton: false,
6062
+ children: /* @__PURE__ */ jsx(FilterSettings, {
6063
+ filters,
6064
+ setFilters
6065
+ })
6066
+ });
6067
+ }
6068
+ function DashboardActions({
6069
+ mode,
6070
+ setMode,
6071
+ hasChanges,
6072
+ saveChanges,
6073
+ revertChanges,
6074
+ getCurrentSchema,
6075
+ filters,
6076
+ setFilters
6077
+ }) {
6078
+ const {
6079
+ addPanel
6080
+ } = React.useContext(DashboardActionContext);
6081
+ const {
6082
+ inLayoutMode,
6083
+ inEditMode,
6084
+ inUseMode
6085
+ } = React.useContext(LayoutStateContext);
6086
+ const [dataEditorOpened, setDataEditorOpened] = React.useState(false);
6087
+ const openQueries = () => setDataEditorOpened(true);
6088
+ const closeQueries = () => setDataEditorOpened(false);
6089
+ const [filtersOpened, setFiltersOpened] = React.useState(false);
6090
+ const openFilters = () => setFiltersOpened(true);
6091
+ const closeFilters = () => setFiltersOpened(false);
6092
+ const [schemaOpened, setSchemaOpened] = React.useState(false);
6093
+ const openSchema = () => setSchemaOpened(true);
6094
+ const closeSchema = () => setSchemaOpened(false);
5617
6095
  return /* @__PURE__ */ jsxs(Group, {
5618
- direction: "column",
5619
- grow: true,
6096
+ position: "apart",
6097
+ pt: 0,
6098
+ pb: "xs",
6099
+ children: [/* @__PURE__ */ jsx(Group, {
6100
+ position: "left",
6101
+ children: /* @__PURE__ */ jsx(ModeToggler, {
6102
+ mode,
6103
+ setMode
6104
+ })
6105
+ }), /* @__PURE__ */ jsxs(Group, {
6106
+ position: "right",
6107
+ children: [!inUseMode && /* @__PURE__ */ jsx(Button, {
6108
+ variant: "default",
6109
+ size: "xs",
6110
+ onClick: addPanel,
6111
+ leftIcon: /* @__PURE__ */ jsx(PlaylistAdd, {
6112
+ size: 20
6113
+ }),
6114
+ children: "Add a Panel"
6115
+ }), inEditMode && /* @__PURE__ */ jsx(Button, {
6116
+ variant: "default",
6117
+ size: "xs",
6118
+ onClick: openFilters,
6119
+ leftIcon: /* @__PURE__ */ jsx(Filter$1, {
6120
+ size: 20
6121
+ }),
6122
+ children: "Filters"
6123
+ }), inEditMode && /* @__PURE__ */ jsx(Button, {
6124
+ variant: "default",
6125
+ size: "xs",
6126
+ onClick: openQueries,
6127
+ leftIcon: /* @__PURE__ */ jsx(Database, {
6128
+ size: 20
6129
+ }),
6130
+ children: "Data Settings"
6131
+ }), !inUseMode && /* @__PURE__ */ jsx(Button, {
6132
+ variant: "default",
6133
+ size: "xs",
6134
+ onClick: saveChanges,
6135
+ disabled: !hasChanges,
6136
+ leftIcon: /* @__PURE__ */ jsx(DeviceFloppy, {
6137
+ size: 20
6138
+ }),
6139
+ children: "Save Changes"
6140
+ }), !inUseMode && /* @__PURE__ */ jsx(Button, {
6141
+ color: "red",
6142
+ size: "xs",
6143
+ disabled: !hasChanges,
6144
+ onClick: revertChanges,
6145
+ leftIcon: /* @__PURE__ */ jsx(Recycle, {
6146
+ size: 20
6147
+ }),
6148
+ children: "Revert Changes"
6149
+ }), /* @__PURE__ */ jsxs(Menu, {
6150
+ children: [/* @__PURE__ */ jsx(Menu.Target, {
6151
+ children: /* @__PURE__ */ jsx(Button, {
6152
+ variant: "default",
6153
+ size: "xs",
6154
+ leftIcon: /* @__PURE__ */ jsx(Share, {
6155
+ size: 20
6156
+ }),
6157
+ children: "Export"
6158
+ })
6159
+ }), /* @__PURE__ */ jsxs(Menu.Dropdown, {
6160
+ children: [/* @__PURE__ */ jsx(Menu.Item, {
6161
+ disabled: true,
6162
+ children: "Download Data"
6163
+ }), /* @__PURE__ */ jsx(Menu.Item, {
6164
+ onClick: openSchema,
6165
+ children: "View Schema"
6166
+ })]
6167
+ })]
6168
+ })]
6169
+ }), /* @__PURE__ */ jsx(FilterSettingsModal, {
6170
+ opened: filtersOpened,
6171
+ close: closeFilters,
6172
+ filters,
6173
+ setFilters
6174
+ }), /* @__PURE__ */ jsx(DataEditorModal, {
6175
+ opened: dataEditorOpened,
6176
+ close: closeQueries
6177
+ }), /* @__PURE__ */ jsx(ViewSchemaModal, {
6178
+ opened: schemaOpened,
6179
+ close: closeSchema,
6180
+ getCurrentSchema
6181
+ })]
6182
+ });
6183
+ }
6184
+ function FullScreenPanel({
6185
+ panel,
6186
+ exitFullScreen
6187
+ }) {
6188
+ return /* @__PURE__ */ jsxs(Stack, {
5620
6189
  sx: {
5621
6190
  flexGrow: 1,
5622
6191
  justifyContent: "flex-start"
5623
6192
  },
5624
6193
  children: [/* @__PURE__ */ jsx(Group, {
5625
- direction: "row",
5626
6194
  sx: {
5627
6195
  flexGrow: 0
5628
6196
  },
@@ -5666,6 +6234,77 @@ function usePanelFullScreen(panels) {
5666
6234
  fullScreenPanel
5667
6235
  };
5668
6236
  }
6237
+ function Filters({
6238
+ filters,
6239
+ filterValues,
6240
+ setFilterValues
6241
+ }) {
6242
+ const {
6243
+ control,
6244
+ handleSubmit
6245
+ } = useForm({
6246
+ defaultValues: filterValues
6247
+ });
6248
+ const filtersInOrder = React.useMemo(() => {
6249
+ return _.sortBy(filters, "order");
6250
+ }, [filters]);
6251
+ if (filters.length === 0) {
6252
+ return null;
6253
+ }
6254
+ return /* @__PURE__ */ jsx("form", {
6255
+ onSubmit: handleSubmit(setFilterValues),
6256
+ children: /* @__PURE__ */ jsxs(Group, {
6257
+ className: "dashboard-filters",
6258
+ position: "apart",
6259
+ p: "md",
6260
+ mb: "md",
6261
+ noWrap: true,
6262
+ sx: {
6263
+ boxShadow: "0px 0px 10px 0px rgba(0,0,0,.2)"
6264
+ },
6265
+ children: [/* @__PURE__ */ jsx(Group, {
6266
+ align: "flex-start",
6267
+ children: filtersInOrder.map((filter) => /* @__PURE__ */ jsx(Controller, {
6268
+ name: filter.key,
6269
+ control,
6270
+ render: ({
6271
+ field
6272
+ }) => /* @__PURE__ */ jsx(Filter, {
6273
+ filter,
6274
+ ...field
6275
+ })
6276
+ }, filter.key))
6277
+ }), /* @__PURE__ */ jsx(Group, {
6278
+ sx: {
6279
+ alignSelf: "flex-end"
6280
+ },
6281
+ children: /* @__PURE__ */ jsx(Button, {
6282
+ color: "blue",
6283
+ size: "sm",
6284
+ type: "submit",
6285
+ children: "Submit"
6286
+ })
6287
+ })]
6288
+ })
6289
+ });
6290
+ }
6291
+ function useFilters(dashboard) {
6292
+ const [filters, setFilters] = React.useState(dashboard.filters);
6293
+ const [filterValues, setFilterValues] = React.useState(() => {
6294
+ const filters2 = dashboard.filters;
6295
+ return filters2.reduce((ret, filter) => {
6296
+ var _a;
6297
+ ret[filter.key] = (_a = filter.config.default_value) != null ? _a : "";
6298
+ return ret;
6299
+ }, {});
6300
+ });
6301
+ return {
6302
+ filters,
6303
+ setFilters,
6304
+ filterValues,
6305
+ setFilterValues
6306
+ };
6307
+ }
5669
6308
  function Dashboard({
5670
6309
  context,
5671
6310
  dashboard,
@@ -5677,11 +6316,20 @@ function Dashboard({
5677
6316
  APIClient.baseURL = config.apiBaseURL;
5678
6317
  }
5679
6318
  const [layoutFrozen, freezeLayout] = React.useState(false);
6319
+ const [mode, setMode] = React.useState(DashboardMode.Edit);
5680
6320
  const [panels, setPanels] = React.useState(dashboard.panels);
5681
6321
  const [sqlSnippets, setSQLSnippets] = React.useState(dashboard.definition.sqlSnippets);
5682
6322
  const [queries, setQueries] = React.useState(dashboard.definition.queries);
5683
- const [mode, setMode] = React.useState(DashboardMode.Use);
6323
+ const {
6324
+ filters,
6325
+ setFilters,
6326
+ filterValues,
6327
+ setFilterValues
6328
+ } = useFilters(dashboard);
5684
6329
  const hasChanges = React.useMemo(() => {
6330
+ if (!_.isEqual(filters, dashboard.filters)) {
6331
+ return true;
6332
+ }
5685
6333
  const cleanJSON = (v) => JSON.parse(JSON.stringify(v));
5686
6334
  const panelsEqual = _.isEqual(cleanJSON(panels), cleanJSON(dashboard.panels));
5687
6335
  if (!panelsEqual) {
@@ -5691,10 +6339,11 @@ function Dashboard({
5691
6339
  return true;
5692
6340
  }
5693
6341
  return !_.isEqual(queries, dashboard.definition.queries);
5694
- }, [dashboard, panels, sqlSnippets, queries]);
6342
+ }, [dashboard, filters, panels, sqlSnippets, queries]);
5695
6343
  const saveDashboardChanges = async () => {
5696
6344
  const d = {
5697
6345
  ...dashboard,
6346
+ filters,
5698
6347
  panels,
5699
6348
  definition: {
5700
6349
  sqlSnippets,
@@ -5704,6 +6353,7 @@ function Dashboard({
5704
6353
  await update(d);
5705
6354
  };
5706
6355
  const revertDashboardChanges = () => {
6356
+ setFilters(dashboard.filters);
5707
6357
  setPanels(dashboard.panels);
5708
6358
  setSQLSnippets(dashboard.definition.sqlSnippets);
5709
6359
  setQueries(dashboard.definition.queries);
@@ -5722,7 +6372,7 @@ function Dashboard({
5722
6372
  description: "<p><br></p>",
5723
6373
  queryID: "",
5724
6374
  viz: {
5725
- type: "text",
6375
+ type: "table",
5726
6376
  conf: {}
5727
6377
  }
5728
6378
  };
@@ -5782,48 +6432,57 @@ function Dashboard({
5782
6432
  return /* @__PURE__ */ jsx(ModalsProvider, {
5783
6433
  children: /* @__PURE__ */ jsx(ContextInfoContext.Provider, {
5784
6434
  value: context,
5785
- children: /* @__PURE__ */ jsx(DashboardActionContext.Provider, {
5786
- value: {
5787
- addPanel,
5788
- duplidatePanel,
5789
- removePanelByID,
5790
- viewPanelInFullScreen,
5791
- inFullScreen
5792
- },
5793
- children: /* @__PURE__ */ jsx(DefinitionContext.Provider, {
5794
- value: definitions,
5795
- children: /* @__PURE__ */ jsxs(LayoutStateContext.Provider, {
5796
- value: {
5797
- layoutFrozen,
5798
- freezeLayout,
5799
- mode,
5800
- inEditMode,
5801
- inLayoutMode,
5802
- inUseMode
5803
- },
5804
- children: [inFullScreen && /* @__PURE__ */ jsx(FullScreenPanel, {
5805
- panel: fullScreenPanel,
5806
- exitFullScreen
5807
- }), /* @__PURE__ */ jsxs(Box, {
5808
- className,
5809
- sx: {
5810
- position: "relative",
5811
- display: inFullScreen ? "none" : "block"
5812
- },
5813
- children: [/* @__PURE__ */ jsx(DashboardActions, {
6435
+ children: /* @__PURE__ */ jsx(FilterValuesContext.Provider, {
6436
+ value: filterValues,
6437
+ children: /* @__PURE__ */ jsx(DashboardActionContext.Provider, {
6438
+ value: {
6439
+ addPanel,
6440
+ duplidatePanel,
6441
+ removePanelByID,
6442
+ viewPanelInFullScreen,
6443
+ inFullScreen
6444
+ },
6445
+ children: /* @__PURE__ */ jsx(DefinitionContext.Provider, {
6446
+ value: definitions,
6447
+ children: /* @__PURE__ */ jsxs(LayoutStateContext.Provider, {
6448
+ value: {
6449
+ layoutFrozen,
6450
+ freezeLayout,
5814
6451
  mode,
5815
- setMode,
5816
- hasChanges,
5817
- saveChanges: saveDashboardChanges,
5818
- revertChanges: revertDashboardChanges,
5819
- getCurrentSchema
5820
- }), /* @__PURE__ */ jsx(DashboardLayout, {
5821
- panels,
5822
- setPanels,
5823
- isDraggable: inLayoutMode,
5824
- isResizable: inLayoutMode
6452
+ inEditMode,
6453
+ inLayoutMode,
6454
+ inUseMode
6455
+ },
6456
+ children: [inFullScreen && /* @__PURE__ */ jsx(FullScreenPanel, {
6457
+ panel: fullScreenPanel,
6458
+ exitFullScreen
6459
+ }), /* @__PURE__ */ jsxs(Box, {
6460
+ className,
6461
+ sx: {
6462
+ position: "relative",
6463
+ display: inFullScreen ? "none" : "block"
6464
+ },
6465
+ children: [/* @__PURE__ */ jsx(DashboardActions, {
6466
+ mode,
6467
+ setMode,
6468
+ hasChanges,
6469
+ saveChanges: saveDashboardChanges,
6470
+ revertChanges: revertDashboardChanges,
6471
+ getCurrentSchema,
6472
+ filters,
6473
+ setFilters
6474
+ }), /* @__PURE__ */ jsx(Filters, {
6475
+ filters,
6476
+ filterValues,
6477
+ setFilterValues
6478
+ }), /* @__PURE__ */ jsx(DashboardLayout, {
6479
+ panels,
6480
+ setPanels,
6481
+ isDraggable: inLayoutMode,
6482
+ isResizable: inLayoutMode
6483
+ })]
5825
6484
  })]
5826
- })]
6485
+ })
5827
6486
  })
5828
6487
  })
5829
6488
  })
@@ -5837,7 +6496,7 @@ function ReadOnlyDashboardLayout({
5837
6496
  rowHeight = 10
5838
6497
  }) {
5839
6498
  return /* @__PURE__ */ jsx(ReactGridLayout, {
5840
- className,
6499
+ className: `dashboard-layout ${className}`,
5841
6500
  rowHeight,
5842
6501
  isDraggable: false,
5843
6502
  isResizable: false,
@@ -5864,6 +6523,11 @@ function ReadOnlyDashboard({
5864
6523
  if (APIClient.baseURL !== config.apiBaseURL) {
5865
6524
  APIClient.baseURL = config.apiBaseURL;
5866
6525
  }
6526
+ const {
6527
+ filters,
6528
+ filterValues,
6529
+ setFilterValues
6530
+ } = useFilters(dashboard);
5867
6531
  const definition = React.useMemo(() => ({
5868
6532
  ...dashboard.definition,
5869
6533
  setSQLSnippets: () => {
@@ -5880,42 +6544,49 @@ function ReadOnlyDashboard({
5880
6544
  return /* @__PURE__ */ jsx(ModalsProvider, {
5881
6545
  children: /* @__PURE__ */ jsx(ContextInfoContext.Provider, {
5882
6546
  value: context,
5883
- children: /* @__PURE__ */ jsx(DashboardActionContext.Provider, {
5884
- value: {
5885
- addPanel: _.noop,
5886
- duplidatePanel: _.noop,
5887
- removePanelByID: _.noop,
5888
- viewPanelInFullScreen,
5889
- inFullScreen
5890
- },
5891
- children: /* @__PURE__ */ jsx(DefinitionContext.Provider, {
5892
- value: definition,
5893
- children: /* @__PURE__ */ jsxs(LayoutStateContext.Provider, {
5894
- value: {
5895
- layoutFrozen: true,
5896
- freezeLayout: () => {
5897
- },
5898
- mode: DashboardMode.Use,
5899
- inEditMode: false,
5900
- inLayoutMode: false,
5901
- inUseMode: true
5902
- },
5903
- children: [inFullScreen && /* @__PURE__ */ jsx(FullScreenPanel, {
5904
- panel: fullScreenPanel,
5905
- exitFullScreen
5906
- }), /* @__PURE__ */ jsx(Box, {
5907
- className,
5908
- sx: {
5909
- display: inFullScreen ? "none" : "block"
6547
+ children: /* @__PURE__ */ jsx(FilterValuesContext.Provider, {
6548
+ value: filterValues,
6549
+ children: /* @__PURE__ */ jsx(DashboardActionContext.Provider, {
6550
+ value: {
6551
+ addPanel: _.noop,
6552
+ duplidatePanel: _.noop,
6553
+ removePanelByID: _.noop,
6554
+ viewPanelInFullScreen,
6555
+ inFullScreen
6556
+ },
6557
+ children: /* @__PURE__ */ jsx(DefinitionContext.Provider, {
6558
+ value: definition,
6559
+ children: /* @__PURE__ */ jsxs(LayoutStateContext.Provider, {
6560
+ value: {
6561
+ layoutFrozen: true,
6562
+ freezeLayout: () => {
6563
+ },
6564
+ mode: DashboardMode.Use,
6565
+ inEditMode: false,
6566
+ inLayoutMode: false,
6567
+ inUseMode: true
5910
6568
  },
5911
- children: /* @__PURE__ */ jsx(ReadOnlyDashboardLayout, {
5912
- panels: dashboard.panels
5913
- })
5914
- })]
6569
+ children: [inFullScreen && /* @__PURE__ */ jsx(FullScreenPanel, {
6570
+ panel: fullScreenPanel,
6571
+ exitFullScreen
6572
+ }), /* @__PURE__ */ jsxs(Box, {
6573
+ className,
6574
+ sx: {
6575
+ display: inFullScreen ? "none" : "block"
6576
+ },
6577
+ children: [/* @__PURE__ */ jsx(Filters, {
6578
+ filters,
6579
+ filterValues,
6580
+ setFilterValues
6581
+ }), /* @__PURE__ */ jsx(ReadOnlyDashboardLayout, {
6582
+ panels: dashboard.panels
6583
+ })]
6584
+ })]
6585
+ })
5915
6586
  })
5916
6587
  })
5917
6588
  })
5918
6589
  })
5919
6590
  });
5920
6591
  }
5921
- export { ContextInfoContext, Dashboard, DashboardLayout, DashboardMode, DefinitionContext, LayoutStateContext, Panel, PanelContext, ReadOnlyDashboard, initialContextInfoContext };
6592
+ export { ContextInfoContext, Dashboard, DashboardLayout, DashboardMode, DefinitionContext, FilterValuesContext, LayoutStateContext, Panel, PanelContext, ReadOnlyDashboard, initialContextInfoContext, initialFilterValuesContext };