@perses-dev/dashboards 0.41.0 → 0.42.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 (89) hide show
  1. package/dist/cjs/components/DashboardStickyToolbar/DashboardStickyToolbar.js +2 -2
  2. package/dist/cjs/components/DashboardToolbar/DashboardToolbar.js +11 -9
  3. package/dist/cjs/components/Datasources/DatasourceEditor.js +236 -0
  4. package/dist/cjs/components/Datasources/EditDatasourcesButton.js +109 -0
  5. package/dist/cjs/components/Datasources/index.js +31 -0
  6. package/dist/cjs/components/EditJsonDialog/EditJsonDialog.js +12 -1
  7. package/dist/cjs/components/PanelDrawer/PanelEditorForm.js +3 -41
  8. package/dist/cjs/components/PanelDrawer/index.js +1 -0
  9. package/dist/cjs/components/QuerySummaryTable/QuerySummaryTable.js +2 -2
  10. package/dist/cjs/components/Variables/TemplateVariable.js +139 -51
  11. package/dist/cjs/components/Variables/VariableList.js +1 -1
  12. package/dist/cjs/components/index.js +1 -0
  13. package/dist/cjs/constants/user-interface-text.js +1 -0
  14. package/dist/cjs/context/DashboardProvider/DashboardProvider.js +4 -2
  15. package/dist/cjs/context/DatasourceStoreProvider.js +58 -6
  16. package/dist/cjs/context/TemplateVariableProvider/TemplateVariableProvider.js +16 -0
  17. package/dist/cjs/context/useDashboard.js +5 -3
  18. package/dist/cjs/views/ViewDashboard/DashboardApp.js +4 -0
  19. package/dist/cjs/views/ViewDashboard/ViewDashboard.js +2 -3
  20. package/dist/components/DashboardStickyToolbar/DashboardStickyToolbar.js +2 -2
  21. package/dist/components/DashboardStickyToolbar/DashboardStickyToolbar.js.map +1 -1
  22. package/dist/components/DashboardToolbar/DashboardToolbar.d.ts.map +1 -1
  23. package/dist/components/DashboardToolbar/DashboardToolbar.js +11 -9
  24. package/dist/components/DashboardToolbar/DashboardToolbar.js.map +1 -1
  25. package/dist/components/Datasources/DatasourceEditor.d.ts +8 -0
  26. package/dist/components/Datasources/DatasourceEditor.d.ts.map +1 -0
  27. package/dist/components/Datasources/DatasourceEditor.js +223 -0
  28. package/dist/components/Datasources/DatasourceEditor.js.map +1 -0
  29. package/dist/components/Datasources/EditDatasourcesButton.d.ts +3 -0
  30. package/dist/components/Datasources/EditDatasourcesButton.d.ts.map +1 -0
  31. package/dist/components/Datasources/EditDatasourcesButton.js +96 -0
  32. package/dist/components/Datasources/EditDatasourcesButton.js.map +1 -0
  33. package/dist/components/Datasources/index.d.ts +3 -0
  34. package/dist/components/Datasources/index.d.ts.map +1 -0
  35. package/dist/components/Datasources/index.js +16 -0
  36. package/dist/components/Datasources/index.js.map +1 -0
  37. package/dist/components/EditJsonDialog/EditJsonDialog.js +13 -2
  38. package/dist/components/EditJsonDialog/EditJsonDialog.js.map +1 -1
  39. package/dist/components/PanelDrawer/PanelEditorForm.d.ts +1 -1
  40. package/dist/components/PanelDrawer/PanelEditorForm.d.ts.map +1 -1
  41. package/dist/components/PanelDrawer/PanelEditorForm.js +3 -2
  42. package/dist/components/PanelDrawer/PanelEditorForm.js.map +1 -1
  43. package/dist/components/PanelDrawer/index.d.ts +1 -0
  44. package/dist/components/PanelDrawer/index.d.ts.map +1 -1
  45. package/dist/components/PanelDrawer/index.js +1 -0
  46. package/dist/components/PanelDrawer/index.js.map +1 -1
  47. package/dist/components/QuerySummaryTable/QuerySummaryTable.js +2 -2
  48. package/dist/components/QuerySummaryTable/QuerySummaryTable.js.map +1 -1
  49. package/dist/components/Variables/TemplateVariable.d.ts +1 -1
  50. package/dist/components/Variables/TemplateVariable.d.ts.map +1 -1
  51. package/dist/components/Variables/TemplateVariable.js +141 -53
  52. package/dist/components/Variables/TemplateVariable.js.map +1 -1
  53. package/dist/components/Variables/VariableEditor.d.ts.map +1 -1
  54. package/dist/components/Variables/VariableEditor.js.map +1 -1
  55. package/dist/components/Variables/VariableList.js +1 -1
  56. package/dist/components/Variables/VariableList.js.map +1 -1
  57. package/dist/components/index.d.ts +1 -0
  58. package/dist/components/index.d.ts.map +1 -1
  59. package/dist/components/index.js +1 -0
  60. package/dist/components/index.js.map +1 -1
  61. package/dist/constants/user-interface-text.d.ts +1 -0
  62. package/dist/constants/user-interface-text.d.ts.map +1 -1
  63. package/dist/constants/user-interface-text.js +1 -0
  64. package/dist/constants/user-interface-text.js.map +1 -1
  65. package/dist/context/DashboardProvider/DashboardProvider.d.ts +2 -1
  66. package/dist/context/DashboardProvider/DashboardProvider.d.ts.map +1 -1
  67. package/dist/context/DashboardProvider/DashboardProvider.js +4 -2
  68. package/dist/context/DashboardProvider/DashboardProvider.js.map +1 -1
  69. package/dist/context/DashboardProvider/panel-editor-slice.d.ts +1 -2
  70. package/dist/context/DashboardProvider/panel-editor-slice.d.ts.map +1 -1
  71. package/dist/context/DashboardProvider/panel-editor-slice.js.map +1 -1
  72. package/dist/context/DatasourceStoreProvider.d.ts +2 -1
  73. package/dist/context/DatasourceStoreProvider.d.ts.map +1 -1
  74. package/dist/context/DatasourceStoreProvider.js +59 -7
  75. package/dist/context/DatasourceStoreProvider.js.map +1 -1
  76. package/dist/context/TemplateVariableProvider/TemplateVariableProvider.d.ts +1 -0
  77. package/dist/context/TemplateVariableProvider/TemplateVariableProvider.d.ts.map +1 -1
  78. package/dist/context/TemplateVariableProvider/TemplateVariableProvider.js +13 -0
  79. package/dist/context/TemplateVariableProvider/TemplateVariableProvider.js.map +1 -1
  80. package/dist/context/useDashboard.d.ts.map +1 -1
  81. package/dist/context/useDashboard.js +5 -3
  82. package/dist/context/useDashboard.js.map +1 -1
  83. package/dist/views/ViewDashboard/DashboardApp.d.ts.map +1 -1
  84. package/dist/views/ViewDashboard/DashboardApp.js +4 -0
  85. package/dist/views/ViewDashboard/DashboardApp.js.map +1 -1
  86. package/dist/views/ViewDashboard/ViewDashboard.d.ts.map +1 -1
  87. package/dist/views/ViewDashboard/ViewDashboard.js +4 -5
  88. package/dist/views/ViewDashboard/ViewDashboard.js.map +1 -1
  89. package/package.json +6 -6
@@ -34,6 +34,17 @@ const _material = require("@mui/material");
34
34
  const _core = require("@perses-dev/core");
35
35
  const _pluginsystem = require("@perses-dev/plugin-system");
36
36
  const _context = require("../../context");
37
+ function variableOptionToVariableValue(options) {
38
+ if (options === null) {
39
+ return null;
40
+ }
41
+ if (Array.isArray(options)) {
42
+ return options.map((v)=>{
43
+ return v.value;
44
+ });
45
+ }
46
+ return options.value;
47
+ }
37
48
  function TemplateVariable({ name , source }) {
38
49
  var _ctx_definition;
39
50
  const ctx = (0, _context.useTemplateVariable)(name, source);
@@ -60,6 +71,7 @@ function TemplateVariable({ name , source }) {
60
71
  function useListVariableState(spec, state, variablesOptionsQuery) {
61
72
  const allowMultiple = (spec === null || spec === void 0 ? void 0 : spec.allowMultiple) === true;
62
73
  const allowAllValue = (spec === null || spec === void 0 ? void 0 : spec.allowAllValue) === true;
74
+ const sort = spec === null || spec === void 0 ? void 0 : spec.sort;
63
75
  const loading = (0, _react.useMemo)(()=>variablesOptionsQuery.isFetching || false, [
64
76
  variablesOptionsQuery
65
77
  ]);
@@ -71,10 +83,34 @@ function useListVariableState(spec, state, variablesOptionsQuery) {
71
83
  value
72
84
  ] : [];
73
85
  }
74
- const viewOptions = (0, _react.useMemo)(()=>{
75
- let computedOptions = options ? [
86
+ // Sort the provided list of options according to the method defined
87
+ const sortedOptions = (0, _react.useMemo)(()=>{
88
+ const opts = options ? [
76
89
  ...options
77
90
  ] : [];
91
+ if (!sort || sort === 'none') return opts;
92
+ switch(sort){
93
+ case 'alphabetical-asc':
94
+ return opts.sort((a, b)=>a.label > b.label ? 1 : -1);
95
+ case 'alphabetical-desc':
96
+ return opts.sort((a, b)=>a.label > b.label ? -1 : 1);
97
+ case 'numerical-asc':
98
+ return opts.sort((a, b)=>parseInt(a.label) > parseInt(b.label) ? 1 : -1);
99
+ case 'numerical-desc':
100
+ return opts.sort((a, b)=>parseInt(a.label) < parseInt(b.label) ? 1 : -1);
101
+ case 'alphabetical-ci-asc':
102
+ return opts.sort((a, b)=>a.label.toLowerCase() > b.label.toLowerCase() ? 1 : -1);
103
+ case 'alphabetical-ci-desc':
104
+ return opts.sort((a, b)=>a.label.toLowerCase() > b.label.toLowerCase() ? -1 : 1);
105
+ default:
106
+ return opts;
107
+ }
108
+ }, [
109
+ options,
110
+ sort
111
+ ]);
112
+ const viewOptions = (0, _react.useMemo)(()=>{
113
+ let computedOptions = sortedOptions;
78
114
  // Add the all value if it's allowed
79
115
  if (allowAllValue) {
80
116
  computedOptions = [
@@ -87,8 +123,8 @@ function useListVariableState(spec, state, variablesOptionsQuery) {
87
123
  }
88
124
  return computedOptions;
89
125
  }, [
90
- options,
91
- allowAllValue
126
+ allowAllValue,
127
+ sortedOptions
92
128
  ]);
93
129
  const valueIsInOptions = (0, _react.useMemo)(()=>Boolean(viewOptions.find((v)=>{
94
130
  if (allowMultiple) {
@@ -119,23 +155,49 @@ function useListVariableState(spec, state, variablesOptionsQuery) {
119
155
  allowMultiple,
120
156
  allowAllValue
121
157
  ]);
122
- // Once we computed value, we set it as the selected one, if it is available in the options
123
- const selectedValue = value && valueIsInOptions ? value : allowMultiple ? [] : '';
158
+ const selectedOptions = (0, _react.useMemo)(()=>{
159
+ // In the case Autocomplete.multiple equals false, Autocomplete.value expects a single object, not
160
+ // an array, hence this conditional
161
+ if (Array.isArray(value)) {
162
+ return viewOptions.filter((o)=>{
163
+ return value === null || value === void 0 ? void 0 : value.includes(o.value);
164
+ });
165
+ } else {
166
+ var _viewOptions_find;
167
+ return (_viewOptions_find = viewOptions.find((o)=>{
168
+ return value === o.value;
169
+ })) !== null && _viewOptions_find !== void 0 ? _viewOptions_find : {
170
+ value: '',
171
+ label: ''
172
+ };
173
+ }
174
+ }, [
175
+ value,
176
+ viewOptions
177
+ ]);
124
178
  return {
125
179
  value,
126
180
  loading,
127
181
  options,
128
- selectedValue,
182
+ selectedOptions,
129
183
  viewOptions
130
184
  };
131
185
  }
186
+ const StyledPopper = (props)=>/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Popper, {
187
+ ...props,
188
+ sx: {
189
+ minWidth: 'fit-content'
190
+ },
191
+ placement: "bottom-start"
192
+ });
132
193
  function ListVariable({ name , source }) {
133
194
  var _definition_spec_display;
134
195
  const ctx = (0, _context.useTemplateVariable)(name, source);
135
196
  const definition = ctx.definition;
136
197
  const variablesOptionsQuery = (0, _pluginsystem.useListVariablePluginValues)(definition);
137
198
  const { setVariableValue , setVariableLoading , setVariableOptions } = (0, _context.useTemplateVariableActions)();
138
- const { selectedValue , value , loading , options , viewOptions } = useListVariableState(definition === null || definition === void 0 ? void 0 : definition.spec, ctx.state, variablesOptionsQuery);
199
+ const { selectedOptions , value , loading , options , viewOptions } = useListVariableState(definition === null || definition === void 0 ? void 0 : definition.spec, ctx.state, variablesOptionsQuery);
200
+ const [inputValue, setInputValue] = (0, _react.useState)('');
139
201
  var _definition_spec_display_name;
140
202
  const title = (_definition_spec_display_name = (_definition_spec_display = definition === null || definition === void 0 ? void 0 : definition.spec.display) === null || _definition_spec_display === void 0 ? void 0 : _definition_spec_display.name) !== null && _definition_spec_display_name !== void 0 ? _definition_spec_display_name : name;
141
203
  const allowMultiple = (definition === null || definition === void 0 ? void 0 : definition.spec.allowMultiple) === true;
@@ -171,51 +233,72 @@ function ListVariable({ name , source }) {
171
233
  options,
172
234
  source
173
235
  ]);
174
- return /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Box, {
175
- display: 'flex',
176
- children: /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.FormControl, {
177
- fullWidth: true,
178
- children: [
179
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.InputLabel, {
180
- id: name,
181
- children: title
182
- }),
183
- /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Select, {
184
- id: name,
185
- title: selectedValue,
186
- label: title,
187
- value: selectedValue,
188
- onChange: (e)=>{
189
- // Must be selected
190
- if (e.target.value === null || e.target.value.length === 0) {
191
- if (allowAllValue) {
192
- setVariableValue(name, _core.DEFAULT_ALL_VALUE, source);
193
- }
194
- return;
236
+ const LETTER_HSIZE = 8; // approximation
237
+ const ARROW_OFFSET = 40;
238
+ const MIN_INPUT_WIDTH = 120;
239
+ const MAX_INPUT_WIDTH = 500;
240
+ const [inputWidth, setInputWidth] = (0, _react.useState)(MIN_INPUT_WIDTH);
241
+ const handleInputResize = (newInputValue)=>{
242
+ const newInputValueSize = (newInputValue.length + 1) * LETTER_HSIZE + ARROW_OFFSET;
243
+ if (newInputValueSize < MIN_INPUT_WIDTH) {
244
+ setInputWidth(MIN_INPUT_WIDTH);
245
+ } else if (newInputValueSize > MAX_INPUT_WIDTH) {
246
+ setInputWidth(MAX_INPUT_WIDTH);
247
+ } else {
248
+ setInputWidth(newInputValueSize);
249
+ }
250
+ };
251
+ return /*#__PURE__*/ (0, _jsxruntime.jsxs)(_jsxruntime.Fragment, {
252
+ children: [
253
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Autocomplete, {
254
+ disablePortal: true,
255
+ disableCloseOnSelect: allowMultiple,
256
+ multiple: allowMultiple,
257
+ fullWidth: true,
258
+ limitTags: 3,
259
+ size: "small",
260
+ disableClearable: true,
261
+ PopperComponent: StyledPopper,
262
+ renderInput: (params)=>{
263
+ return allowMultiple ? /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.TextField, {
264
+ ...params,
265
+ label: title
266
+ }) : /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.TextField, {
267
+ ...params,
268
+ label: title,
269
+ style: {
270
+ width: `${inputWidth}px`
195
271
  }
196
- setVariableValue(name, e.target.value, source);
272
+ });
273
+ },
274
+ sx: {
275
+ '& .MuiInputBase-root': {
276
+ minHeight: '38px'
197
277
  },
198
- multiple: allowMultiple,
199
- children: [
200
- loading && /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.MenuItem, {
201
- value: "loading",
202
- disabled: true,
203
- children: "Loading"
204
- }),
205
- viewOptions.length === 0 && /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.MenuItem, {
206
- value: "empty",
207
- disabled: true,
208
- children: "No options"
209
- }),
210
- viewOptions.map((option)=>/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.MenuItem, {
211
- value: option.value,
212
- children: option.label
213
- }, option.value))
214
- ]
215
- }),
216
- loading && /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.LinearProgress, {})
217
- ]
218
- })
278
+ '& .MuiInputBase-root.MuiOutlinedInput-root.MuiInputBase-sizeSmall': {
279
+ paddingY: '5px',
280
+ paddingLeft: '5px'
281
+ }
282
+ },
283
+ value: selectedOptions,
284
+ onChange: (_, value)=>{
285
+ if ((value === null || Array.isArray(value) && value.length === 0) && allowAllValue) {
286
+ setVariableValue(name, _core.DEFAULT_ALL_VALUE, source);
287
+ } else {
288
+ setVariableValue(name, variableOptionToVariableValue(value), source);
289
+ }
290
+ },
291
+ inputValue: inputValue,
292
+ onInputChange: (_, newInputValue)=>{
293
+ setInputValue(newInputValue);
294
+ if (!allowMultiple) {
295
+ handleInputResize(newInputValue);
296
+ }
297
+ },
298
+ options: viewOptions
299
+ }),
300
+ loading && /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.LinearProgress, {})
301
+ ]
219
302
  });
220
303
  }
221
304
  function TextVariable({ name , source }) {
@@ -242,6 +325,11 @@ function TextVariable({ name , source }) {
242
325
  label: (_definition_spec_display_name = (_definition_spec_display = definition === null || definition === void 0 ? void 0 : definition.spec.display) === null || _definition_spec_display === void 0 ? void 0 : _definition_spec_display.name) !== null && _definition_spec_display_name !== void 0 ? _definition_spec_display_name : name,
243
326
  InputProps: {
244
327
  readOnly: (_definition_spec_constant = definition === null || definition === void 0 ? void 0 : definition.spec.constant) !== null && _definition_spec_constant !== void 0 ? _definition_spec_constant : false
328
+ },
329
+ sx: {
330
+ '& .MuiInputBase-root': {
331
+ minHeight: '38px'
332
+ }
245
333
  }
246
334
  });
247
335
  }
@@ -60,7 +60,7 @@ function TemplateVariableListItem({ spec , source }) {
60
60
  maxWidth: VARIABLE_INPUT_MAX_WIDTH,
61
61
  marginBottom: 1,
62
62
  marginRight: 1,
63
- "data-testid": "template-variable",
63
+ "data-testid": 'template-variable-' + spec.name,
64
64
  children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_TemplateVariable.TemplateVariable, {
65
65
  name: spec.name,
66
66
  source: source
@@ -19,6 +19,7 @@ _export_star(require("./AddPanelButton"), exports);
19
19
  _export_star(require("./Dashboard"), exports);
20
20
  _export_star(require("./DashboardToolbar"), exports);
21
21
  _export_star(require("./DashboardStickyToolbar"), exports);
22
+ _export_star(require("./Datasources"), exports);
22
23
  _export_star(require("./DeletePanelDialog"), exports);
23
24
  _export_star(require("./DeletePanelGroupDialog"), exports);
24
25
  _export_star(require("./DiscardChangesConfirmationDialog"), exports);
@@ -33,6 +33,7 @@ const TOOLTIP_TEXT = {
33
33
  addPanel: 'Add panel',
34
34
  addGroup: 'Add panel group',
35
35
  downloadDashboard: 'Download JSON',
36
+ editDatasources: 'Edit datasources',
36
37
  editJson: 'Edit JSON',
37
38
  editVariables: 'Edit variables',
38
39
  refreshDashboard: 'Refresh dashboard',
@@ -89,7 +89,7 @@ function DashboardProvider(props) {
89
89
  }
90
90
  function initStore(props) {
91
91
  const { initialState: { dashboardResource , isEditMode } } = props;
92
- const { spec: { display , duration , refreshInterval =_core.DEFAULT_REFRESH_INTERVAL } , metadata } = dashboardResource;
92
+ const { spec: { display , duration , refreshInterval =_core.DEFAULT_REFRESH_INTERVAL , datasources } , metadata } = dashboardResource;
93
93
  let { spec: { layouts , panels } } = dashboardResource;
94
94
  // Set fallbacks in case the frontend is used with a non-Perses backend
95
95
  layouts = layouts !== null && layouts !== void 0 ? layouts : [];
@@ -111,11 +111,12 @@ function initStore(props) {
111
111
  display,
112
112
  duration,
113
113
  refreshInterval,
114
+ datasources,
114
115
  isEditMode: !!isEditMode,
115
116
  setEditMode: (isEditMode)=>set({
116
117
  isEditMode
117
118
  }),
118
- setDashboard: ({ metadata , spec: { display , panels ={} , layouts =[] , duration , refreshInterval } })=>{
119
+ setDashboard: ({ metadata , spec: { display , panels ={} , layouts =[] , duration , refreshInterval , datasources ={} } })=>{
119
120
  set((state)=>{
120
121
  state.metadata = metadata;
121
122
  state.display = display;
@@ -125,6 +126,7 @@ function initStore(props) {
125
126
  state.panelGroupOrder = panelGroupOrder;
126
127
  state.duration = duration;
127
128
  state.refreshInterval = refreshInterval !== null && refreshInterval !== void 0 ? refreshInterval : _core.DEFAULT_REFRESH_INTERVAL;
129
+ state.datasources = datasources;
128
130
  });
129
131
  }
130
132
  };
@@ -25,7 +25,10 @@ const _react = require("react");
25
25
  const _core = require("@perses-dev/core");
26
26
  const _pluginsystem = require("@perses-dev/plugin-system");
27
27
  function DatasourceStoreProvider(props) {
28
- const { dashboardResource , projectName , datasourceApi , onCreate , children } = props;
28
+ const { projectName , datasourceApi , onCreate , children } = props;
29
+ const [dashboardResource, setDashboardResource] = (0, _react.useState)(props.dashboardResource);
30
+ var _props_savedDatasources;
31
+ const [savedDatasources, setSavedDatasources] = (0, _react.useState)((_props_savedDatasources = props.savedDatasources) !== null && _props_savedDatasources !== void 0 ? _props_savedDatasources : {});
29
32
  const project = projectName !== null && projectName !== void 0 ? projectName : dashboardResource === null || dashboardResource === void 0 ? void 0 : dashboardResource.metadata.project;
30
33
  const { getPlugin , listPluginMetadata } = (0, _pluginsystem.usePluginRegistry)();
31
34
  const findDatasource = (0, _core.useEvent)(async (selector)=>{
@@ -114,29 +117,77 @@ function DatasourceStoreProvider(props) {
114
117
  for(const selectorName in dashboardResource.spec.datasources){
115
118
  const spec = dashboardResource.spec.datasources[selectorName];
116
119
  if (spec === undefined || spec.plugin.kind !== datasourcePluginKind) continue;
117
- addItem(spec, selectorName, 'dashboard');
120
+ const saved = selectorName in savedDatasources;
121
+ addItem({
122
+ spec,
123
+ selectorName,
124
+ selectorGroup: 'dashboard',
125
+ saved
126
+ });
118
127
  }
119
128
  }
120
129
  // Now look at project-level datasources
121
130
  for (const datasource of datasources){
122
131
  const selectorName = datasource.metadata.name;
123
- addItem(datasource.spec, selectorName, 'project', `/projects/${project}/datasources`);
132
+ addItem({
133
+ spec: datasource.spec,
134
+ selectorName,
135
+ selectorGroup: 'project',
136
+ editLink: `/projects/${project}/datasources`
137
+ });
124
138
  }
125
139
  // And finally global datasources
126
140
  for (const globalDatasource of globalDatasources){
127
141
  const selectorName = globalDatasource.metadata.name;
128
- addItem(globalDatasource.spec, selectorName, 'global', '/admin/datasources');
142
+ addItem({
143
+ spec: globalDatasource.spec,
144
+ selectorName,
145
+ selectorGroup: 'global',
146
+ editLink: '/admin/datasources'
147
+ });
129
148
  }
130
149
  return results;
131
150
  });
151
+ const getLocalDatasources = (0, _react.useCallback)(()=>{
152
+ var _dashboardResource_spec_datasources;
153
+ return (_dashboardResource_spec_datasources = dashboardResource === null || dashboardResource === void 0 ? void 0 : dashboardResource.spec.datasources) !== null && _dashboardResource_spec_datasources !== void 0 ? _dashboardResource_spec_datasources : {};
154
+ }, [
155
+ dashboardResource
156
+ ]);
157
+ const getSavedDatasources = (0, _react.useCallback)(()=>{
158
+ return savedDatasources;
159
+ }, [
160
+ savedDatasources
161
+ ]);
162
+ const setLocalDatasources = (0, _react.useCallback)((datasources)=>{
163
+ if (dashboardResource) {
164
+ setDashboardResource({
165
+ ...dashboardResource,
166
+ spec: {
167
+ ...dashboardResource.spec,
168
+ datasources: datasources
169
+ }
170
+ });
171
+ }
172
+ }, [
173
+ dashboardResource
174
+ ]);
132
175
  const ctxValue = (0, _react.useMemo)(()=>({
133
176
  getDatasource,
134
177
  getDatasourceClient,
178
+ getLocalDatasources,
179
+ setLocalDatasources,
180
+ setSavedDatasources,
181
+ getSavedDatasources,
135
182
  listDatasourceSelectItems
136
183
  }), [
137
184
  getDatasource,
138
185
  getDatasourceClient,
139
- listDatasourceSelectItems
186
+ getLocalDatasources,
187
+ setLocalDatasources,
188
+ listDatasourceSelectItems,
189
+ setSavedDatasources,
190
+ getSavedDatasources
140
191
  ]);
141
192
  return /*#__PURE__*/ (0, _jsxruntime.jsx)(_pluginsystem.DatasourceStoreContext.Provider, {
142
193
  value: ctxValue,
@@ -178,7 +229,7 @@ function findDashboardDatasource(dashboardDatasources, selector) {
178
229
  let explicitDefaultAdded = false;
179
230
  const groupIndices = {};
180
231
  let currentGroupIndex = 1; // 0 is the default group, always there as it contains at least the first item.
181
- const addItem = (spec, selectorName, group, editLink)=>{
232
+ const addItem = ({ spec , selectorName , selectorGroup: group , editLink , saved })=>{
182
233
  var _spec_display;
183
234
  group = group !== null && group !== void 0 ? group : '';
184
235
  // Ensure the default group is always present as soon as an item is added.
@@ -207,6 +258,7 @@ function findDashboardDatasource(dashboardDatasources, selector) {
207
258
  selectItemGroup.items.push({
208
259
  name: (_spec_display_name = (_spec_display = spec.display) === null || _spec_display === void 0 ? void 0 : _spec_display.name) !== null && _spec_display_name !== void 0 ? _spec_display_name : selectorName,
209
260
  overridden: isOverridden,
261
+ saved,
210
262
  selector: {
211
263
  kind: spec.plugin.kind,
212
264
  name: selectorName,
@@ -44,6 +44,9 @@ _export(exports, {
44
44
  },
45
45
  TemplateVariableProvider: function() {
46
46
  return TemplateVariableProvider;
47
+ },
48
+ TemplateVariableProviderWithQueryParams: function() {
49
+ return TemplateVariableProviderWithQueryParams;
47
50
  }
48
51
  });
49
52
  const _jsxruntime = require("react/jsx-runtime");
@@ -369,6 +372,19 @@ function createTemplateVariableSrvStore({ initialVariableDefinitions =[] , exter
369
372
  return store;
370
373
  }
371
374
  function TemplateVariableProvider({ children , initialVariableDefinitions =[] , externalVariableDefinitions =[] , builtinVariables =[] }) {
375
+ const [store] = (0, _react.useState)(createTemplateVariableSrvStore({
376
+ initialVariableDefinitions,
377
+ externalVariableDefinitions
378
+ }));
379
+ return /*#__PURE__*/ (0, _jsxruntime.jsx)(TemplateVariableStoreContext.Provider, {
380
+ value: store,
381
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(PluginProvider, {
382
+ builtinVariables: builtinVariables,
383
+ children: children
384
+ })
385
+ });
386
+ }
387
+ function TemplateVariableProviderWithQueryParams({ children , initialVariableDefinitions =[] , externalVariableDefinitions =[] , builtinVariables =[] }) {
372
388
  const allVariableDefs = (0, _utils.mergeVariableDefinitions)(initialVariableDefinitions, externalVariableDefinitions);
373
389
  const queryParams = (0, _queryparams.useVariableQueryParams)(allVariableDefs);
374
390
  const [store] = (0, _react.useState)(createTemplateVariableSrvStore({
@@ -24,7 +24,7 @@ const _core = require("@perses-dev/core");
24
24
  const _DashboardProvider = require("./DashboardProvider");
25
25
  const _TemplateVariableProvider = require("./TemplateVariableProvider");
26
26
  function useDashboard() {
27
- const { panels , panelGroups , panelGroupOrder , setDashboard: setDashboardResource , metadata , display , duration , refreshInterval } = (0, _DashboardProvider.useDashboardStore)(({ panels , panelGroups , panelGroupOrder , setDashboard , metadata , display , duration , refreshInterval })=>({
27
+ const { panels , panelGroups , panelGroupOrder , setDashboard: setDashboardResource , metadata , display , duration , refreshInterval , datasources } = (0, _DashboardProvider.useDashboardStore)(({ panels , panelGroups , panelGroupOrder , setDashboard , metadata , display , duration , refreshInterval , datasources })=>({
28
28
  panels,
29
29
  panelGroups,
30
30
  panelGroupOrder,
@@ -32,7 +32,8 @@ function useDashboard() {
32
32
  metadata,
33
33
  display,
34
34
  duration,
35
- refreshInterval
35
+ refreshInterval,
36
+ datasources
36
37
  }));
37
38
  const { setVariableDefinitions } = (0, _TemplateVariableProvider.useTemplateVariableActions)();
38
39
  const variables = (0, _TemplateVariableProvider.useTemplateVariableDefinitions)();
@@ -46,7 +47,8 @@ function useDashboard() {
46
47
  layouts,
47
48
  variables,
48
49
  duration,
49
- refreshInterval
50
+ refreshInterval,
51
+ datasources
50
52
  }
51
53
  };
52
54
  const setDashboard = (dashboardResource)=>{
@@ -24,6 +24,7 @@ const _jsxruntime = require("react/jsx-runtime");
24
24
  const _react = require("react");
25
25
  const _material = require("@mui/material");
26
26
  const _components = require("@perses-dev/components");
27
+ const _pluginsystem = require("@perses-dev/plugin-system");
27
28
  const _components1 = require("../../components");
28
29
  const _context = require("../../context");
29
30
  const DashboardApp = (props)=>{
@@ -32,6 +33,7 @@ const DashboardApp = (props)=>{
32
33
  const { setEditMode } = (0, _context.useEditMode)();
33
34
  const { dashboard , setDashboard } = (0, _context.useDashboard)();
34
35
  const [originalDashboard, setOriginalDashboard] = (0, _react.useState)(undefined);
36
+ const { setSavedDatasources } = (0, _pluginsystem.useDatasourceStore)();
35
37
  const { openDiscardChangesConfirmationDialog , closeDiscardChangesConfirmationDialog } = (0, _context.useDiscardChangesConfirmationDialog)();
36
38
  const handleDiscardChanges = ()=>{
37
39
  // Reset to the original spec and exit edit mode
@@ -47,6 +49,8 @@ const DashboardApp = (props)=>{
47
49
  const onEditButtonClick = ()=>{
48
50
  setEditMode(true);
49
51
  setOriginalDashboard(dashboard);
52
+ var _dashboard_spec_datasources;
53
+ setSavedDatasources((_dashboard_spec_datasources = dashboard.spec.datasources) !== null && _dashboard_spec_datasources !== void 0 ? _dashboard_spec_datasources : {});
50
54
  };
51
55
  const onCancelButtonClick = ()=>{
52
56
  // check if dashboard has been modified
@@ -84,11 +84,10 @@ function ViewDashboard(props) {
84
84
  dashboardResource,
85
85
  isEditMode: !!isEditing
86
86
  },
87
- children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_pluginsystem.TimeRangeProvider, {
87
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_pluginsystem.TimeRangeProviderWithQueryParams, {
88
88
  initialTimeRange: initialTimeRange,
89
89
  initialRefreshInterval: initialRefreshInterval,
90
- enabledURLParams: true,
91
- children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_context.TemplateVariableProvider, {
90
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_context.TemplateVariableProviderWithQueryParams, {
92
91
  initialVariableDefinitions: spec.variables,
93
92
  externalVariableDefinitions: externalVariableDefinitions,
94
93
  builtinVariables: builtinVariables,
@@ -44,7 +44,7 @@ export function DashboardStickyToolbar(props) {
44
44
  display: "flex",
45
45
  flexWrap: "wrap",
46
46
  alignItems: "start",
47
- my: isSticky ? 2 : 0,
47
+ mt: isSticky ? 1.5 : 0,
48
48
  ml: isSticky ? 2 : 0,
49
49
  children: [
50
50
  /*#__PURE__*/ _jsx(TemplateVariableList, {}),
@@ -55,7 +55,7 @@ export function DashboardStickyToolbar(props) {
55
55
  ]
56
56
  }),
57
57
  isSticky && /*#__PURE__*/ _jsx(Box, {
58
- my: 2,
58
+ mt: 1.5,
59
59
  mr: 2,
60
60
  children: /*#__PURE__*/ _jsx(TimeRangeControls, {})
61
61
  })
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/DashboardStickyToolbar/DashboardStickyToolbar.tsx"],"sourcesContent":["// Copyright 2023 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { useState } from 'react';\nimport { AppBar, Box, IconButton, SxProps, Theme, useScrollTrigger } from '@mui/material';\nimport PinOutline from 'mdi-material-ui/PinOutline';\nimport PinOffOutline from 'mdi-material-ui/PinOffOutline';\nimport { TemplateVariableList } from '../Variables';\nimport { TimeRangeControls } from '../TimeRangeControls';\n\ninterface DashboardStickyToolbarProps {\n initialVariableIsSticky?: boolean;\n sx?: SxProps<Theme>;\n}\n\nexport function DashboardStickyToolbar(props: DashboardStickyToolbarProps) {\n const [isPin, setIsPin] = useState(props.initialVariableIsSticky);\n\n const scrollTrigger = useScrollTrigger({ disableHysteresis: true });\n const isSticky = scrollTrigger && props.initialVariableIsSticky && isPin;\n\n return (\n // marginBottom={-1} counteracts the marginBottom={1} on every variable input.\n // The margin on the inputs is for spacing between inputs, but is not meant to add space to bottom of the container.\n <Box marginBottom={-1} data-testid=\"variable-list\">\n <AppBar\n color=\"inherit\"\n position={isSticky ? 'fixed' : 'static'}\n elevation={isSticky ? 4 : 0}\n sx={{ backgroundColor: 'inherit', ...props.sx }}\n >\n <Box display=\"flex\" justifyContent=\"space-between\">\n <Box display=\"flex\" flexWrap=\"wrap\" alignItems=\"start\" my={isSticky ? 2 : 0} ml={isSticky ? 2 : 0}>\n <TemplateVariableList></TemplateVariableList>\n {props.initialVariableIsSticky && (\n <IconButton onClick={() => setIsPin(!isPin)}>{isPin ? <PinOutline /> : <PinOffOutline />}</IconButton>\n )}\n </Box>\n {isSticky && (\n <Box my={2} mr={2}>\n <TimeRangeControls></TimeRangeControls>\n </Box>\n )}\n </Box>\n </AppBar>\n </Box>\n );\n}\n"],"names":["useState","AppBar","Box","IconButton","useScrollTrigger","PinOutline","PinOffOutline","TemplateVariableList","TimeRangeControls","DashboardStickyToolbar","props","isPin","setIsPin","initialVariableIsSticky","scrollTrigger","disableHysteresis","isSticky","marginBottom","data-testid","color","position","elevation","sx","backgroundColor","display","justifyContent","flexWrap","alignItems","my","ml","onClick","mr"],"mappings":"AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;;AAEjC,SAASA,QAAQ,QAAQ,QAAQ;AACjC,SAASC,MAAM,EAAEC,GAAG,EAAEC,UAAU,EAAkBC,gBAAgB,QAAQ,gBAAgB;AAC1F,OAAOC,gBAAgB,6BAA6B;AACpD,OAAOC,mBAAmB,gCAAgC;AAC1D,SAASC,oBAAoB,QAAQ,eAAe;AACpD,SAASC,iBAAiB,QAAQ,uBAAuB;AAOzD,OAAO,SAASC,uBAAuBC,KAAkC;IACvE,MAAM,CAACC,OAAOC,SAAS,GAAGZ,SAASU,MAAMG;IAEzC,MAAMC,gBAAgBV,iBAAiB;QAAEW,mBAAmB;IAAK;IACjE,MAAMC,WAAWF,iBAAiBJ,MAAMG,2BAA2BF;IAEnE,OACE,8EAA8E;IAC9E,oHAAoH;kBACpH,KAACT;QAAIe,cAAc,CAAC;QAAGC,eAAY;kBACjC,cAAA,KAACjB;YACCkB,OAAM;YACNC,UAAUJ,WAAW,UAAU;YAC/BK,WAAWL,WAAW,IAAI;YAC1BM,IAAI;gBAAEC,iBAAiB;gBAAW,GAAGb,MAAMY,EAAE;YAAC;sBAE9C,cAAA,MAACpB;gBAAIsB,SAAQ;gBAAOC,gBAAe;;kCACjC,MAACvB;wBAAIsB,SAAQ;wBAAOE,UAAS;wBAAOC,YAAW;wBAAQC,IAAIZ,WAAW,IAAI;wBAAGa,IAAIb,WAAW,IAAI;;0CAC9F,KAACT;4BACAG,MAAMG,yCACL,KAACV;gCAAW2B,SAAS,IAAMlB,SAAS,CAACD;0CAASA,sBAAQ,KAACN,gCAAgB,KAACC;;;;oBAG3EU,0BACC,KAACd;wBAAI0B,IAAI;wBAAGG,IAAI;kCACd,cAAA,KAACvB;;;;;;AAOf"}
1
+ {"version":3,"sources":["../../../src/components/DashboardStickyToolbar/DashboardStickyToolbar.tsx"],"sourcesContent":["// Copyright 2023 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { useState } from 'react';\nimport { AppBar, Box, IconButton, SxProps, Theme, useScrollTrigger } from '@mui/material';\nimport PinOutline from 'mdi-material-ui/PinOutline';\nimport PinOffOutline from 'mdi-material-ui/PinOffOutline';\nimport { TemplateVariableList } from '../Variables';\nimport { TimeRangeControls } from '../TimeRangeControls';\n\ninterface DashboardStickyToolbarProps {\n initialVariableIsSticky?: boolean;\n sx?: SxProps<Theme>;\n}\n\nexport function DashboardStickyToolbar(props: DashboardStickyToolbarProps) {\n const [isPin, setIsPin] = useState(props.initialVariableIsSticky);\n\n const scrollTrigger = useScrollTrigger({ disableHysteresis: true });\n const isSticky = scrollTrigger && props.initialVariableIsSticky && isPin;\n\n return (\n // marginBottom={-1} counteracts the marginBottom={1} on every variable input.\n // The margin on the inputs is for spacing between inputs, but is not meant to add space to bottom of the container.\n <Box marginBottom={-1} data-testid=\"variable-list\">\n <AppBar\n color=\"inherit\"\n position={isSticky ? 'fixed' : 'static'}\n elevation={isSticky ? 4 : 0}\n sx={{ backgroundColor: 'inherit', ...props.sx }}\n >\n <Box display=\"flex\" justifyContent=\"space-between\">\n <Box display=\"flex\" flexWrap=\"wrap\" alignItems=\"start\" mt={isSticky ? 1.5 : 0} ml={isSticky ? 2 : 0}>\n <TemplateVariableList></TemplateVariableList>\n {props.initialVariableIsSticky && (\n <IconButton onClick={() => setIsPin(!isPin)}>{isPin ? <PinOutline /> : <PinOffOutline />}</IconButton>\n )}\n </Box>\n {isSticky && (\n <Box mt={1.5} mr={2}>\n <TimeRangeControls></TimeRangeControls>\n </Box>\n )}\n </Box>\n </AppBar>\n </Box>\n );\n}\n"],"names":["useState","AppBar","Box","IconButton","useScrollTrigger","PinOutline","PinOffOutline","TemplateVariableList","TimeRangeControls","DashboardStickyToolbar","props","isPin","setIsPin","initialVariableIsSticky","scrollTrigger","disableHysteresis","isSticky","marginBottom","data-testid","color","position","elevation","sx","backgroundColor","display","justifyContent","flexWrap","alignItems","mt","ml","onClick","mr"],"mappings":"AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;;AAEjC,SAASA,QAAQ,QAAQ,QAAQ;AACjC,SAASC,MAAM,EAAEC,GAAG,EAAEC,UAAU,EAAkBC,gBAAgB,QAAQ,gBAAgB;AAC1F,OAAOC,gBAAgB,6BAA6B;AACpD,OAAOC,mBAAmB,gCAAgC;AAC1D,SAASC,oBAAoB,QAAQ,eAAe;AACpD,SAASC,iBAAiB,QAAQ,uBAAuB;AAOzD,OAAO,SAASC,uBAAuBC,KAAkC;IACvE,MAAM,CAACC,OAAOC,SAAS,GAAGZ,SAASU,MAAMG;IAEzC,MAAMC,gBAAgBV,iBAAiB;QAAEW,mBAAmB;IAAK;IACjE,MAAMC,WAAWF,iBAAiBJ,MAAMG,2BAA2BF;IAEnE,OACE,8EAA8E;IAC9E,oHAAoH;kBACpH,KAACT;QAAIe,cAAc,CAAC;QAAGC,eAAY;kBACjC,cAAA,KAACjB;YACCkB,OAAM;YACNC,UAAUJ,WAAW,UAAU;YAC/BK,WAAWL,WAAW,IAAI;YAC1BM,IAAI;gBAAEC,iBAAiB;gBAAW,GAAGb,MAAMY,EAAE;YAAC;sBAE9C,cAAA,MAACpB;gBAAIsB,SAAQ;gBAAOC,gBAAe;;kCACjC,MAACvB;wBAAIsB,SAAQ;wBAAOE,UAAS;wBAAOC,YAAW;wBAAQC,IAAIZ,WAAW,MAAM;wBAAGa,IAAIb,WAAW,IAAI;;0CAChG,KAACT;4BACAG,MAAMG,yCACL,KAACV;gCAAW2B,SAAS,IAAMlB,SAAS,CAACD;0CAASA,sBAAQ,KAACN,gCAAgB,KAACC;;;;oBAG3EU,0BACC,KAACd;wBAAI0B,IAAI;wBAAKG,IAAI;kCAChB,cAAA,KAACvB;;;;;;AAOf"}
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardToolbar.d.ts","sourceRoot":"","sources":["../../../src/components/DashboardToolbar/DashboardToolbar.tsx"],"names":[],"mappings":";AAeA,OAAO,EAAE,eAAe,EAAe,MAAM,eAAe,CAAC;AAW7D,MAAM,WAAW,qBAAqB;IACpC,aAAa,EAAE,MAAM,CAAC;IACtB,uBAAuB,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC;IACtC,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,UAAU,EAAE,OAAO,CAAC;IACpB,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,mBAAmB,EAAE,MAAM,IAAI,CAAC;IAChC,MAAM,CAAC,EAAE,eAAe,CAAC;CAC1B;AAED,eAAO,MAAM,gBAAgB,UAAW,qBAAqB,gBAgG5D,CAAC"}
1
+ {"version":3,"file":"DashboardToolbar.d.ts","sourceRoot":"","sources":["../../../src/components/DashboardToolbar/DashboardToolbar.tsx"],"names":[],"mappings":";AAeA,OAAO,EAAE,eAAe,EAAe,MAAM,eAAe,CAAC;AAY7D,MAAM,WAAW,qBAAqB;IACpC,aAAa,EAAE,MAAM,CAAC;IACtB,uBAAuB,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC;IACtC,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,UAAU,EAAE,OAAO,CAAC;IACpB,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,mBAAmB,EAAE,MAAM,IAAI,CAAC;IAChC,MAAM,CAAC,EAAE,eAAe,CAAC;CAC1B;AAED,eAAO,MAAM,gBAAgB,UAAW,qBAAqB,gBAiG5D,CAAC"}