@perses-dev/dashboards 0.52.0-beta.4 → 0.52.0-rc.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 (117) hide show
  1. package/dist/cjs/components/GridLayout/GridItemContent.js +137 -17
  2. package/dist/cjs/components/GridLayout/GridLayout.js +78 -126
  3. package/dist/cjs/components/GridLayout/Row.js +150 -0
  4. package/dist/cjs/components/GridLayout/index.js +1 -0
  5. package/dist/cjs/components/LeaveDialog/LeaveDialog.js +44 -0
  6. package/dist/cjs/components/LeaveDialog/index.js +30 -0
  7. package/dist/cjs/components/Panel/Panel.js +7 -2
  8. package/dist/cjs/components/Panel/PanelActions.js +25 -5
  9. package/dist/cjs/components/Panel/PanelHeader.js +33 -15
  10. package/dist/cjs/components/PanelDrawer/PanelDrawer.js +58 -21
  11. package/dist/cjs/components/PanelGroupDialog/PanelGroupDialog.js +3 -0
  12. package/dist/cjs/components/PanelGroupDialog/PanelGroupEditorForm.js +35 -15
  13. package/dist/cjs/components/index.js +1 -0
  14. package/dist/cjs/constants/user-interface-text.js +4 -2
  15. package/dist/cjs/context/DashboardProvider/DashboardProvider.js +7 -8
  16. package/dist/cjs/context/DashboardProvider/DashboardProviderWithQueryParams.js +3 -3
  17. package/dist/cjs/context/DashboardProvider/panel-editor-slice.js +1 -0
  18. package/dist/cjs/context/DashboardProvider/panel-group-editor-slice.js +6 -2
  19. package/dist/cjs/context/DashboardProvider/panel-group-slice.js +1 -0
  20. package/dist/cjs/context/DashboardProvider/view-panel-slice.js +10 -3
  21. package/dist/cjs/context/VariableProvider/VariableProvider.js +1 -1
  22. package/dist/cjs/context/useDashboard.js +5 -4
  23. package/dist/cjs/views/ViewDashboard/DashboardApp.js +7 -3
  24. package/dist/cjs/views/ViewDashboard/ViewDashboard.js +9 -8
  25. package/dist/components/DashboardToolbar/DashboardToolbar.d.ts +2 -2
  26. package/dist/components/DashboardToolbar/DashboardToolbar.d.ts.map +1 -1
  27. package/dist/components/DashboardToolbar/DashboardToolbar.js.map +1 -1
  28. package/dist/components/GridLayout/GridItemContent.d.ts.map +1 -1
  29. package/dist/components/GridLayout/GridItemContent.js +99 -20
  30. package/dist/components/GridLayout/GridItemContent.js.map +1 -1
  31. package/dist/components/GridLayout/GridLayout.d.ts +8 -0
  32. package/dist/components/GridLayout/GridLayout.d.ts.map +1 -1
  33. package/dist/components/GridLayout/GridLayout.js +72 -126
  34. package/dist/components/GridLayout/GridLayout.js.map +1 -1
  35. package/dist/components/GridLayout/Row.d.ts +17 -0
  36. package/dist/components/GridLayout/Row.d.ts.map +1 -0
  37. package/dist/components/GridLayout/Row.js +142 -0
  38. package/dist/components/GridLayout/Row.js.map +1 -0
  39. package/dist/components/GridLayout/index.d.ts +1 -0
  40. package/dist/components/GridLayout/index.d.ts.map +1 -1
  41. package/dist/components/GridLayout/index.js +1 -0
  42. package/dist/components/GridLayout/index.js.map +1 -1
  43. package/dist/components/LeaveDialog/LeaveDialog.d.ts +7 -0
  44. package/dist/components/LeaveDialog/LeaveDialog.d.ts.map +1 -0
  45. package/dist/components/LeaveDialog/LeaveDialog.js +36 -0
  46. package/dist/components/LeaveDialog/LeaveDialog.js.map +1 -0
  47. package/dist/components/LeaveDialog/index.d.ts +2 -0
  48. package/dist/components/LeaveDialog/index.d.ts.map +1 -0
  49. package/dist/components/LeaveDialog/index.js +15 -0
  50. package/dist/components/LeaveDialog/index.js.map +1 -0
  51. package/dist/components/Panel/Panel.d.ts +6 -0
  52. package/dist/components/Panel/Panel.d.ts.map +1 -1
  53. package/dist/components/Panel/Panel.js +7 -2
  54. package/dist/components/Panel/Panel.js.map +1 -1
  55. package/dist/components/Panel/PanelActions.d.ts +5 -0
  56. package/dist/components/Panel/PanelActions.d.ts.map +1 -1
  57. package/dist/components/Panel/PanelActions.js +25 -5
  58. package/dist/components/Panel/PanelActions.js.map +1 -1
  59. package/dist/components/Panel/PanelHeader.d.ts +7 -1
  60. package/dist/components/Panel/PanelHeader.d.ts.map +1 -1
  61. package/dist/components/Panel/PanelHeader.js +34 -16
  62. package/dist/components/Panel/PanelHeader.js.map +1 -1
  63. package/dist/components/PanelDrawer/PanelDrawer.d.ts.map +1 -1
  64. package/dist/components/PanelDrawer/PanelDrawer.js +59 -22
  65. package/dist/components/PanelDrawer/PanelDrawer.js.map +1 -1
  66. package/dist/components/PanelGroupDialog/PanelGroupDialog.d.ts.map +1 -1
  67. package/dist/components/PanelGroupDialog/PanelGroupDialog.js +3 -0
  68. package/dist/components/PanelGroupDialog/PanelGroupDialog.js.map +1 -1
  69. package/dist/components/PanelGroupDialog/PanelGroupEditorForm.d.ts +1 -0
  70. package/dist/components/PanelGroupDialog/PanelGroupEditorForm.d.ts.map +1 -1
  71. package/dist/components/PanelGroupDialog/PanelGroupEditorForm.js +36 -16
  72. package/dist/components/PanelGroupDialog/PanelGroupEditorForm.js.map +1 -1
  73. package/dist/components/index.d.ts +1 -0
  74. package/dist/components/index.d.ts.map +1 -1
  75. package/dist/components/index.js +1 -0
  76. package/dist/components/index.js.map +1 -1
  77. package/dist/constants/user-interface-text.d.ts +2 -0
  78. package/dist/constants/user-interface-text.d.ts.map +1 -1
  79. package/dist/constants/user-interface-text.js +4 -2
  80. package/dist/constants/user-interface-text.js.map +1 -1
  81. package/dist/context/DashboardProvider/DashboardProvider.d.ts +5 -5
  82. package/dist/context/DashboardProvider/DashboardProvider.d.ts.map +1 -1
  83. package/dist/context/DashboardProvider/DashboardProvider.js +7 -8
  84. package/dist/context/DashboardProvider/DashboardProvider.js.map +1 -1
  85. package/dist/context/DashboardProvider/DashboardProviderWithQueryParams.js +4 -4
  86. package/dist/context/DashboardProvider/DashboardProviderWithQueryParams.js.map +1 -1
  87. package/dist/context/DashboardProvider/common.d.ts +1 -1
  88. package/dist/context/DashboardProvider/common.d.ts.map +1 -1
  89. package/dist/context/DashboardProvider/common.js.map +1 -1
  90. package/dist/context/DashboardProvider/panel-editor-slice.d.ts +1 -0
  91. package/dist/context/DashboardProvider/panel-editor-slice.d.ts.map +1 -1
  92. package/dist/context/DashboardProvider/panel-editor-slice.js +1 -0
  93. package/dist/context/DashboardProvider/panel-editor-slice.js.map +1 -1
  94. package/dist/context/DashboardProvider/panel-group-editor-slice.d.ts +1 -0
  95. package/dist/context/DashboardProvider/panel-group-editor-slice.d.ts.map +1 -1
  96. package/dist/context/DashboardProvider/panel-group-editor-slice.js +6 -2
  97. package/dist/context/DashboardProvider/panel-group-editor-slice.js.map +1 -1
  98. package/dist/context/DashboardProvider/panel-group-slice.d.ts +3 -0
  99. package/dist/context/DashboardProvider/panel-group-slice.d.ts.map +1 -1
  100. package/dist/context/DashboardProvider/panel-group-slice.js +1 -0
  101. package/dist/context/DashboardProvider/panel-group-slice.js.map +1 -1
  102. package/dist/context/DashboardProvider/view-panel-slice.d.ts +6 -2
  103. package/dist/context/DashboardProvider/view-panel-slice.d.ts.map +1 -1
  104. package/dist/context/DashboardProvider/view-panel-slice.js +10 -3
  105. package/dist/context/DashboardProvider/view-panel-slice.js.map +1 -1
  106. package/dist/context/VariableProvider/VariableProvider.js +1 -1
  107. package/dist/context/VariableProvider/VariableProvider.js.map +1 -1
  108. package/dist/context/useDashboard.js +5 -4
  109. package/dist/context/useDashboard.js.map +1 -1
  110. package/dist/views/ViewDashboard/DashboardApp.d.ts +7 -6
  111. package/dist/views/ViewDashboard/DashboardApp.d.ts.map +1 -1
  112. package/dist/views/ViewDashboard/DashboardApp.js +8 -4
  113. package/dist/views/ViewDashboard/DashboardApp.js.map +1 -1
  114. package/dist/views/ViewDashboard/ViewDashboard.d.ts.map +1 -1
  115. package/dist/views/ViewDashboard/ViewDashboard.js +9 -8
  116. package/dist/views/ViewDashboard/ViewDashboard.js.map +1 -1
  117. package/package.json +5 -5
@@ -34,7 +34,7 @@ function _interop_require_default(obj) {
34
34
  };
35
35
  }
36
36
  const Panel = /*#__PURE__*/ (0, _react.memo)(function Panel(props) {
37
- const { definition, readHandlers, editHandlers, onMouseEnter, onMouseLeave, sx, panelOptions, panelGroupItemId, ...others } = props;
37
+ const { definition, readHandlers, editHandlers, onMouseEnter, onMouseLeave, sx, panelOptions, panelGroupItemId, viewQueriesHandler, ...others } = props;
38
38
  // Make sure we have an ID we can use for aria attributes
39
39
  const generatedPanelId = (0, _components.useId)('Panel');
40
40
  const headerId = `${generatedPanelId}-header`;
@@ -142,6 +142,8 @@ const Panel = /*#__PURE__*/ (0, _react.memo)(function Panel(props) {
142
142
  const handleMouseLeave = (e)=>{
143
143
  onMouseLeave?.(e);
144
144
  };
145
+ // default value for showIcons: if the dashboard is in editing mode or the panel is in fullscreen mode: 'always', otherwise 'hover'
146
+ const showIcons = panelOptions?.showIcons ?? (editHandlers || readHandlers?.isPanelViewed ? 'always' : 'hover');
145
147
  return /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Card, {
146
148
  component: "section",
147
149
  sx: (0, _components.combineSx)({
@@ -172,11 +174,14 @@ const Panel = /*#__PURE__*/ (0, _react.memo)(function Panel(props) {
172
174
  queryResults: queryResults,
173
175
  readHandlers: readHandlers,
174
176
  editHandlers: editHandlers,
177
+ viewQueriesHandler: viewQueriesHandler,
175
178
  links: definition.spec.links,
176
179
  pluginActions: pluginActions,
180
+ showIcons: showIcons,
177
181
  sx: {
178
182
  paddingX: `${chartsTheme.container.padding.default}px`
179
- }
183
+ },
184
+ dimension: contentDimensions
180
185
  }),
181
186
  /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.CardContent, {
182
187
  component: "figure",
@@ -24,6 +24,7 @@ const _jsxruntime = require("react/jsx-runtime");
24
24
  const _material = require("@mui/material");
25
25
  const _react = require("react");
26
26
  const _components = require("@perses-dev/components");
27
+ const _DatabaseSearch = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/DatabaseSearch"));
27
28
  const _ArrowCollapse = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/ArrowCollapse"));
28
29
  const _ArrowExpand = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/ArrowExpand"));
29
30
  const _PencilOutline = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/PencilOutline"));
@@ -47,7 +48,7 @@ const ConditionalBox = (0, _material.styled)(_material.Box)({
47
48
  flexGrow: 1,
48
49
  justifyContent: 'flex-end'
49
50
  });
50
- const PanelActions = ({ editHandlers, readHandlers, extra, title, description, descriptionTooltipId, links, queryResults, pluginActions = [] })=>{
51
+ const PanelActions = ({ editHandlers, readHandlers, viewQueriesHandler, extra, title, description, descriptionTooltipId, links, queryResults, pluginActions = [], showIcons })=>{
51
52
  const descriptionAction = (0, _react.useMemo)(()=>{
52
53
  if (description && description.trim().length > 0) {
53
54
  return /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.InfoTooltip, {
@@ -124,6 +125,23 @@ const PanelActions = ({ editHandlers, readHandlers, extra, title, description, d
124
125
  readHandlers,
125
126
  title
126
127
  ]);
128
+ const viewQueryAction = (0, _react.useMemo)(()=>{
129
+ if (!viewQueriesHandler?.onClick) return null;
130
+ return /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.InfoTooltip, {
131
+ description: _constants.TOOLTIP_TEXT.queryView,
132
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_HeaderIconButton.HeaderIconButton, {
133
+ "aria-label": _constants.ARIA_LABEL_TEXT.openQueryView(title),
134
+ size: "small",
135
+ onClick: viewQueriesHandler.onClick,
136
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_DatabaseSearch.default, {
137
+ fontSize: "inherit"
138
+ })
139
+ })
140
+ });
141
+ }, [
142
+ viewQueriesHandler,
143
+ title
144
+ ]);
127
145
  const editActions = (0, _react.useMemo)(()=>{
128
146
  if (editHandlers !== undefined) {
129
147
  // If there are edit handlers, always just show the edit buttons
@@ -203,8 +221,8 @@ const PanelActions = ({ editHandlers, readHandlers, extra, title, description, d
203
221
  flexGrow: 1
204
222
  }
205
223
  });
206
- // if the panel is in non-editing, non-fullscreen mode, show certain icons only on hover
207
- const OnHover = ({ children })=>editHandlers === undefined && !readHandlers?.isPanelViewed ? /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Box, {
224
+ // By default, the panel header shows certain icons only on hover if the panel is in non-editing, non-fullscreen mode
225
+ const OnHover = ({ children })=>showIcons === 'hover' ? /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Box, {
208
226
  sx: {
209
227
  display: 'var(--panel-hover, none)'
210
228
  },
@@ -235,6 +253,7 @@ const PanelActions = ({ editHandlers, readHandlers, extra, title, description, d
235
253
  " ",
236
254
  extraActions,
237
255
  " ",
256
+ viewQueryAction,
238
257
  readActions,
239
258
  " ",
240
259
  pluginActions,
@@ -266,13 +285,14 @@ const PanelActions = ({ editHandlers, readHandlers, extra, title, description, d
266
285
  /*#__PURE__*/ (0, _jsxruntime.jsxs)(OnHover, {
267
286
  children: [
268
287
  extraActions,
269
- " ",
270
288
  readActions,
271
289
  /*#__PURE__*/ (0, _jsxruntime.jsxs)(OverflowMenu, {
272
290
  title: title,
273
291
  children: [
274
292
  editActions,
275
293
  " ",
294
+ viewQueryAction,
295
+ " ",
276
296
  pluginActions
277
297
  ]
278
298
  }),
@@ -303,7 +323,7 @@ const PanelActions = ({ editHandlers, readHandlers, extra, title, description, d
303
323
  /*#__PURE__*/ (0, _jsxruntime.jsxs)(OnHover, {
304
324
  children: [
305
325
  extraActions,
306
- " ",
326
+ viewQueryAction,
307
327
  readActions,
308
328
  " ",
309
329
  editActions,
@@ -24,13 +24,24 @@ const _jsxruntime = require("react/jsx-runtime");
24
24
  const _material = require("@mui/material");
25
25
  const _components = require("@perses-dev/components");
26
26
  const _pluginsystem = require("@perses-dev/plugin-system");
27
+ const _react = require("react");
27
28
  const _constants = require("../../constants");
28
29
  const _PanelActions = require("./PanelActions");
29
- function PanelHeader({ id, title: rawTitle, description: rawDescription, links, queryResults, readHandlers, editHandlers, sx, extra, pluginActions, ...rest }) {
30
+ function PanelHeader({ id, title: rawTitle, description: rawDescription, links, queryResults, readHandlers, editHandlers, sx, extra, pluginActions, showIcons, viewQueriesHandler, dimension, ...rest }) {
30
31
  const titleElementId = `${id}-title`;
31
32
  const descriptionTooltipId = `${id}-description`;
32
33
  const title = (0, _pluginsystem.useReplaceVariablesInString)(rawTitle);
33
34
  const description = (0, _pluginsystem.useReplaceVariablesInString)(rawDescription);
35
+ const textRef = (0, _react.useRef)(null);
36
+ const [isEllipsisActive, setIsEllipsisActive] = (0, _react.useState)(false);
37
+ (0, _react.useEffect)(()=>{
38
+ if (textRef.current && dimension?.width) {
39
+ setIsEllipsisActive(textRef.current.scrollWidth > textRef.current.clientWidth);
40
+ }
41
+ }, [
42
+ title,
43
+ dimension?.width
44
+ ]);
34
45
  return /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.CardHeader, {
35
46
  id: id,
36
47
  component: "header",
@@ -42,19 +53,24 @@ function PanelHeader({ id, title: rawTitle, description: rawDescription, links,
42
53
  alignItems: "center",
43
54
  height: "var(--panel-header-height, 30px)",
44
55
  children: [
45
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Typography, {
46
- id: titleElementId,
47
- variant: "subtitle1",
48
- sx: {
49
- // `minHeight` guarantees that the header has the correct height
50
- // when there is no title (i.e. in the preview)
51
- lineHeight: '24px',
52
- minHeight: '26px',
53
- whiteSpace: 'nowrap',
54
- overflow: 'hidden',
55
- textOverflow: 'ellipsis'
56
- },
57
- children: title
56
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Tooltip, {
57
+ title: title,
58
+ disableHoverListener: !isEllipsisActive,
59
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Typography, {
60
+ id: titleElementId,
61
+ variant: "subtitle1",
62
+ ref: textRef,
63
+ sx: {
64
+ // `minHeight` guarantees that the header has the correct height
65
+ // when there is no title (i.e. in the preview)
66
+ lineHeight: '24px',
67
+ minHeight: '26px',
68
+ whiteSpace: 'nowrap',
69
+ overflow: 'hidden',
70
+ textOverflow: 'ellipsis'
71
+ },
72
+ children: title
73
+ })
58
74
  }),
59
75
  /*#__PURE__*/ (0, _jsxruntime.jsx)(_PanelActions.PanelActions, {
60
76
  title: title,
@@ -63,9 +79,11 @@ function PanelHeader({ id, title: rawTitle, description: rawDescription, links,
63
79
  links: links,
64
80
  readHandlers: readHandlers,
65
81
  editHandlers: editHandlers,
82
+ viewQueriesHandler: viewQueriesHandler,
66
83
  extra: extra,
67
84
  queryResults: queryResults,
68
- pluginActions: pluginActions
85
+ pluginActions: pluginActions,
86
+ showIcons: showIcons
69
87
  })
70
88
  ]
71
89
  }),
@@ -23,6 +23,7 @@ Object.defineProperty(exports, "PanelDrawer", {
23
23
  const _jsxruntime = require("react/jsx-runtime");
24
24
  const _react = require("react");
25
25
  const _components = require("@perses-dev/components");
26
+ const _pluginsystem = require("@perses-dev/plugin-system");
26
27
  const _context = require("../../context");
27
28
  const _PanelEditorForm = require("./PanelEditorForm");
28
29
  const PanelDrawer = ()=>{
@@ -30,42 +31,78 @@ const PanelDrawer = ()=>{
30
31
  // When the user clicks close, start closing but don't call the store yet to keep values stable during animtation
31
32
  const [isClosing, setIsClosing] = (0, _react.useState)(false);
32
33
  // Drawer is open if we have a model and we're not transitioning out
33
- const isOpen = panelEditor !== undefined && isClosing === false;
34
- function handleSave(values) {
34
+ const isOpen = panelEditor !== undefined && !isClosing;
35
+ const handleSave = (0, _react.useCallback)((values)=>{
35
36
  // This shouldn't happen since we don't render the submit button until we have a model, but check to make TS happy
36
37
  if (panelEditor === undefined || values === undefined) {
37
38
  throw new Error('Cannot apply changes');
38
39
  }
39
40
  panelEditor.applyChanges(values);
40
41
  setIsClosing(true);
41
- }
42
+ }, [
43
+ panelEditor
44
+ ]);
42
45
  const handleClose = ()=>{
43
46
  setIsClosing(true);
44
47
  };
45
48
  // Don't call closeDrawer on the store until the Drawer has completely transitioned out and reset close state
46
- const handleExited = ()=>{
49
+ const handleExited = (0, _react.useCallback)(()=>{
47
50
  panelEditor?.close();
48
51
  setIsClosing(false);
49
- };
52
+ }, [
53
+ panelEditor
54
+ ]);
50
55
  // Disables closing on click out. This is a quick-win solution to avoid losing draft changes.
51
56
  // -> TODO find a way to enable closing by clicking-out in edit view, with a discard confirmation modal popping up
52
57
  const handleClickOut = ()=>{
53
58
  /* do nothing */ };
54
- return /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.Drawer, {
55
- isOpen: isOpen,
56
- onClose: handleClickOut,
57
- SlideProps: {
58
- onExited: handleExited
59
- },
60
- "data-testid": "panel-editor",
61
- children: panelEditor && /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.ErrorBoundary, {
62
- FallbackComponent: _components.ErrorAlert,
63
- children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_PanelEditorForm.PanelEditorForm, {
64
- initialAction: panelEditor.mode,
65
- initialValues: panelEditor.initialValues,
66
- onSave: handleSave,
67
- onClose: handleClose
59
+ const drawer = (0, _react.useMemo)(()=>{
60
+ return /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.Drawer, {
61
+ isOpen: isOpen,
62
+ onClose: handleClickOut,
63
+ SlideProps: {
64
+ onExited: handleExited
65
+ },
66
+ "data-testid": "panel-editor",
67
+ children: panelEditor && /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.ErrorBoundary, {
68
+ FallbackComponent: _components.ErrorAlert,
69
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_PanelEditorForm.PanelEditorForm, {
70
+ initialAction: panelEditor.mode,
71
+ initialValues: panelEditor.initialValues,
72
+ onSave: handleSave,
73
+ onClose: handleClose
74
+ })
68
75
  })
69
- })
70
- });
76
+ });
77
+ }, [
78
+ handleExited,
79
+ handleSave,
80
+ isOpen,
81
+ panelEditor
82
+ ]);
83
+ // If the panel editor is using a repeat variable, we need to wrap the drawer in a VariableContext.Provider
84
+ if (panelEditor?.panelGroupItemId?.repeatVariable) {
85
+ return /*#__PURE__*/ (0, _jsxruntime.jsx)(RepeatVariableWrapper, {
86
+ repeatVariable: panelEditor.panelGroupItemId.repeatVariable,
87
+ children: drawer
88
+ });
89
+ }
90
+ return drawer;
71
91
  };
92
+ // Wraps the drawer in a VariableContext.Provider to provide the repeat variable value
93
+ // This is necessary for previewing panels that use repeat variables and query editor
94
+ function RepeatVariableWrapper({ repeatVariable, children }) {
95
+ const variables = (0, _pluginsystem.useVariableValues)();
96
+ return /*#__PURE__*/ (0, _jsxruntime.jsx)(_pluginsystem.VariableContext.Provider, {
97
+ value: {
98
+ state: {
99
+ ...variables,
100
+ [repeatVariable[0]]: {
101
+ value: repeatVariable[1],
102
+ loading: false
103
+ }
104
+ }
105
+ },
106
+ children: children
107
+ });
108
+ }
@@ -24,6 +24,7 @@ const _jsxruntime = require("react/jsx-runtime");
24
24
  const _material = require("@mui/material");
25
25
  const _Close = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/Close"));
26
26
  const _react = require("react");
27
+ const _pluginsystem = require("@perses-dev/plugin-system");
27
28
  const _context = require("../../context");
28
29
  const _PanelGroupEditorForm = require("./PanelGroupEditorForm");
29
30
  function _interop_require_default(obj) {
@@ -33,6 +34,7 @@ function _interop_require_default(obj) {
33
34
  }
34
35
  function PanelGroupDialog() {
35
36
  const panelGroupEditor = (0, _context.usePanelGroupEditor)();
37
+ const variables = (0, _pluginsystem.useVariableValues)();
36
38
  // When the user clicks close, start closing but don't call the store yet to keep values stable during animtation
37
39
  const [isClosing, setIsClosing] = (0, _react.useState)(false);
38
40
  const handleClose = ()=>setIsClosing(true);
@@ -81,6 +83,7 @@ function PanelGroupDialog() {
81
83
  },
82
84
  children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_PanelGroupEditorForm.PanelGroupEditorForm, {
83
85
  initialValues: panelGroupEditor.initialValues,
86
+ variables: Object.keys(variables),
84
87
  onSubmit: handleSubmit
85
88
  })
86
89
  }),
@@ -32,18 +32,16 @@ const _jsxruntime = require("react/jsx-runtime");
32
32
  const _react = require("react");
33
33
  const _material = require("@mui/material");
34
34
  function PanelGroupEditorForm(props) {
35
- const { initialValues, onSubmit } = props;
35
+ const { initialValues, variables, onSubmit } = props;
36
36
  const [title, setTitle] = (0, _react.useState)(initialValues.title);
37
37
  const [isCollapsed, setIsCollapsed] = (0, _react.useState)(initialValues.isCollapsed);
38
- const handleCollapsedChange = (e)=>{
39
- const next = e.target.value;
40
- setIsCollapsed(next === 'Closed');
41
- };
38
+ const [repeatVariable, setRepeatVariable] = (0, _react.useState)(initialValues.repeatVariable);
42
39
  const handleSubmit = (e)=>{
43
40
  e.preventDefault();
44
41
  onSubmit({
45
42
  title,
46
- isCollapsed
43
+ isCollapsed,
44
+ repeatVariable
47
45
  });
48
46
  };
49
47
  return /*#__PURE__*/ (0, _jsxruntime.jsxs)("form", {
@@ -58,25 +56,21 @@ function PanelGroupEditorForm(props) {
58
56
  label: "Name",
59
57
  variant: "outlined",
60
58
  value: title,
61
- onChange: (e)=>setTitle(e.target.value)
59
+ onChange: (e)=>setTitle(e.target.value),
60
+ "data-testid": "panel-group-editor-name"
62
61
  })
63
62
  }),
64
63
  /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.FormControl, {
65
64
  fullWidth: true,
66
65
  margin: "normal",
67
66
  children: [
68
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.InputLabel, {
69
- id: "select-collapse-state",
70
- children: "Collapse State"
71
- }),
72
- /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Select, {
67
+ /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.TextField, {
68
+ select: true,
73
69
  required: true,
74
- displayEmpty: true,
75
- labelId: "select-collapse-state",
76
70
  label: "Collapse State",
77
71
  size: "small",
78
72
  value: isCollapsed ? 'Closed' : 'Open',
79
- onChange: handleCollapsedChange,
73
+ onChange: (e)=>setIsCollapsed(e.target.value === 'Closed'),
80
74
  children: [
81
75
  /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.MenuItem, {
82
76
  value: "Open",
@@ -87,6 +81,32 @@ function PanelGroupEditorForm(props) {
87
81
  children: "Closed"
88
82
  })
89
83
  ]
84
+ }),
85
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.FormControl, {
86
+ fullWidth: true,
87
+ margin: "normal",
88
+ children: /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.TextField, {
89
+ select: true,
90
+ label: "Repeat Variable",
91
+ variant: "outlined",
92
+ value: repeatVariable ?? '',
93
+ onChange: (e)=>setRepeatVariable(e.target.value === '' ? undefined : e.target.value),
94
+ children: [
95
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.MenuItem, {
96
+ value: "",
97
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Typography, {
98
+ sx: {
99
+ fontStyle: 'italic'
100
+ },
101
+ children: "None"
102
+ })
103
+ }),
104
+ variables?.sort((a, b)=>a.localeCompare(b)).map((variable)=>/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.MenuItem, {
105
+ value: variable,
106
+ children: variable
107
+ }, variable))
108
+ ]
109
+ })
90
110
  })
91
111
  ]
92
112
  })
@@ -28,6 +28,7 @@ _export_star(require("./EditJsonButton"), exports);
28
28
  _export_star(require("./EditJsonDialog"), exports);
29
29
  _export_star(require("./EmptyDashboard"), exports);
30
30
  _export_star(require("./GridLayout"), exports);
31
+ _export_star(require("./LeaveDialog"), exports);
31
32
  _export_star(require("./Panel"), exports);
32
33
  _export_star(require("./PanelDrawer"), exports);
33
34
  _export_star(require("./PanelGroupDialog"), exports);
@@ -50,7 +50,8 @@ const TOOLTIP_TEXT = {
50
50
  movePanel: 'Move',
51
51
  // Variable editor buttons
52
52
  refreshVariableValues: 'Refresh values',
53
- copyVariableValues: 'Copy values to clipboard'
53
+ copyVariableValues: 'Copy values to clipboard',
54
+ queryView: 'Open query view'
54
55
  };
55
56
  const ARIA_LABEL_TEXT = {
56
57
  // Group buttons
@@ -65,5 +66,6 @@ const ARIA_LABEL_TEXT = {
65
66
  duplicatePanel: (panelName)=>`duplicate panel ${panelName}`,
66
67
  deletePanel: (panelName)=>`delete panel ${panelName}`,
67
68
  showPanelActions: (panelName)=>`show panel actions for ${panelName}`,
68
- movePanel: (panelName)=>`move panel ${panelName}`
69
+ movePanel: (panelName)=>`move panel ${panelName}`,
70
+ openQueryView: (panelName)=>`open query view for panel ${panelName}`
69
71
  };
@@ -61,14 +61,15 @@ function useDashboardStore(selector) {
61
61
  return (0, _traditional.useStoreWithEqualityFn)(store, selector, _shallow.shallow);
62
62
  }
63
63
  function DashboardProvider(props) {
64
+ // Prevent calling createDashboardStore every time it rerenders
64
65
  const createDashboardStore = (0, _react.useCallback)(initStore, [
65
66
  props
66
67
  ]);
68
+ const [store] = (0, _react.useState)(createDashboardStore(props));
67
69
  // load plugin to retrieve initial spec if default panel kind is defined
68
70
  const { defaultPluginKinds } = (0, _pluginsystem.usePluginRegistry)();
69
71
  const defaultPanelKind = defaultPluginKinds?.['Panel'] ?? '';
70
72
  const { data: plugin } = (0, _pluginsystem.usePlugin)('Panel', defaultPanelKind);
71
- const [store] = (0, _react.useState)(createDashboardStore(props)); // prevent calling createDashboardStore every time it rerenders
72
73
  (0, _react.useEffect)(()=>{
73
74
  if (plugin === undefined) return;
74
75
  const defaultPanelSpec = plugin.createInitialOptions ? plugin.createInitialOptions() : {};
@@ -90,12 +91,8 @@ function DashboardProvider(props) {
90
91
  }
91
92
  function initStore(props) {
92
93
  const { initialState: { dashboardResource, isEditMode, viewPanelRef, setViewPanelRef } } = props;
93
- const { kind, metadata, spec: { display, duration, refreshInterval = _core.DEFAULT_REFRESH_INTERVAL, datasources } } = dashboardResource;
94
+ const { kind, metadata, spec: { display, duration, refreshInterval = _core.DEFAULT_REFRESH_INTERVAL, datasources, layouts = [], panels = {} } } = dashboardResource;
94
95
  const ttl = 'ttl' in dashboardResource.spec ? dashboardResource.spec.ttl : undefined;
95
- let { spec: { layouts, panels } } = dashboardResource;
96
- // Set fallbacks in case the frontend is used with a non-Perses backend
97
- layouts = layouts ?? [];
98
- panels = panels ?? {};
99
96
  const store = (0, _zustand.createStore)()((0, _immer.immer)((0, _middleware.devtools)((...args)=>{
100
97
  const [set] = args;
101
98
  return {
@@ -118,9 +115,11 @@ function initStore(props) {
118
115
  datasources,
119
116
  ttl,
120
117
  isEditMode: !!isEditMode,
121
- setEditMode: (isEditMode)=>set({
118
+ setEditMode: (isEditMode)=>{
119
+ set({
122
120
  isEditMode
123
- }),
121
+ });
122
+ },
124
123
  setDashboard: ({ kind, metadata, spec: { display, panels = {}, layouts = [], duration, refreshInterval, datasources = {} } })=>{
125
124
  set((state)=>{
126
125
  state.kind = kind;
@@ -24,12 +24,12 @@ const _jsxruntime = require("react/jsx-runtime");
24
24
  const _usequeryparams = require("use-query-params");
25
25
  const _DashboardProvider = require("./DashboardProvider");
26
26
  function DashboardProviderWithQueryParams({ children, initialState }) {
27
- const [viewPanelRef, setViewPanelRef] = (0, _usequeryparams.useQueryParam)('viewPanelRef', _usequeryparams.StringParam);
27
+ const [viewPanelRef, setViewPanelRef] = (0, _usequeryparams.useQueryParam)('viewPanelRef', _usequeryparams.JsonParam);
28
28
  return /*#__PURE__*/ (0, _jsxruntime.jsx)(_DashboardProvider.DashboardProvider, {
29
29
  initialState: {
30
+ ...initialState,
30
31
  viewPanelRef: viewPanelRef ?? undefined,
31
- setViewPanelRef: setViewPanelRef,
32
- ...initialState
32
+ setViewPanelRef: setViewPanelRef
33
33
  },
34
34
  children: children
35
35
  });
@@ -42,6 +42,7 @@ function createPanelEditorSlice() {
42
42
  }
43
43
  const editorState = {
44
44
  mode: 'update',
45
+ panelGroupItemId: panelGroupItemId,
45
46
  initialValues: {
46
47
  groupId: panelGroupItemId.panelGroupId,
47
48
  panelDefinition: panelToEdit
@@ -29,12 +29,14 @@ const createPanelGroupEditorSlice = (set, get)=>({
29
29
  mode: 'Add',
30
30
  initialValues: {
31
31
  title: '',
32
- isCollapsed: false
32
+ isCollapsed: false,
33
+ repeatVariable: ''
33
34
  },
34
35
  applyChanges (next) {
35
36
  const newGroup = (0, _panelgroupslice.createEmptyPanelGroup)();
36
37
  newGroup.title = next.title;
37
38
  newGroup.isCollapsed = next.isCollapsed;
39
+ newGroup.repeatVariable = next.repeatVariable;
38
40
  set((draft)=>{
39
41
  (0, _panelgroupslice.addPanelGroup)(draft, newGroup);
40
42
  });
@@ -60,7 +62,8 @@ const createPanelGroupEditorSlice = (set, get)=>({
60
62
  mode: 'Edit',
61
63
  initialValues: {
62
64
  title: existingGroup.title ?? '',
63
- isCollapsed: existingGroup.isCollapsed
65
+ isCollapsed: existingGroup.isCollapsed,
66
+ repeatVariable: existingGroup.repeatVariable ?? ''
64
67
  },
65
68
  applyChanges (next) {
66
69
  set((draft)=>{
@@ -70,6 +73,7 @@ const createPanelGroupEditorSlice = (set, get)=>({
70
73
  }
71
74
  group.title = next.title;
72
75
  group.isCollapsed = next.isCollapsed;
76
+ group.repeatVariable = next.repeatVariable;
73
77
  });
74
78
  },
75
79
  close () {
@@ -100,6 +100,7 @@ function convertLayoutsToPanelGroups(layouts) {
100
100
  panelGroups[panelGroupId] = {
101
101
  id: panelGroupId,
102
102
  isCollapsed: layout.spec.display?.collapse?.open === false,
103
+ repeatVariable: layout.spec.repeatVariable,
103
104
  title: layout.spec.display?.title,
104
105
  itemLayouts,
105
106
  itemPanelKeys
@@ -55,12 +55,13 @@ function getViewPanelGroupId(panelGroups, panelGroupItemId, panelRef) {
55
55
  // Find the PanelGroupItemId of a Panel from a PanelRef
56
56
  function findPanelGroupItemIdOfPanelRef(panelGroups, panelRef) {
57
57
  for (const panelGroup of Object.values(panelGroups)){
58
- const itemPanel = Object.entries(panelGroup.itemPanelKeys ?? []).find(([_, value])=>value === panelRef);
58
+ const itemPanel = Object.entries(panelGroup.itemPanelKeys ?? []).find(([_, value])=>value === panelRef.ref);
59
59
  if (itemPanel) {
60
60
  const [key] = itemPanel;
61
61
  return {
62
62
  panelGroupId: panelGroup.id,
63
- panelGroupItemLayoutId: key
63
+ panelGroupItemLayoutId: key,
64
+ repeatVariable: panelRef.repeatVariable
64
65
  };
65
66
  }
66
67
  }
@@ -73,7 +74,13 @@ function findPanelRefOfPanelGroupItemId(panelGroups, panelGroupItemId) {
73
74
  }
74
75
  const panelGroup = panelGroups[panelGroupItemId.panelGroupId];
75
76
  if (panelGroup) {
76
- return panelGroup.itemPanelKeys[panelGroupItemId.panelGroupItemLayoutId];
77
+ const panelRef = panelGroup.itemPanelKeys[panelGroupItemId.panelGroupItemLayoutId];
78
+ if (panelRef) {
79
+ return {
80
+ ref: panelRef,
81
+ repeatVariable: panelGroupItemId.repeatVariable
82
+ };
83
+ }
77
84
  }
78
85
  return undefined;
79
86
  }
@@ -362,7 +362,7 @@ function createVariableDefinitionStore({ initialVariableDefinitions = [], extern
362
362
  return (0, _utils.checkSavedDefaultVariableStatus)(get().variableDefinitions, get().variableState);
363
363
  }
364
364
  }))));
365
- return store; // TODO: @Gladorme check if we can avoid this cast
365
+ return store;
366
366
  }
367
367
  function VariableProvider({ children, initialVariableDefinitions = [], externalVariableDefinitions = [], builtinVariableDefinitions = [] }) {
368
368
  const [store] = (0, _react.useState)(()=>createVariableDefinitionStore({
@@ -82,11 +82,11 @@ function convertPanelGroupsToLayouts(panelGroups, panelGroupOrder) {
82
82
  if (group === undefined) {
83
83
  throw new Error('panel group not found');
84
84
  }
85
- const { title, isCollapsed, itemLayouts, itemPanelKeys } = group;
85
+ const { title, isCollapsed, repeatVariable, itemLayouts, itemPanelKeys } = group;
86
86
  let display = undefined;
87
- if (title) {
87
+ if (title || isCollapsed !== undefined) {
88
88
  display = {
89
- title,
89
+ title: title ?? '',
90
90
  collapse: {
91
91
  open: !isCollapsed
92
92
  }
@@ -108,7 +108,8 @@ function convertPanelGroupsToLayouts(panelGroups, panelGroupOrder) {
108
108
  height: layout.h,
109
109
  content: (0, _core.createPanelRef)(panelKey)
110
110
  };
111
- })
111
+ }),
112
+ repeatVariable: repeatVariable
112
113
  }
113
114
  };
114
115
  layouts.push(layout);