@devtable/dashboard 1.26.0 → 1.29.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.
@@ -33,15 +33,15 @@ var __publicField = (obj, key, value) => {
33
33
  __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
34
34
  return value;
35
35
  };
36
- import React from "react";
36
+ import React, { createContext, useContext, useReducer } from "react";
37
37
  import _ from "lodash";
38
38
  import RGL, { WidthProvider } from "react-grid-layout";
39
- 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";
39
+ import { Box, Group, Button, Modal, Popover, Tooltip, Text, ActionIcon, TextInput, LoadingOverlay, Table, Select, useMantineTheme, ColorSwatch, Switch, Slider, SegmentedControl, NumberInput, ColorInput, Divider, Accordion, JsonInput, AppShell, Tabs, Menu, Container, Textarea } from "@mantine/core";
40
40
  import { useRequest } from "ahooks";
41
41
  import axios from "axios";
42
- import { InfoCircle, DeviceFloppy, Refresh, Trash, PlaylistAdd, Settings, Resize, Paint, PlayerPlay, Database, Recycle, Share } from "tabler-icons-react";
42
+ import { InfoCircle, DeviceFloppy, Refresh, Trash, PlaylistAdd, Settings, Copy, Resize, Paint, PlayerPlay, Database, Recycle, Share } from "tabler-icons-react";
43
43
  import RichTextEditor, { RichTextEditor as RichTextEditor$1 } from "@mantine/rte";
44
- import { useInputState, useElementSize, randomId } from "@mantine/hooks";
44
+ import { randomId, useInputState, useElementSize } from "@mantine/hooks";
45
45
  import ReactEChartsCore from "echarts-for-react/lib/core";
46
46
  import * as echarts from "echarts/core";
47
47
  import { SunburstChart, BarChart, LineChart, ScatterChart, PieChart } from "echarts/charts";
@@ -58,7 +58,7 @@ var DashboardMode = /* @__PURE__ */ ((DashboardMode2) => {
58
58
  DashboardMode2["Edit"] = "edit";
59
59
  return DashboardMode2;
60
60
  })(DashboardMode || {});
61
- const initialContext$3 = {
61
+ const initialContext$4 = {
62
62
  layoutFrozen: false,
63
63
  freezeLayout: () => {
64
64
  },
@@ -67,7 +67,7 @@ const initialContext$3 = {
67
67
  inLayoutMode: false,
68
68
  inUseMode: true
69
69
  };
70
- const LayoutStateContext = React.createContext(initialContext$3);
70
+ const LayoutStateContext = React.createContext(initialContext$4);
71
71
  function explainSQLSnippet(snippet, context) {
72
72
  const names = Object.keys(context);
73
73
  const vals = Object.values(context);
@@ -146,26 +146,27 @@ const queryBySQL = ({ context, definitions, title, query }) => async () => {
146
146
  console.log(formattedSQL);
147
147
  console.groupEnd();
148
148
  }
149
- const res = await APIClient.getRequest("POST")("/query", { type, key, sql: formattedSQL });
149
+ const res = await APIClient.getRequest("POST")("/query", { type, key, query: formattedSQL });
150
150
  return res;
151
151
  } catch (error) {
152
152
  console.error(error);
153
153
  return [];
154
154
  }
155
155
  };
156
- async function getQuerySources() {
156
+ async function listDataSources() {
157
157
  try {
158
- const res = await APIClient.getRequest("GET")("/query/sources", {});
158
+ const res = await APIClient.getRequest("GET")("/datasource/list", {});
159
159
  return res;
160
160
  } catch (error) {
161
161
  console.error(error);
162
162
  return {};
163
163
  }
164
164
  }
165
- const initialContext$2 = {};
166
- const initialContextInfoContext = initialContext$2;
167
- const ContextInfoContext = React.createContext(initialContext$2);
168
- const initialContext$1 = {
165
+ const initialContext$3 = {};
166
+ const initialContextInfoContext = initialContext$3;
167
+ const ContextInfoContext = React.createContext(initialContext$3);
168
+ const initialContext$2 = {
169
+ id: "",
169
170
  data: [],
170
171
  loading: false,
171
172
  title: "",
@@ -186,16 +187,96 @@ const initialContext$1 = {
186
187
  refreshData: () => {
187
188
  }
188
189
  };
189
- const PanelContext = React.createContext(initialContext$1);
190
- const initialContext = {
191
- sqlSnippets: [],
192
- setSQLSnippets: () => {
193
- },
194
- queries: [],
195
- setQueries: () => {
190
+ const PanelContext = React.createContext(initialContext$2);
191
+ const ModalsContext = createContext(null);
192
+ ModalsContext.displayName = "@mantine/modals/ModalsContext";
193
+ function useModals() {
194
+ const ctx = useContext(ModalsContext);
195
+ if (!ctx) {
196
+ throw new Error("[@mantine/modals] useModals hook was called outside of context, wrap your app with ModalsProvider component");
196
197
  }
198
+ return ctx;
199
+ }
200
+ var __defProp$1 = Object.defineProperty;
201
+ var __defProps$1 = Object.defineProperties;
202
+ var __getOwnPropDescs$1 = Object.getOwnPropertyDescriptors;
203
+ var __getOwnPropSymbols$1 = Object.getOwnPropertySymbols;
204
+ var __hasOwnProp$1 = Object.prototype.hasOwnProperty;
205
+ var __propIsEnum$1 = Object.prototype.propertyIsEnumerable;
206
+ var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
207
+ var __spreadValues$1 = (a, b) => {
208
+ for (var prop in b || (b = {}))
209
+ if (__hasOwnProp$1.call(b, prop))
210
+ __defNormalProp$1(a, prop, b[prop]);
211
+ if (__getOwnPropSymbols$1)
212
+ for (var prop of __getOwnPropSymbols$1(b)) {
213
+ if (__propIsEnum$1.call(b, prop))
214
+ __defNormalProp$1(a, prop, b[prop]);
215
+ }
216
+ return a;
197
217
  };
198
- const DefinitionContext = React.createContext(initialContext);
218
+ var __spreadProps$1 = (a, b) => __defProps$1(a, __getOwnPropDescs$1(b));
219
+ function ConfirmModal({
220
+ id,
221
+ cancelProps,
222
+ confirmProps,
223
+ labels = { cancel: "", confirm: "" },
224
+ closeOnConfirm = true,
225
+ closeOnCancel = true,
226
+ groupProps,
227
+ onCancel,
228
+ onConfirm,
229
+ children
230
+ }) {
231
+ const { cancel: cancelLabel, confirm: confirmLabel } = labels;
232
+ const ctx = useModals();
233
+ const handleCancel = (event) => {
234
+ typeof (cancelProps == null ? void 0 : cancelProps.onClick) === "function" && (cancelProps == null ? void 0 : cancelProps.onClick(event));
235
+ typeof onCancel === "function" && onCancel();
236
+ closeOnCancel && ctx.closeModal(id);
237
+ };
238
+ const handleConfirm = (event) => {
239
+ typeof (confirmProps == null ? void 0 : confirmProps.onClick) === "function" && (confirmProps == null ? void 0 : confirmProps.onClick(event));
240
+ typeof onConfirm === "function" && onConfirm();
241
+ closeOnConfirm && ctx.closeModal(id);
242
+ };
243
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, children && /* @__PURE__ */ React.createElement(Box, {
244
+ mb: "md"
245
+ }, children), /* @__PURE__ */ React.createElement(Group, __spreadValues$1({
246
+ position: "right"
247
+ }, groupProps), /* @__PURE__ */ React.createElement(Button, __spreadProps$1(__spreadValues$1({
248
+ variant: "default"
249
+ }, cancelProps), {
250
+ onClick: handleCancel
251
+ }), (cancelProps == null ? void 0 : cancelProps.children) || cancelLabel), /* @__PURE__ */ React.createElement(Button, __spreadProps$1(__spreadValues$1({}, confirmProps), {
252
+ onClick: handleConfirm
253
+ }), (confirmProps == null ? void 0 : confirmProps.children) || confirmLabel)));
254
+ }
255
+ function modalsReducer(state, action) {
256
+ switch (action.type) {
257
+ case "OPEN": {
258
+ return {
259
+ current: action.payload,
260
+ modals: [...state.modals, action.payload]
261
+ };
262
+ }
263
+ case "CLOSE": {
264
+ return {
265
+ current: state.modals[state.modals.length - 2] || null,
266
+ modals: state.modals.filter((m2) => m2.id !== action.payload)
267
+ };
268
+ }
269
+ case "CLOSE_ALL": {
270
+ return {
271
+ current: state.current,
272
+ modals: []
273
+ };
274
+ }
275
+ default: {
276
+ return state;
277
+ }
278
+ }
279
+ }
199
280
  var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
200
281
  var jsxRuntime = { exports: {} };
201
282
  var reactJsxRuntime_production_min = {};
@@ -230,6 +311,240 @@ reactJsxRuntime_production_min.jsxs = q;
230
311
  const jsx = jsxRuntime.exports.jsx;
231
312
  const jsxs = jsxRuntime.exports.jsxs;
232
313
  const Fragment = jsxRuntime.exports.Fragment;
314
+ var __defProp2 = Object.defineProperty;
315
+ var __defProps2 = Object.defineProperties;
316
+ var __getOwnPropDescs2 = Object.getOwnPropertyDescriptors;
317
+ var __getOwnPropSymbols2 = Object.getOwnPropertySymbols;
318
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
319
+ var __propIsEnum2 = Object.prototype.propertyIsEnumerable;
320
+ var __defNormalProp2 = (obj, key, value) => key in obj ? __defProp2(obj, key, {
321
+ enumerable: true,
322
+ configurable: true,
323
+ writable: true,
324
+ value
325
+ }) : obj[key] = value;
326
+ var __spreadValues2 = (a, b) => {
327
+ for (var prop in b || (b = {}))
328
+ if (__hasOwnProp2.call(b, prop))
329
+ __defNormalProp2(a, prop, b[prop]);
330
+ if (__getOwnPropSymbols2)
331
+ for (var prop of __getOwnPropSymbols2(b)) {
332
+ if (__propIsEnum2.call(b, prop))
333
+ __defNormalProp2(a, prop, b[prop]);
334
+ }
335
+ return a;
336
+ };
337
+ var __spreadProps2 = (a, b) => __defProps2(a, __getOwnPropDescs2(b));
338
+ var __objRest2 = (source, exclude) => {
339
+ var target = {};
340
+ for (var prop in source)
341
+ if (__hasOwnProp2.call(source, prop) && exclude.indexOf(prop) < 0)
342
+ target[prop] = source[prop];
343
+ if (source != null && __getOwnPropSymbols2)
344
+ for (var prop of __getOwnPropSymbols2(source)) {
345
+ if (exclude.indexOf(prop) < 0 && __propIsEnum2.call(source, prop))
346
+ target[prop] = source[prop];
347
+ }
348
+ return target;
349
+ };
350
+ function separateConfirmModalProps(props) {
351
+ if (!props) {
352
+ return {
353
+ confirmProps: {},
354
+ modalProps: {}
355
+ };
356
+ }
357
+ const _a = props, {
358
+ id,
359
+ children,
360
+ onCancel,
361
+ onConfirm,
362
+ closeOnConfirm,
363
+ closeOnCancel,
364
+ cancelProps,
365
+ confirmProps,
366
+ groupProps,
367
+ labels
368
+ } = _a, others = __objRest2(_a, ["id", "children", "onCancel", "onConfirm", "closeOnConfirm", "closeOnCancel", "cancelProps", "confirmProps", "groupProps", "labels"]);
369
+ return {
370
+ confirmProps: {
371
+ id,
372
+ children,
373
+ onCancel,
374
+ onConfirm,
375
+ closeOnConfirm,
376
+ closeOnCancel,
377
+ cancelProps,
378
+ confirmProps,
379
+ groupProps,
380
+ labels
381
+ },
382
+ modalProps: __spreadValues2({
383
+ id
384
+ }, others)
385
+ };
386
+ }
387
+ function ModalsProvider({
388
+ children,
389
+ modalProps,
390
+ labels,
391
+ modals
392
+ }) {
393
+ const [state, dispatch] = useReducer(modalsReducer, {
394
+ modals: [],
395
+ current: null
396
+ });
397
+ const closeAll = (canceled) => {
398
+ state.modals.forEach((modal) => {
399
+ var _a, _b, _c, _d;
400
+ if (modal.type === "confirm" && canceled) {
401
+ (_b = (_a = modal.props) == null ? void 0 : _a.onCancel) == null ? void 0 : _b.call(_a);
402
+ }
403
+ (_d = (_c = modal.props) == null ? void 0 : _c.onClose) == null ? void 0 : _d.call(_c);
404
+ });
405
+ dispatch({
406
+ type: "CLOSE_ALL"
407
+ });
408
+ };
409
+ const openModal = (props) => {
410
+ const id = props.id || randomId();
411
+ dispatch({
412
+ type: "OPEN",
413
+ payload: {
414
+ id,
415
+ type: "content",
416
+ props
417
+ }
418
+ });
419
+ return id;
420
+ };
421
+ const openConfirmModal = (props) => {
422
+ const id = props.id || randomId();
423
+ dispatch({
424
+ type: "OPEN",
425
+ payload: {
426
+ id,
427
+ type: "confirm",
428
+ props
429
+ }
430
+ });
431
+ return id;
432
+ };
433
+ const openContextModal = (modal, props) => {
434
+ const id = props.id || randomId();
435
+ dispatch({
436
+ type: "OPEN",
437
+ payload: {
438
+ id,
439
+ type: "context",
440
+ props,
441
+ ctx: modal
442
+ }
443
+ });
444
+ return id;
445
+ };
446
+ const closeModal = (id, canceled) => {
447
+ var _a, _b, _c, _d;
448
+ if (state.modals.length <= 1) {
449
+ closeAll(canceled);
450
+ return;
451
+ }
452
+ const modal = state.modals.find((item) => item.id === id);
453
+ if ((modal == null ? void 0 : modal.type) === "confirm" && canceled) {
454
+ (_b = (_a = modal.props) == null ? void 0 : _a.onCancel) == null ? void 0 : _b.call(_a);
455
+ }
456
+ (_d = (_c = modal == null ? void 0 : modal.props) == null ? void 0 : _c.onClose) == null ? void 0 : _d.call(_c);
457
+ dispatch({
458
+ type: "CLOSE",
459
+ payload: modal.id
460
+ });
461
+ };
462
+ const ctx = {
463
+ modals: state.modals,
464
+ openModal,
465
+ openConfirmModal,
466
+ openContextModal,
467
+ closeModal,
468
+ closeAll
469
+ };
470
+ const getCurrentModal = () => {
471
+ var _a;
472
+ switch ((_a = state.current) == null ? void 0 : _a.type) {
473
+ case "context": {
474
+ const _b = state.current.props, {
475
+ innerProps
476
+ } = _b, rest = __objRest2(_b, ["innerProps"]);
477
+ const ContextModal = modals[state.current.ctx];
478
+ return {
479
+ modalProps: rest,
480
+ content: /* @__PURE__ */ jsx(ContextModal, {
481
+ innerProps,
482
+ context: ctx,
483
+ id: state.current.id
484
+ })
485
+ };
486
+ }
487
+ case "confirm": {
488
+ const {
489
+ modalProps: separatedModalProps,
490
+ confirmProps: separatedConfirmProps
491
+ } = separateConfirmModalProps(state.current.props);
492
+ return {
493
+ modalProps: separatedModalProps,
494
+ content: /* @__PURE__ */ jsx(ConfirmModal, __spreadValues({}, __spreadProps2(__spreadValues2({}, separatedConfirmProps), {
495
+ id: state.current.id,
496
+ labels: state.current.props.labels || labels
497
+ })))
498
+ };
499
+ }
500
+ case "content": {
501
+ const _c = state.current.props, {
502
+ children: currentModalChildren
503
+ } = _c, rest = __objRest2(_c, ["children"]);
504
+ return {
505
+ modalProps: rest,
506
+ content: /* @__PURE__ */ jsx(Fragment, {
507
+ children: currentModalChildren
508
+ })
509
+ };
510
+ }
511
+ default: {
512
+ return {
513
+ modalProps: {},
514
+ content: null
515
+ };
516
+ }
517
+ }
518
+ };
519
+ const {
520
+ modalProps: currentModalProps,
521
+ content
522
+ } = getCurrentModal();
523
+ return /* @__PURE__ */ jsxs(ModalsContext.Provider, {
524
+ value: ctx,
525
+ children: [/* @__PURE__ */ jsx(Modal, __spreadProps(__spreadValues({}, __spreadProps2(__spreadValues2(__spreadValues2({}, modalProps), currentModalProps), {
526
+ opened: state.modals.length > 0,
527
+ onClose: () => closeModal(state.current.id)
528
+ })), {
529
+ children: content
530
+ })), children]
531
+ });
532
+ }
533
+ const initialContext$1 = {
534
+ addPanel: _.noop,
535
+ duplidatePanel: _.noop,
536
+ removePanelByID: _.noop
537
+ };
538
+ const DashboardActionContext = React.createContext(initialContext$1);
539
+ const initialContext = {
540
+ sqlSnippets: [],
541
+ setSQLSnippets: () => {
542
+ },
543
+ queries: [],
544
+ setQueries: () => {
545
+ }
546
+ };
547
+ const DefinitionContext = React.createContext(initialContext);
233
548
  function DescriptionPopover({
234
549
  position = "bottom",
235
550
  trigger = "hover"
@@ -5744,16 +6059,34 @@ function PanelSettingsModal({
5744
6059
  }
5745
6060
  var titleBar = "";
5746
6061
  function PanelTitleBar({}) {
6062
+ const modals = useModals();
5747
6063
  const [opened, setOpened] = React.useState(false);
5748
6064
  const open = () => setOpened(true);
5749
6065
  const close = () => setOpened(false);
5750
6066
  const {
6067
+ id,
5751
6068
  title,
5752
6069
  refreshData
5753
6070
  } = React.useContext(PanelContext);
5754
6071
  const {
5755
6072
  inEditMode
5756
6073
  } = React.useContext(LayoutStateContext);
6074
+ const {
6075
+ duplidatePanel,
6076
+ removePanelByID
6077
+ } = React.useContext(DashboardActionContext);
6078
+ const duplicate = React.useCallback(() => {
6079
+ duplidatePanel(id);
6080
+ }, [duplidatePanel, id]);
6081
+ const remove = () => modals.openConfirmModal({
6082
+ title: "Delete this panel?",
6083
+ labels: {
6084
+ confirm: "Confirm",
6085
+ cancel: "Cancel"
6086
+ },
6087
+ onCancel: () => console.log("Cancel"),
6088
+ onConfirm: () => removePanelByID(id)
6089
+ });
5757
6090
  return /* @__PURE__ */ jsxs(Box, {
5758
6091
  sx: {
5759
6092
  position: "relative"
@@ -5794,8 +6127,14 @@ function PanelTitleBar({}) {
5794
6127
  }),
5795
6128
  children: "Settings"
5796
6129
  }), /* @__PURE__ */ jsx(Divider, {}), /* @__PURE__ */ jsx(Menu.Item, {
6130
+ onClick: duplicate,
6131
+ icon: /* @__PURE__ */ jsx(Copy, {
6132
+ size: 14
6133
+ }),
6134
+ children: "Duplicate"
6135
+ }), /* @__PURE__ */ jsx(Menu.Item, {
5797
6136
  color: "red",
5798
- disabled: true,
6137
+ onClick: remove,
5799
6138
  icon: /* @__PURE__ */ jsx(Trash, {
5800
6139
  size: 14
5801
6140
  }),
@@ -5855,6 +6194,7 @@ function Panel({
5855
6194
  const refreshData = refresh;
5856
6195
  return /* @__PURE__ */ jsx(PanelContext.Provider, {
5857
6196
  value: {
6197
+ id,
5858
6198
  data,
5859
6199
  loading,
5860
6200
  title,
@@ -5884,7 +6224,6 @@ function DashboardLayout({
5884
6224
  setPanels,
5885
6225
  className = "layout",
5886
6226
  rowHeight = 10,
5887
- onRemoveItem,
5888
6227
  isDraggable,
5889
6228
  isResizable
5890
6229
  }) {
@@ -5920,7 +6259,6 @@ function DashboardLayout({
5920
6259
  children: /* @__PURE__ */ jsx(Panel, __spreadProps(__spreadValues({
5921
6260
  id
5922
6261
  }, rest), {
5923
- destroy: () => onRemoveItem(id),
5924
6262
  update: (panel) => {
5925
6263
  setPanels((prevs) => {
5926
6264
  prevs.splice(index2, 1, panel);
@@ -6095,7 +6433,7 @@ function QueryForm({
6095
6433
  const {
6096
6434
  data: querySources = {},
6097
6435
  loading
6098
- } = useRequest(getQuerySources, {
6436
+ } = useRequest(listDataSources, {
6099
6437
  refreshDeps: []
6100
6438
  }, []);
6101
6439
  const querySourceTypeOptions = React.useMemo(() => {
@@ -6660,13 +6998,51 @@ function DataEditorModal({
6660
6998
  })
6661
6999
  });
6662
7000
  }
7001
+ function ViewSchemaModal({
7002
+ opened,
7003
+ close,
7004
+ getCurrentSchema
7005
+ }) {
7006
+ const {
7007
+ freezeLayout
7008
+ } = React.useContext(LayoutStateContext);
7009
+ React.useEffect(() => {
7010
+ freezeLayout(opened);
7011
+ }, [opened]);
7012
+ const schema = React.useMemo(() => {
7013
+ return JSON.stringify(getCurrentSchema(), null, 2);
7014
+ }, [opened]);
7015
+ return /* @__PURE__ */ jsx(Modal, {
7016
+ size: "96vw",
7017
+ overflow: "inside",
7018
+ opened,
7019
+ onClose: close,
7020
+ title: "This dashboard is described by this schema",
7021
+ trapFocus: true,
7022
+ onDragStart: (e) => {
7023
+ e.stopPropagation();
7024
+ },
7025
+ children: /* @__PURE__ */ jsx(Prism, {
7026
+ language: "json",
7027
+ sx: {
7028
+ width: "100%"
7029
+ },
7030
+ colorScheme: "dark",
7031
+ children: schema
7032
+ })
7033
+ });
7034
+ }
6663
7035
  function DashboardActions({
6664
7036
  mode,
6665
7037
  setMode,
6666
7038
  hasChanges,
6667
- addPanel,
6668
- saveChanges
7039
+ saveChanges,
7040
+ revertChanges,
7041
+ getCurrentSchema
6669
7042
  }) {
7043
+ const {
7044
+ addPanel
7045
+ } = React.useContext(DashboardActionContext);
6670
7046
  const {
6671
7047
  inLayoutMode,
6672
7048
  inEditMode,
@@ -6675,6 +7051,9 @@ function DashboardActions({
6675
7051
  const [dataEditorOpened, setDataEditorOpened] = React.useState(false);
6676
7052
  const openQueries = () => setDataEditorOpened(true);
6677
7053
  const closeQueries = () => setDataEditorOpened(false);
7054
+ const [schemaOpened, setSchemaOpened] = React.useState(false);
7055
+ const openSchema = () => setSchemaOpened(true);
7056
+ const closeSchema = () => setSchemaOpened(false);
6678
7057
  return /* @__PURE__ */ jsxs(Group, {
6679
7058
  position: "apart",
6680
7059
  pt: "sm",
@@ -6716,22 +7095,35 @@ function DashboardActions({
6716
7095
  color: "red",
6717
7096
  size: "sm",
6718
7097
  disabled: !hasChanges,
7098
+ onClick: revertChanges,
6719
7099
  leftIcon: /* @__PURE__ */ jsx(Recycle, {
6720
7100
  size: 20
6721
7101
  }),
6722
7102
  children: "Revert Changes"
7103
+ }), /* @__PURE__ */ jsxs(Menu, {
7104
+ control: /* @__PURE__ */ jsx(Button, {
7105
+ variant: "default",
7106
+ size: "sm",
7107
+ leftIcon: /* @__PURE__ */ jsx(Share, {
7108
+ size: 20
7109
+ }),
7110
+ children: "Export"
7111
+ }),
7112
+ children: [/* @__PURE__ */ jsx(Menu.Item, {
7113
+ disabled: true,
7114
+ children: "Download Data"
7115
+ }), /* @__PURE__ */ jsx(Menu.Item, {
7116
+ onClick: openSchema,
7117
+ children: "View Schema"
7118
+ })]
6723
7119
  })]
6724
7120
  }), /* @__PURE__ */ jsx(DataEditorModal, {
6725
7121
  opened: dataEditorOpened,
6726
7122
  close: closeQueries
6727
- }), inUseMode && /* @__PURE__ */ jsx(Button, {
6728
- variant: "default",
6729
- size: "sm",
6730
- disabled: true,
6731
- leftIcon: /* @__PURE__ */ jsx(Share, {
6732
- size: 20
6733
- }),
6734
- children: "Share"
7123
+ }), /* @__PURE__ */ jsx(ViewSchemaModal, {
7124
+ opened: schemaOpened,
7125
+ close: closeSchema,
7126
+ getCurrentSchema
6735
7127
  })]
6736
7128
  });
6737
7129
  }
@@ -6771,6 +7163,11 @@ function Dashboard({
6771
7163
  });
6772
7164
  await update(d);
6773
7165
  };
7166
+ const revertDashboardChanges = () => {
7167
+ setPanels(dashboard.panels);
7168
+ setSQLSnippets(dashboard.definition.sqlSnippets);
7169
+ setQueries(dashboard.definition.queries);
7170
+ };
6774
7171
  const addPanel = () => {
6775
7172
  const id = randomId();
6776
7173
  const newItem = {
@@ -6791,6 +7188,24 @@ function Dashboard({
6791
7188
  };
6792
7189
  setPanels((prevs) => [...prevs, newItem]);
6793
7190
  };
7191
+ const duplidatePanel = (id) => {
7192
+ try {
7193
+ const panel = panels.find((p2) => p2.id === id);
7194
+ if (!panel) {
7195
+ throw new Error(`[duplicate panel] Can't find a panel by id[${id}]`);
7196
+ }
7197
+ const newPanel = __spreadProps(__spreadValues({}, panel), {
7198
+ id: randomId(),
7199
+ layout: __spreadProps(__spreadValues({}, panel.layout), {
7200
+ x: 0,
7201
+ y: Infinity
7202
+ })
7203
+ });
7204
+ setPanels((prevs) => [...prevs, newPanel]);
7205
+ } catch (error) {
7206
+ console.error(error);
7207
+ }
7208
+ };
6794
7209
  const removePanelByID = (id) => {
6795
7210
  const index2 = panels.findIndex((p2) => p2.id === id);
6796
7211
  setPanels((prevs) => {
@@ -6807,34 +7222,52 @@ function Dashboard({
6807
7222
  queries,
6808
7223
  setQueries
6809
7224
  }), [sqlSnippets, setSQLSnippets, queries, setQueries]);
6810
- return /* @__PURE__ */ jsx(ContextInfoContext.Provider, {
6811
- value: context,
6812
- children: /* @__PURE__ */ jsx("div", {
6813
- className,
6814
- children: /* @__PURE__ */ jsx(DefinitionContext.Provider, {
6815
- value: definitions,
6816
- children: /* @__PURE__ */ jsxs(LayoutStateContext.Provider, {
6817
- value: {
6818
- layoutFrozen,
6819
- freezeLayout,
6820
- mode,
6821
- inEditMode,
6822
- inLayoutMode,
6823
- inUseMode
6824
- },
6825
- children: [/* @__PURE__ */ jsx(DashboardActions, {
6826
- mode,
6827
- setMode,
6828
- hasChanges,
6829
- addPanel,
6830
- saveChanges: saveDashboardChanges
6831
- }), /* @__PURE__ */ jsx(DashboardLayout, {
6832
- panels,
6833
- setPanels,
6834
- isDraggable: inLayoutMode,
6835
- isResizable: inLayoutMode,
6836
- onRemoveItem: removePanelByID
6837
- })]
7225
+ const getCurrentSchema = React.useCallback(() => {
7226
+ return {
7227
+ panels,
7228
+ definition: {
7229
+ sqlSnippets,
7230
+ queries
7231
+ }
7232
+ };
7233
+ }, [sqlSnippets, queries, panels]);
7234
+ return /* @__PURE__ */ jsx(ModalsProvider, {
7235
+ children: /* @__PURE__ */ jsx(ContextInfoContext.Provider, {
7236
+ value: context,
7237
+ children: /* @__PURE__ */ jsx(DashboardActionContext.Provider, {
7238
+ value: {
7239
+ addPanel,
7240
+ duplidatePanel,
7241
+ removePanelByID
7242
+ },
7243
+ children: /* @__PURE__ */ jsx(DefinitionContext.Provider, {
7244
+ value: definitions,
7245
+ children: /* @__PURE__ */ jsx(LayoutStateContext.Provider, {
7246
+ value: {
7247
+ layoutFrozen,
7248
+ freezeLayout,
7249
+ mode,
7250
+ inEditMode,
7251
+ inLayoutMode,
7252
+ inUseMode
7253
+ },
7254
+ children: /* @__PURE__ */ jsxs("div", {
7255
+ className,
7256
+ children: [/* @__PURE__ */ jsx(DashboardActions, {
7257
+ mode,
7258
+ setMode,
7259
+ hasChanges,
7260
+ saveChanges: saveDashboardChanges,
7261
+ revertChanges: revertDashboardChanges,
7262
+ getCurrentSchema
7263
+ }), /* @__PURE__ */ jsx(DashboardLayout, {
7264
+ panels,
7265
+ setPanels,
7266
+ isDraggable: inLayoutMode,
7267
+ isResizable: inLayoutMode
7268
+ })]
7269
+ })
7270
+ })
6838
7271
  })
6839
7272
  })
6840
7273
  })
@@ -6881,24 +7314,26 @@ function ReadOnlyDashboard({
6881
7314
  setQueries: () => {
6882
7315
  }
6883
7316
  }), [dashboard]);
6884
- return /* @__PURE__ */ jsx(ContextInfoContext.Provider, {
6885
- value: context,
6886
- children: /* @__PURE__ */ jsx("div", {
6887
- className,
6888
- children: /* @__PURE__ */ jsx(DefinitionContext.Provider, {
6889
- value: definition,
6890
- children: /* @__PURE__ */ jsx(LayoutStateContext.Provider, {
6891
- value: {
6892
- layoutFrozen: true,
6893
- freezeLayout: () => {
7317
+ return /* @__PURE__ */ jsx(ModalsProvider, {
7318
+ children: /* @__PURE__ */ jsx(ContextInfoContext.Provider, {
7319
+ value: context,
7320
+ children: /* @__PURE__ */ jsx("div", {
7321
+ className,
7322
+ children: /* @__PURE__ */ jsx(DefinitionContext.Provider, {
7323
+ value: definition,
7324
+ children: /* @__PURE__ */ jsx(LayoutStateContext.Provider, {
7325
+ value: {
7326
+ layoutFrozen: true,
7327
+ freezeLayout: () => {
7328
+ },
7329
+ mode: DashboardMode.Use,
7330
+ inEditMode: false,
7331
+ inLayoutMode: false,
7332
+ inUseMode: true
6894
7333
  },
6895
- mode: DashboardMode.Use,
6896
- inEditMode: false,
6897
- inLayoutMode: false,
6898
- inUseMode: true
6899
- },
6900
- children: /* @__PURE__ */ jsx(ReadOnlyDashboardLayout, {
6901
- panels: dashboard.panels
7334
+ children: /* @__PURE__ */ jsx(ReadOnlyDashboardLayout, {
7335
+ panels: dashboard.panels
7336
+ })
6902
7337
  })
6903
7338
  })
6904
7339
  })