@perses-dev/dashboards 0.52.0-rc.0 → 0.52.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 (33) hide show
  1. package/dist/cjs/components/LeaveDialog/LeaveDialog.js +45 -17
  2. package/dist/cjs/components/Panel/PanelActions.js +1 -1
  3. package/dist/cjs/components/PanelDrawer/PanelEditorForm.js +204 -185
  4. package/dist/cjs/components/Variables/VariableEditor.js +22 -15
  5. package/dist/cjs/context/DashboardProvider/DashboardProviderWithQueryParams.js +1 -1
  6. package/dist/cjs/context/DashboardProvider/duplicate-panel-slice.js +1 -1
  7. package/dist/cjs/context/DashboardProvider/panel-editor-slice.js +1 -2
  8. package/dist/components/LeaveDialog/LeaveDialog.d.ts +6 -1
  9. package/dist/components/LeaveDialog/LeaveDialog.d.ts.map +1 -1
  10. package/dist/components/LeaveDialog/LeaveDialog.js +40 -15
  11. package/dist/components/LeaveDialog/LeaveDialog.js.map +1 -1
  12. package/dist/components/Panel/HeaderIconButton.d.ts +1 -1
  13. package/dist/components/Panel/PanelActions.js +1 -1
  14. package/dist/components/Panel/PanelActions.js.map +1 -1
  15. package/dist/components/PanelDrawer/PanelEditorForm.d.ts.map +1 -1
  16. package/dist/components/PanelDrawer/PanelEditorForm.js +207 -188
  17. package/dist/components/PanelDrawer/PanelEditorForm.js.map +1 -1
  18. package/dist/components/Variables/VariableEditor.d.ts.map +1 -1
  19. package/dist/components/Variables/VariableEditor.js +24 -17
  20. package/dist/components/Variables/VariableEditor.js.map +1 -1
  21. package/dist/context/DashboardProvider/DashboardProviderWithQueryParams.d.ts.map +1 -1
  22. package/dist/context/DashboardProvider/DashboardProviderWithQueryParams.js +1 -1
  23. package/dist/context/DashboardProvider/DashboardProviderWithQueryParams.js.map +1 -1
  24. package/dist/context/DashboardProvider/duplicate-panel-slice.js +2 -2
  25. package/dist/context/DashboardProvider/duplicate-panel-slice.js.map +1 -1
  26. package/dist/context/DashboardProvider/panel-editor-slice.d.ts.map +1 -1
  27. package/dist/context/DashboardProvider/panel-editor-slice.js +2 -3
  28. package/dist/context/DashboardProvider/panel-editor-slice.js.map +1 -1
  29. package/dist/utils/panelUtils.d.ts +3 -0
  30. package/dist/utils/panelUtils.d.ts.map +1 -1
  31. package/dist/utils/panelUtils.js +3 -0
  32. package/dist/utils/panelUtils.js.map +1 -1
  33. package/package.json +6 -6
@@ -14,31 +14,59 @@
14
14
  Object.defineProperty(exports, "__esModule", {
15
15
  value: true
16
16
  });
17
- Object.defineProperty(exports, "LeaveDialog", {
18
- enumerable: true,
19
- get: function() {
17
+ function _export(target, all) {
18
+ for(var name in all)Object.defineProperty(target, name, {
19
+ enumerable: true,
20
+ get: all[name]
21
+ });
22
+ }
23
+ _export(exports, {
24
+ LeaveDialog: function() {
20
25
  return LeaveDialog;
26
+ },
27
+ Prompt: function() {
28
+ return Prompt;
21
29
  }
22
30
  });
23
31
  const _jsxruntime = require("react/jsx-runtime");
24
32
  const _react = require("react");
25
- function LeaveDialog({ original, current }) {
33
+ const _reactrouterdom = require("react-router-dom");
34
+ const _components = require("@perses-dev/components");
35
+ const handleRouteChange = (event)=>{
36
+ event.preventDefault();
37
+ event.returnValue = ''; // Required for Chrome
38
+ return ''; // Required for other browsers
39
+ };
40
+ function Prompt({ isBlocked, message }) {
41
+ const blocker = (0, _reactrouterdom.useBlocker)(isBlocked);
42
+ const isBlockedState = blocker.state === 'blocked';
43
+ const isProceedingState = blocker.state === 'proceeding';
26
44
  (0, _react.useEffect)(()=>{
27
- const handleBeforeUnload = (event)=>{
28
- if (JSON.stringify(original) === JSON.stringify(current)) {
29
- return null;
30
- }
31
- event.preventDefault();
32
- event.returnValue = ''; // Required for Chrome
33
- return ''; // Required for other browsers
34
- };
35
- window.addEventListener('beforeunload', handleBeforeUnload);
45
+ if (isBlocked) {
46
+ window.addEventListener('beforeunload', handleRouteChange);
47
+ } else {
48
+ window.removeEventListener('beforeunload', handleRouteChange);
49
+ }
36
50
  return ()=>{
37
- window.removeEventListener('beforeunload', handleBeforeUnload);
51
+ window.removeEventListener('beforeunload', handleRouteChange);
38
52
  };
39
53
  }, [
40
- original,
41
- current
54
+ blocker,
55
+ isBlocked,
56
+ isBlockedState
42
57
  ]);
43
- return /*#__PURE__*/ (0, _jsxruntime.jsx)(_jsxruntime.Fragment, {});
58
+ const handleDiscardChanges = ()=>blocker.proceed?.();
59
+ const handleCancel = ()=>blocker.reset?.();
60
+ return /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.DiscardChangesConfirmationDialog, {
61
+ description: message,
62
+ isOpen: isBlockedState || isProceedingState,
63
+ onDiscardChanges: handleDiscardChanges,
64
+ onCancel: handleCancel
65
+ });
66
+ }
67
+ function LeaveDialog({ original, current }) {
68
+ return /*#__PURE__*/ (0, _jsxruntime.jsx)(Prompt, {
69
+ isBlocked: JSON.stringify(original) !== JSON.stringify(current),
70
+ message: "You have unsaved changes, are you sure you want to leave?"
71
+ });
44
72
  }
@@ -344,7 +344,7 @@ const OverflowMenu = ({ children, title })=>{
344
344
  // do not show overflow menu if there is no content (for example, edit actions are hidden)
345
345
  const hasContent = /*#__PURE__*/ (0, _react.isValidElement)(children) || Array.isArray(children) && children.some(_react.isValidElement);
346
346
  if (!hasContent) {
347
- return undefined;
347
+ return null;
348
348
  }
349
349
  const handleClick = (event)=>{
350
350
  setAnchorPosition(event.currentTarget.getBoundingClientRect());
@@ -31,6 +31,7 @@ _export(exports, {
31
31
  const _jsxruntime = require("react/jsx-runtime");
32
32
  const _react = require("react");
33
33
  const _material = require("@mui/material");
34
+ const _core = require("@perses-dev/core");
34
35
  const _components = require("@perses-dev/components");
35
36
  const _pluginsystem = require("@perses-dev/plugin-system");
36
37
  const _reacthookform = require("react-hook-form");
@@ -40,6 +41,7 @@ const _PanelPreview = require("./PanelPreview");
40
41
  const _usePanelEditor = require("./usePanelEditor");
41
42
  function PanelEditorForm(props) {
42
43
  const { initialValues, initialAction, onSave, onClose } = props;
44
+ const pluginEditorRef = (0, _react.useRef)(null);
43
45
  const panelGroups = (0, _context.useListPanelGroups)();
44
46
  const { panelDefinition, setName, setDescription, setLinks, setQueries, setPlugin, setPanelDefinition } = (0, _usePanelEditor.usePanelEditor)(initialValues.panelDefinition);
45
47
  const { plugin } = panelDefinition.spec;
@@ -50,6 +52,9 @@ function PanelEditorForm(props) {
50
52
  mode: 'onBlur',
51
53
  defaultValues: initialValues
52
54
  });
55
+ const { dashboard } = (0, _context.useDashboard)();
56
+ const dashboardDuration = dashboard?.kind === 'Dashboard' ? dashboard.spec.duration : _core.DEFAULT_DASHBOARD_DURATION;
57
+ const initialTimeRange = (0, _pluginsystem.useInitialTimeRange)(dashboardDuration);
53
58
  // Use common plugin editor logic even though we've split the inputs up in this form
54
59
  const pluginEditor = (0, _pluginsystem.usePluginEditor)({
55
60
  pluginTypes: [
@@ -88,9 +93,11 @@ function PanelEditorForm(props) {
88
93
  setLinks,
89
94
  links
90
95
  ]);
91
- const processForm = (data)=>{
96
+ const processForm = (0, _react.useCallback)((data)=>{
92
97
  onSave(data);
93
- };
98
+ }, [
99
+ onSave
100
+ ]);
94
101
  // When user click on cancel, several possibilities:
95
102
  // - create action: ask for discard approval
96
103
  // - update action: ask for discard approval if changed
@@ -123,199 +130,211 @@ function PanelEditorForm(props) {
123
130
  control: form.control,
124
131
  name: 'panelDefinition.spec.plugin.kind'
125
132
  });
126
- return /*#__PURE__*/ (0, _jsxruntime.jsxs)(_reacthookform.FormProvider, {
127
- ...form,
128
- children: [
129
- /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Box, {
130
- sx: {
131
- display: 'flex',
132
- alignItems: 'center',
133
- padding: (theme)=>theme.spacing(1, 2),
134
- borderBottom: (theme)=>`1px solid ${theme.palette.divider}`
135
- },
136
- children: [
137
- /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Typography, {
138
- variant: "h2",
139
- children: [
140
- titleAction,
141
- " Panel"
142
- ]
143
- }),
144
- /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Stack, {
145
- direction: "row",
146
- spacing: 1,
147
- marginLeft: "auto",
148
- children: [
149
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Button, {
150
- variant: "contained",
151
- disabled: !form.formState.isValid,
152
- onClick: form.handleSubmit(processForm),
153
- children: submitText
154
- }),
155
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Button, {
156
- color: "secondary",
157
- variant: "outlined",
158
- onClick: handleCancel,
159
- children: "Cancel"
160
- })
161
- ]
162
- })
163
- ]
164
- }),
165
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Box, {
166
- id: panelEditorFormId,
167
- sx: {
168
- flex: 1,
169
- overflowY: 'scroll',
170
- padding: (theme)=>theme.spacing(2)
171
- },
172
- children: /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Grid, {
173
- container: true,
174
- spacing: 2,
133
+ const { timeRange } = (0, _pluginsystem.useTimeRangeParams)(initialTimeRange);
134
+ const handleSubmit = (0, _react.useCallback)(()=>{
135
+ pluginEditorRef.current?.flushChanges?.();
136
+ form.handleSubmit(processForm)();
137
+ }, [
138
+ form,
139
+ processForm
140
+ ]);
141
+ return /*#__PURE__*/ (0, _jsxruntime.jsx)(_pluginsystem.TimeRangeProvider, {
142
+ timeRange: timeRange,
143
+ children: /*#__PURE__*/ (0, _jsxruntime.jsxs)(_reacthookform.FormProvider, {
144
+ ...form,
145
+ children: [
146
+ /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Box, {
147
+ sx: {
148
+ display: 'flex',
149
+ alignItems: 'center',
150
+ padding: (theme)=>theme.spacing(1, 2),
151
+ borderBottom: (theme)=>`1px solid ${theme.palette.divider}`
152
+ },
175
153
  children: [
176
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Grid, {
177
- item: true,
178
- xs: 8,
179
- children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_reacthookform.Controller, {
180
- control: form.control,
181
- name: "panelDefinition.spec.display.name",
182
- render: ({ field, fieldState })=>/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.TextField, {
183
- ...field,
184
- required: true,
185
- fullWidth: true,
186
- label: "Name",
187
- error: !!fieldState.error,
188
- helperText: fieldState.error?.message,
189
- value: watchedName ?? '',
190
- onChange: (event)=>{
191
- field.onChange(event);
192
- setName(event.target.value);
193
- }
194
- })
195
- })
196
- }),
197
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Grid, {
198
- item: true,
199
- xs: 4,
200
- children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_reacthookform.Controller, {
201
- control: form.control,
202
- name: "groupId",
203
- render: ({ field, fieldState })=>/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.TextField, {
204
- select: true,
205
- ...field,
206
- required: true,
207
- fullWidth: true,
208
- label: "Group",
209
- error: !!fieldState.error,
210
- helperText: fieldState.error?.message,
211
- onChange: (event)=>{
212
- field.onChange(event);
213
- },
214
- children: panelGroups.map((panelGroup, index)=>/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.MenuItem, {
215
- value: panelGroup.id,
216
- children: panelGroup.title ?? `Group ${index + 1}`
217
- }, panelGroup.id))
218
- })
219
- })
220
- }),
221
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Grid, {
222
- item: true,
223
- xs: 8,
224
- children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_reacthookform.Controller, {
225
- control: form.control,
226
- name: "panelDefinition.spec.display.description",
227
- render: ({ field, fieldState })=>/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.TextField, {
228
- ...field,
229
- fullWidth: true,
230
- label: "Description",
231
- error: !!fieldState.error,
232
- helperText: fieldState.error?.message,
233
- value: watchedDescription ?? '',
234
- onChange: (event)=>{
235
- field.onChange(event);
236
- setDescription(event.target.value);
237
- }
238
- })
239
- })
240
- }),
241
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Grid, {
242
- item: true,
243
- xs: 4,
244
- children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_reacthookform.Controller, {
245
- control: form.control,
246
- name: "panelDefinition.spec.plugin.kind",
247
- render: ({ field, fieldState })=>/*#__PURE__*/ (0, _jsxruntime.jsx)(_pluginsystem.PluginKindSelect, {
248
- ...field,
249
- pluginTypes: [
250
- 'Panel'
251
- ],
252
- required: true,
253
- fullWidth: true,
254
- label: "Type",
255
- disabled: pluginEditor.isLoading,
256
- error: !!pluginEditor.error || !!fieldState.error,
257
- helperText: pluginEditor.error?.message ?? fieldState.error?.message,
258
- value: {
259
- type: 'Panel',
260
- kind: watchedPluginKind
261
- },
262
- onChange: (event)=>{
263
- field.onChange(event.kind);
264
- pluginEditor.onSelectionChange(event);
265
- }
266
- })
267
- })
154
+ /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Typography, {
155
+ variant: "h2",
156
+ children: [
157
+ titleAction,
158
+ " Panel"
159
+ ]
268
160
  }),
269
- /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Grid, {
270
- item: true,
271
- xs: 12,
161
+ /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Stack, {
162
+ direction: "row",
163
+ spacing: 1,
164
+ marginLeft: "auto",
272
165
  children: [
273
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Typography, {
274
- variant: "h4",
275
- marginBottom: 1,
276
- children: "Preview"
166
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Button, {
167
+ variant: "contained",
168
+ disabled: !form.formState.isValid,
169
+ onClick: handleSubmit,
170
+ children: submitText
277
171
  }),
278
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.ErrorBoundary, {
279
- FallbackComponent: _components.ErrorAlert,
280
- children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_PanelPreview.PanelPreview, {
281
- panelDefinition: panelDefinition
282
- })
172
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Button, {
173
+ color: "secondary",
174
+ variant: "outlined",
175
+ onClick: handleCancel,
176
+ children: "Cancel"
283
177
  })
284
178
  ]
285
- }),
286
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Grid, {
287
- item: true,
288
- xs: 12,
289
- children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.ErrorBoundary, {
290
- FallbackComponent: _components.ErrorAlert,
291
- children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_pluginsystem.PanelSpecEditor, {
179
+ })
180
+ ]
181
+ }),
182
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Box, {
183
+ id: panelEditorFormId,
184
+ sx: {
185
+ flex: 1,
186
+ overflowY: 'scroll',
187
+ padding: (theme)=>theme.spacing(2)
188
+ },
189
+ children: /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Grid, {
190
+ container: true,
191
+ spacing: 2,
192
+ children: [
193
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Grid, {
194
+ item: true,
195
+ xs: 8,
196
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_reacthookform.Controller, {
197
+ control: form.control,
198
+ name: "panelDefinition.spec.display.name",
199
+ render: ({ field, fieldState })=>/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.TextField, {
200
+ ...field,
201
+ required: true,
202
+ fullWidth: true,
203
+ label: "Name",
204
+ error: !!fieldState.error,
205
+ helperText: fieldState.error?.message,
206
+ value: watchedName ?? '',
207
+ onChange: (event)=>{
208
+ field.onChange(event);
209
+ setName(event.target.value);
210
+ }
211
+ })
212
+ })
213
+ }),
214
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Grid, {
215
+ item: true,
216
+ xs: 4,
217
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_reacthookform.Controller, {
218
+ control: form.control,
219
+ name: "groupId",
220
+ render: ({ field, fieldState })=>/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.TextField, {
221
+ select: true,
222
+ ...field,
223
+ required: true,
224
+ fullWidth: true,
225
+ label: "Group",
226
+ error: !!fieldState.error,
227
+ helperText: fieldState.error?.message,
228
+ onChange: (event)=>{
229
+ field.onChange(event);
230
+ },
231
+ children: panelGroups.map((panelGroup, index)=>/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.MenuItem, {
232
+ value: panelGroup.id,
233
+ children: panelGroup.title ?? `Group ${index + 1}`
234
+ }, panelGroup.id))
235
+ })
236
+ })
237
+ }),
238
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Grid, {
239
+ item: true,
240
+ xs: 8,
241
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_reacthookform.Controller, {
242
+ control: form.control,
243
+ name: "panelDefinition.spec.display.description",
244
+ render: ({ field, fieldState })=>/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.TextField, {
245
+ ...field,
246
+ fullWidth: true,
247
+ label: "Description",
248
+ error: !!fieldState.error,
249
+ helperText: fieldState.error?.message,
250
+ value: watchedDescription ?? '',
251
+ onChange: (event)=>{
252
+ field.onChange(event);
253
+ setDescription(event.target.value);
254
+ }
255
+ })
256
+ })
257
+ }),
258
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Grid, {
259
+ item: true,
260
+ xs: 4,
261
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_reacthookform.Controller, {
292
262
  control: form.control,
293
- panelDefinition: panelDefinition,
294
- onJSONChange: handlePanelDefinitionChange,
295
- onQueriesChange: (queries)=>{
296
- setQueries(queries);
297
- },
298
- onPluginSpecChange: (spec)=>{
299
- pluginEditor.onSpecChange(spec);
300
- }
263
+ name: "panelDefinition.spec.plugin.kind",
264
+ render: ({ field, fieldState })=>/*#__PURE__*/ (0, _jsxruntime.jsx)(_pluginsystem.PluginKindSelect, {
265
+ ...field,
266
+ pluginTypes: [
267
+ 'Panel'
268
+ ],
269
+ required: true,
270
+ fullWidth: true,
271
+ label: "Type",
272
+ disabled: pluginEditor.isLoading,
273
+ error: !!pluginEditor.error || !!fieldState.error,
274
+ helperText: pluginEditor.error?.message ?? fieldState.error?.message,
275
+ value: {
276
+ type: 'Panel',
277
+ kind: watchedPluginKind
278
+ },
279
+ onChange: (event)=>{
280
+ field.onChange(event.kind);
281
+ pluginEditor.onSelectionChange(event);
282
+ }
283
+ })
284
+ })
285
+ }),
286
+ /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Grid, {
287
+ item: true,
288
+ xs: 12,
289
+ children: [
290
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Typography, {
291
+ variant: "h4",
292
+ marginBottom: 1,
293
+ children: "Preview"
294
+ }),
295
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.ErrorBoundary, {
296
+ FallbackComponent: _components.ErrorAlert,
297
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_PanelPreview.PanelPreview, {
298
+ panelDefinition: panelDefinition
299
+ })
300
+ })
301
+ ]
302
+ }),
303
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Grid, {
304
+ item: true,
305
+ xs: 12,
306
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.ErrorBoundary, {
307
+ FallbackComponent: _components.ErrorAlert,
308
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_pluginsystem.PanelSpecEditor, {
309
+ ref: pluginEditorRef,
310
+ control: form.control,
311
+ panelDefinition: panelDefinition,
312
+ onJSONChange: handlePanelDefinitionChange,
313
+ onQueriesChange: (queries)=>{
314
+ setQueries(queries);
315
+ },
316
+ onPluginSpecChange: (spec)=>{
317
+ pluginEditor.onSpecChange(spec);
318
+ }
319
+ })
301
320
  })
302
321
  })
303
- })
304
- ]
322
+ ]
323
+ })
324
+ }),
325
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.DiscardChangesConfirmationDialog, {
326
+ description: "You have unapplied changes in this panel. Are you sure you want to discard these changes? Changes cannot be recovered.",
327
+ isOpen: isDiscardDialogOpened,
328
+ onCancel: ()=>{
329
+ setDiscardDialogOpened(false);
330
+ },
331
+ onDiscardChanges: ()=>{
332
+ setDiscardDialogOpened(false);
333
+ onClose();
334
+ }
305
335
  })
306
- }),
307
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.DiscardChangesConfirmationDialog, {
308
- description: "You have unapplied changes in this panel. Are you sure you want to discard these changes? Changes cannot be recovered.",
309
- isOpen: isDiscardDialogOpened,
310
- onCancel: ()=>{
311
- setDiscardDialogOpened(false);
312
- },
313
- onDiscardChanges: ()=>{
314
- setDiscardDialogOpened(false);
315
- onClose();
316
- }
317
- })
318
- ]
336
+ ]
337
+ })
319
338
  });
320
339
  }
321
340
  const panelEditorFormId = 'panel-editor-form';
@@ -32,6 +32,7 @@ const _jsxruntime = require("react/jsx-runtime");
32
32
  const _react = require("react");
33
33
  const _material = require("@mui/material");
34
34
  const _Plus = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/Plus"));
35
+ const _core = require("@perses-dev/core");
35
36
  const _useimmer = require("use-immer");
36
37
  const _Pencil = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/Pencil"));
37
38
  const _TrashCan = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/TrashCan"));
@@ -163,26 +164,32 @@ function VariableEditor(props) {
163
164
  draft.push(v);
164
165
  });
165
166
  };
167
+ const { dashboard } = (0, _context.useDashboard)();
168
+ const dashboardDuration = dashboard?.kind === 'Dashboard' ? dashboard.spec.duration : _core.DEFAULT_DASHBOARD_DURATION;
169
+ const initialTimeRange = (0, _pluginsystem.useInitialTimeRange)(dashboardDuration);
166
170
  return /*#__PURE__*/ (0, _jsxruntime.jsxs)(_jsxruntime.Fragment, {
167
171
  children: [
168
172
  currentEditingVariableDefinition && /*#__PURE__*/ (0, _jsxruntime.jsx)(_pluginsystem.ValidationProvider, {
169
- children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_pluginsystem.VariableEditorForm, {
170
- initialVariableDefinition: currentEditingVariableDefinition,
171
- action: variableFormAction,
172
- isDraft: true,
173
- onActionChange: setVariableFormAction,
174
- onSave: (definition)=>{
175
- setVariableDefinitions((draft)=>{
176
- draft[variableEditIdx] = definition;
173
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_pluginsystem.TimeRangeProvider, {
174
+ timeRange: initialTimeRange,
175
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_pluginsystem.VariableEditorForm, {
176
+ initialVariableDefinition: currentEditingVariableDefinition,
177
+ action: variableFormAction,
178
+ isDraft: true,
179
+ onActionChange: setVariableFormAction,
180
+ onSave: (definition)=>{
181
+ setVariableDefinitions((draft)=>{
182
+ draft[variableEditIdx] = definition;
183
+ setVariableEditIdx(null);
184
+ });
185
+ },
186
+ onClose: ()=>{
187
+ if (variableFormAction === 'create') {
188
+ removeVariable(variableEditIdx);
189
+ }
177
190
  setVariableEditIdx(null);
178
- });
179
- },
180
- onClose: ()=>{
181
- if (variableFormAction === 'create') {
182
- removeVariable(variableEditIdx);
183
191
  }
184
- setVariableEditIdx(null);
185
- }
192
+ })
186
193
  })
187
194
  }),
188
195
  !currentEditingVariableDefinition && /*#__PURE__*/ (0, _jsxruntime.jsxs)(_jsxruntime.Fragment, {
@@ -1,4 +1,4 @@
1
- // Copyright 2024 The Perses Authors
1
+ // Copyright 2025 The Perses Authors
2
2
  // Licensed under the Apache License, Version 2.0 (the "License");
3
3
  // you may not use this file except in compliance with the License.
4
4
  // You may obtain a copy of the License at
@@ -49,7 +49,7 @@ function createDuplicatePanelSlice() {
49
49
  if (matchingLayout === undefined) {
50
50
  throw new Error(`Cannot find layout for Panel with key '${panelKey}'`);
51
51
  }
52
- const dupePanelKey = (0, _panelUtils.getValidPanelKey)(panelKey, panels);
52
+ const dupePanelKey = crypto.randomUUID().replaceAll('-', '');
53
53
  state.panels[dupePanelKey] = panelToDupe;
54
54
  const duplicateLayout = {
55
55
  i: (0, _common.generateId)().toString(),
@@ -110,8 +110,7 @@ function createPanelEditorSlice() {
110
110
  panelDefinition: get().initialValues?.panelDefinition ?? (0, _common.createPanelDefinition)()
111
111
  },
112
112
  applyChanges: (next)=>{
113
- const name = next.panelDefinition.spec.display.name;
114
- const panelKey = (0, _utils.getValidPanelKey)(name, get().panels);
113
+ const panelKey = crypto.randomUUID().replaceAll('-', '');
115
114
  set((state)=>{
116
115
  // Add a panel
117
116
  state.panels[panelKey] = next.panelDefinition;
@@ -1,5 +1,10 @@
1
1
  import { DashboardResource, EphemeralDashboardResource } from '@perses-dev/core';
2
- import { ReactNode } from 'react';
2
+ import { ReactElement, ReactNode } from 'react';
3
+ export interface LeaveDialogProps {
4
+ isBlocked: boolean;
5
+ message: string;
6
+ }
7
+ export declare function Prompt({ isBlocked, message }: LeaveDialogProps): ReactElement;
3
8
  export declare function LeaveDialog({ original, current, }: {
4
9
  original: DashboardResource | EphemeralDashboardResource | undefined;
5
10
  current: DashboardResource | EphemeralDashboardResource;
@@ -1 +1 @@
1
- {"version":3,"file":"LeaveDialog.d.ts","sourceRoot":"","sources":["../../../src/components/LeaveDialog/LeaveDialog.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAE,iBAAiB,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AACjF,OAAO,EAAE,SAAS,EAAa,MAAM,OAAO,CAAC;AAE7C,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EACR,OAAO,GACR,EAAE;IACD,QAAQ,EAAE,iBAAiB,GAAG,0BAA0B,GAAG,SAAS,CAAC;IACrE,OAAO,EAAE,iBAAiB,GAAG,0BAA0B,CAAC;CACzD,GAAG,SAAS,CAmBZ"}
1
+ {"version":3,"file":"LeaveDialog.d.ts","sourceRoot":"","sources":["../../../src/components/LeaveDialog/LeaveDialog.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAE,iBAAiB,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,SAAS,EAAa,MAAM,OAAO,CAAC;AAU3D,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAMD,wBAAgB,MAAM,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,gBAAgB,GAAG,YAAY,CA4B7E;AAKD,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EACR,OAAO,GACR,EAAE;IACD,QAAQ,EAAE,iBAAiB,GAAG,0BAA0B,GAAG,SAAS,CAAC;IACrE,OAAO,EAAE,iBAAiB,GAAG,0BAA0B,CAAC;CACzD,GAAG,SAAS,CAOZ"}