@perses-dev/plugin-system 0.51.0-beta.1 → 0.51.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 (53) hide show
  1. package/dist/cjs/components/DatasourceSelect.js +155 -71
  2. package/dist/cjs/components/TimeRangeControls/TimeRangeControls.js +91 -1
  3. package/dist/cjs/components/Variables/VariableEditorForm/VariableEditorForm.js +11 -7
  4. package/dist/cjs/constants/user-interface-text.js +3 -1
  5. package/dist/cjs/remote/PluginRuntime.js +168 -162
  6. package/dist/cjs/runtime/TimeRangeProvider/TimeRangeSettingsProvider.js +13 -0
  7. package/dist/cjs/runtime/time-series-queries.js +3 -13
  8. package/dist/cjs/runtime/trace-queries.js +46 -16
  9. package/dist/cjs/runtime/utils.js +39 -0
  10. package/dist/components/DatasourceSelect.d.ts +8 -3
  11. package/dist/components/DatasourceSelect.d.ts.map +1 -1
  12. package/dist/components/DatasourceSelect.js +148 -72
  13. package/dist/components/DatasourceSelect.js.map +1 -1
  14. package/dist/components/PluginRegistry/PluginRegistry.js.map +1 -1
  15. package/dist/components/PluginRegistry/plugin-indexes.d.ts +1 -1
  16. package/dist/components/PluginRegistry/plugin-indexes.d.ts.map +1 -1
  17. package/dist/components/PluginRegistry/plugin-indexes.js.map +1 -1
  18. package/dist/components/TimeRangeControls/TimeRangeControls.d.ts +2 -1
  19. package/dist/components/TimeRangeControls/TimeRangeControls.d.ts.map +1 -1
  20. package/dist/components/TimeRangeControls/TimeRangeControls.js +94 -2
  21. package/dist/components/TimeRangeControls/TimeRangeControls.js.map +1 -1
  22. package/dist/components/Variables/VariableEditorForm/VariableEditorForm.d.ts.map +1 -1
  23. package/dist/components/Variables/VariableEditorForm/VariableEditorForm.js +11 -7
  24. package/dist/components/Variables/VariableEditorForm/VariableEditorForm.js.map +1 -1
  25. package/dist/constants/user-interface-text.d.ts +2 -0
  26. package/dist/constants/user-interface-text.d.ts.map +1 -1
  27. package/dist/constants/user-interface-text.js +3 -1
  28. package/dist/constants/user-interface-text.js.map +1 -1
  29. package/dist/model/trace-queries.d.ts +13 -1
  30. package/dist/model/trace-queries.d.ts.map +1 -1
  31. package/dist/model/trace-queries.js.map +1 -1
  32. package/dist/remote/PluginRuntime.d.ts +0 -1
  33. package/dist/remote/PluginRuntime.d.ts.map +1 -1
  34. package/dist/remote/PluginRuntime.js +169 -160
  35. package/dist/remote/PluginRuntime.js.map +1 -1
  36. package/dist/runtime/TimeRangeProvider/TimeRangeSettingsProvider.d.ts +7 -0
  37. package/dist/runtime/TimeRangeProvider/TimeRangeSettingsProvider.d.ts.map +1 -1
  38. package/dist/runtime/TimeRangeProvider/TimeRangeSettingsProvider.js +13 -0
  39. package/dist/runtime/TimeRangeProvider/TimeRangeSettingsProvider.js.map +1 -1
  40. package/dist/runtime/plugin-registry.d.ts +2 -2
  41. package/dist/runtime/plugin-registry.d.ts.map +1 -1
  42. package/dist/runtime/plugin-registry.js.map +1 -1
  43. package/dist/runtime/time-series-queries.d.ts.map +1 -1
  44. package/dist/runtime/time-series-queries.js +1 -11
  45. package/dist/runtime/time-series-queries.js.map +1 -1
  46. package/dist/runtime/trace-queries.d.ts.map +1 -1
  47. package/dist/runtime/trace-queries.js +47 -17
  48. package/dist/runtime/trace-queries.js.map +1 -1
  49. package/dist/runtime/utils.d.ts +7 -0
  50. package/dist/runtime/utils.d.ts.map +1 -0
  51. package/dist/runtime/utils.js +25 -0
  52. package/dist/runtime/utils.js.map +1 -0
  53. package/package.json +3 -3
@@ -26,23 +26,42 @@ _export(exports, {
26
26
  },
27
27
  DatasourceSelect: function() {
28
28
  return DatasourceSelect;
29
+ },
30
+ datasourceSelectValueToSelector: function() {
31
+ return datasourceSelectValueToSelector;
32
+ },
33
+ isVariableDatasource: function() {
34
+ return isVariableDatasource;
35
+ },
36
+ useDatasourceSelectValueToSelector: function() {
37
+ return useDatasourceSelectValueToSelector;
29
38
  }
30
39
  });
31
40
  const _jsxruntime = require("react/jsx-runtime");
41
+ const _react = require("react");
32
42
  const _OpenInNew = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/OpenInNew"));
33
43
  const _material = require("@mui/material");
34
- const _react = require("react");
35
44
  const _runtime = require("../runtime");
45
+ const _utils = require("../utils");
36
46
  function _interop_require_default(obj) {
37
47
  return obj && obj.__esModule ? obj : {
38
48
  default: obj
39
49
  };
40
50
  }
51
+ const DATASOURCE_VARIABLE_VALUE_PREFIX = '__DATASOURCE_VARIABLE_VALUE__';
52
+ const VARIABLE_IDENTIFIER = '$';
53
+ const emptyDatasourceOption = {
54
+ name: '',
55
+ value: ''
56
+ };
41
57
  function DatasourceSelect(props) {
42
58
  const { datasourcePluginKind, value, project, onChange, ...others } = props;
43
59
  const { data, isLoading } = (0, _runtime.useListDatasourceSelectItems)(datasourcePluginKind, project);
44
- // Rebuild the group of the value if not provided
60
+ const variables = (0, _runtime.useVariableValues)();
45
61
  const defaultValue = (0, _react.useMemo)(()=>{
62
+ if (isVariableDatasource(value)) {
63
+ return value;
64
+ }
46
65
  const group = (data ?? []).flatMap((itemGroup)=>itemGroup.items).find((item)=>{
47
66
  return value.kind === item.selector.kind && value.name === item.selector.name && !item.overridden;
48
67
  })?.selector.group;
@@ -54,87 +73,112 @@ function DatasourceSelect(props) {
54
73
  value,
55
74
  data
56
75
  ]);
57
- // Convert the datasource list into menu items with name/group?/value strings that the Select input can work with
58
- const menuItems = (0, _react.useMemo)(()=>{
59
- return (data ?? []).map((itemGroup)=>({
60
- group: itemGroup.group,
61
- editLink: itemGroup.editLink,
62
- items: itemGroup.items.map((item)=>({
63
- name: item.name,
64
- overriding: item.overriding,
65
- overridden: item.overridden,
66
- saved: item.saved ?? true,
67
- group: item.selector.group,
68
- value: selectorToOptionValue(item.selector)
69
- }))
70
- }));
76
+ const options = (0, _react.useMemo)(()=>{
77
+ const datasourceOptions = (data || []).flatMap((itemGroup)=>itemGroup.items.map((item)=>({
78
+ groupLabel: itemGroup.group,
79
+ groupEditLink: itemGroup.editLink,
80
+ name: item.name,
81
+ overriding: item.overriding,
82
+ overridden: item.overridden,
83
+ saved: item.saved ?? true,
84
+ group: item.selector.group,
85
+ value: selectorToOptionValue(item.selector)
86
+ })));
87
+ const datasourceOptionsMap = new Map(datasourceOptions.map((option)=>[
88
+ option.name,
89
+ option
90
+ ]));
91
+ const variableOptions = Object.entries(variables).flatMap(([name, variable])=>{
92
+ if (Array.isArray(variable.value)) return [];
93
+ const associatedDatasource = datasourceOptionsMap.get(variable.value ?? '');
94
+ if (!associatedDatasource) return [];
95
+ return {
96
+ groupLabel: 'Variables',
97
+ name: `${VARIABLE_IDENTIFIER}${name}`,
98
+ saved: true,
99
+ value: `${DATASOURCE_VARIABLE_VALUE_PREFIX}${VARIABLE_IDENTIFIER}${name}`
100
+ };
101
+ });
102
+ return [
103
+ ...datasourceOptions,
104
+ ...variableOptions
105
+ ];
71
106
  }, [
72
- data
107
+ data,
108
+ variables
73
109
  ]);
74
- // While loading available values, just use an empty string so MUI select doesn't warn about values out of range
75
- const optionValue = isLoading ? '' : selectorToOptionValue(defaultValue);
110
+ // While loading available values, just use an empty datasource option so MUI select doesn't warn about values out of range
111
+ const optionValue = isLoading ? emptyDatasourceOption : options.find((option)=>option.value === selectorToOptionValue(defaultValue));
76
112
  // When the user makes a selection, convert the string option value back to a DatasourceSelector
77
- const handleChange = (e)=>{
78
- const next = optionValueToSelector(e.target.value);
79
- onChange(next);
113
+ const handleChange = (selectedOption)=>{
114
+ if (selectedOption) {
115
+ const next = optionValueToSelector(selectedOption?.value || '');
116
+ onChange(next);
117
+ } else {
118
+ onChange({
119
+ kind: datasourcePluginKind
120
+ });
121
+ }
80
122
  };
81
123
  // We use a fake action event when we click on the action of the chip (hijack the "delete" feature).
82
124
  // This is because the href link action is on the `deleteIcon` property already, but the `onDelete` property
83
125
  // controls its visibility.
84
126
  // eslint-disable-next-line @typescript-eslint/no-empty-function
85
127
  const fakeActionEvent = ()=>{};
86
- // TODO:
87
- // - Does this need a loading indicator of some kind?
88
- // - The group's edit link is not clickable once selected.
89
- // - The group's edit link is disabled if datasource is overridden.
90
- // Ref: https://github.com/mui/material-ui/issues/36572
91
- return /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Select, {
92
- ...others,
128
+ return /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Autocomplete, {
129
+ options: options,
130
+ renderInput: (params)=>/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.TextField, {
131
+ ...params,
132
+ label: others.label,
133
+ placeholder: ""
134
+ }),
135
+ groupBy: (option)=>option.groupLabel || 'No group',
136
+ getOptionLabel: (option)=>{
137
+ return option.name;
138
+ },
139
+ onChange: (_, v)=>handleChange(v),
93
140
  value: optionValue,
94
- onChange: handleChange,
95
- children: menuItems.map((menuItemGroup)=>[
96
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Divider, {}, `${menuItemGroup.group}-divider`),
97
- ...menuItemGroup.items.map((menuItem)=>/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.MenuItem, {
98
- value: menuItem.value,
99
- disabled: menuItem.overridden || !menuItem.saved,
100
- children: /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Stack, {
101
- direction: "row",
102
- alignItems: "center",
103
- justifyContent: "space-between",
104
- width: "100%",
105
- children: [
106
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.ListItemText, {
107
- children: /*#__PURE__*/ (0, _jsxruntime.jsx)(DatasourceName, {
108
- name: menuItem.name,
109
- overridden: menuItem.overridden,
110
- overriding: menuItem.overriding
111
- })
112
- }),
113
- !menuItem.saved && /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.ListItemText, {
114
- children: "Save the dashboard to enable this datasource"
115
- }),
116
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.ListItemText, {
117
- style: {
118
- textAlign: 'right'
119
- },
120
- children: menuItemGroup.group && menuItemGroup.group.length > 0 && /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Chip, {
121
- disabled: false,
122
- label: menuItemGroup.group,
123
- size: "small",
124
- onDelete: menuItemGroup.editLink ? fakeActionEvent : undefined,
125
- deleteIcon: menuItemGroup.editLink ? /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.IconButton, {
126
- href: menuItemGroup.editLink,
127
- target: "_blank",
128
- children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_OpenInNew.default, {
129
- fontSize: "small"
130
- })
131
- }) : undefined
132
- })
141
+ renderOption: (props, option)=>{
142
+ return /*#__PURE__*/ (0, _react.createElement)("li", {
143
+ ...props,
144
+ key: option.value
145
+ }, /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Stack, {
146
+ direction: "row",
147
+ alignItems: "center",
148
+ justifyContent: "space-between",
149
+ width: "100%",
150
+ children: [
151
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.ListItemText, {
152
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(DatasourceName, {
153
+ name: option.name,
154
+ overridden: option.overridden,
155
+ overriding: option.overriding
156
+ })
157
+ }),
158
+ !option.saved && /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.ListItemText, {
159
+ children: "Save the dashboard to enable this datasource"
160
+ }),
161
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.ListItemText, {
162
+ style: {
163
+ textAlign: 'right'
164
+ },
165
+ children: option.groupLabel && option.groupLabel.length > 0 && /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Chip, {
166
+ disabled: false,
167
+ label: option.groupLabel,
168
+ size: "small",
169
+ onDelete: option.groupEditLink ? fakeActionEvent : undefined,
170
+ deleteIcon: option.groupEditLink ? /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.IconButton, {
171
+ href: option.groupEditLink,
172
+ target: "_blank",
173
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_OpenInNew.default, {
174
+ fontSize: "small"
133
175
  })
134
- ]
176
+ }) : undefined
135
177
  })
136
- }, menuItem.value))
137
- ])
178
+ })
179
+ ]
180
+ }));
181
+ }
138
182
  });
139
183
  }
140
184
  function DatasourceName(props) {
@@ -159,6 +203,9 @@ const OPTION_VALUE_DELIMITER = '_____';
159
203
  * returns a string value like `{kind}_____{group}_____{name}` that can be used as a Select input value.
160
204
  * @param selector
161
205
  */ function selectorToOptionValue(selector) {
206
+ if (isVariableDatasource(selector)) {
207
+ return `${DATASOURCE_VARIABLE_VALUE_PREFIX}${selector}`;
208
+ }
162
209
  return [
163
210
  selector.kind,
164
211
  selector.group ?? '',
@@ -170,6 +217,9 @@ const OPTION_VALUE_DELIMITER = '_____';
170
217
  * returns a DatasourceSelector to be used by the query data model.
171
218
  * @param optionValue
172
219
  */ function optionValueToSelector(optionValue) {
220
+ if (optionValue.startsWith(DATASOURCE_VARIABLE_VALUE_PREFIX)) {
221
+ return optionValue.split(DATASOURCE_VARIABLE_VALUE_PREFIX)[1];
222
+ }
173
223
  const words = optionValue.split(OPTION_VALUE_DELIMITER);
174
224
  const kind = words[0];
175
225
  const name = words[2];
@@ -181,3 +231,37 @@ const OPTION_VALUE_DELIMITER = '_____';
181
231
  name: name === '' ? undefined : name
182
232
  };
183
233
  }
234
+ function isVariableDatasource(value) {
235
+ return typeof value === 'string' && value.startsWith(VARIABLE_IDENTIFIER);
236
+ }
237
+ const datasourceSelectValueToSelector = (value, variables, datasourceSelectItemGroups)=>{
238
+ if (!isVariableDatasource(value)) {
239
+ return value;
240
+ }
241
+ const [variableName] = (0, _utils.parseVariables)(value);
242
+ const variable = variables[variableName ?? ''];
243
+ // If the variable is not defined or if its value is an array, we cannot determine a selector and return undefined
244
+ if (!variable || Array.isArray(variable.value)) {
245
+ return undefined;
246
+ }
247
+ const associatedDatasource = (datasourceSelectItemGroups || []).flatMap((itemGroup)=>itemGroup.items).find((datasource)=>datasource.name === variable.value);
248
+ // If the variable value is not a datasource, we cannot determine a selector and return undefined
249
+ if (associatedDatasource === undefined) {
250
+ return undefined;
251
+ }
252
+ const datasourceSelector = {
253
+ kind: associatedDatasource.selector.kind,
254
+ name: associatedDatasource.selector.name
255
+ };
256
+ return datasourceSelector;
257
+ };
258
+ const useDatasourceSelectValueToSelector = (value, datasourcePluginKind)=>{
259
+ const { data } = (0, _runtime.useListDatasourceSelectItems)(datasourcePluginKind);
260
+ const variables = (0, _runtime.useVariableValues)();
261
+ if (!isVariableDatasource(value)) {
262
+ return value;
263
+ }
264
+ return datasourceSelectValueToSelector(value, variables, data) ?? {
265
+ kind: datasourcePluginKind
266
+ };
267
+ };
@@ -30,8 +30,11 @@ _export(exports, {
30
30
  });
31
31
  const _jsxruntime = require("react/jsx-runtime");
32
32
  const _Refresh = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/Refresh"));
33
+ const _PlusCircleOutline = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/PlusCircleOutline"));
34
+ const _MinusCircleOutline = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/MinusCircleOutline"));
33
35
  const _material = require("@mui/material");
34
36
  const _components = require("@perses-dev/components");
37
+ const _core = require("@perses-dev/core");
35
38
  const _react = require("react");
36
39
  const _constants = require("../../constants");
37
40
  const _runtime = require("../../runtime");
@@ -79,9 +82,10 @@ const DEFAULT_REFRESH_INTERVAL_OPTIONS = [
79
82
  }
80
83
  ];
81
84
  const DEFAULT_HEIGHT = '34px';
82
- function TimeRangeControls({ heightPx, showTimeRangeSelector = true, showRefreshButton = true, showRefreshInterval = true, showCustomTimeRange, timePresets }) {
85
+ function TimeRangeControls({ heightPx, showTimeRangeSelector = true, showRefreshButton = true, showRefreshInterval = true, showCustomTimeRange, showZoomButtons = true, timePresets }) {
83
86
  const { timeRange, setTimeRange, refresh, refreshInterval, setRefreshInterval } = (0, _runtime.useTimeRange)();
84
87
  const showCustomTimeRangeValue = (0, _runtime.useShowCustomTimeRangeSetting)(showCustomTimeRange);
88
+ const showZoomInOutButtons = (0, _runtime.useShowZoomRangeSetting)(showZoomButtons);
85
89
  const timePresetsValue = (0, _runtime.useTimeRangeOptionsSetting)(timePresets);
86
90
  // Convert height to a string, then use the string for styling
87
91
  const height = heightPx === undefined ? DEFAULT_HEIGHT : `${heightPx}px`;
@@ -95,6 +99,70 @@ function TimeRangeControls({ heightPx, showTimeRangeSelector = true, showRefresh
95
99
  }, [
96
100
  setRefreshInterval
97
101
  ]);
102
+ const fromDurationToMillis = (strDuration)=>{
103
+ const duration = (0, _core.parseDurationString)(strDuration);
104
+ const millis = // eslint-disable-next-line prettier/prettier
105
+ ((duration.seconds ?? 0) + (duration.minutes ?? 0) * 60 + (duration.hours ?? 0) * 3600 + (duration.days ?? 0) * 86400 + (duration.weeks ?? 0) * 7 * 86400 + (duration.months ?? 0) * 30.436875 * 86400 + // avg month duration is ok for zoom purposes
106
+ (duration.years ?? 0) * 365.2425 * 86400) * // avg year duration is ok for zoom purposes
107
+ // eslint-disable-next-line prettier/prettier
108
+ 1000; // to milliseconds
109
+ return millis;
110
+ };
111
+ // Function to double current time range, adding 50% before current start and 50% after current end
112
+ const doubleTimeRange = ()=>{
113
+ let newStart, newEnd, extendEndsBy;
114
+ const now = new Date();
115
+ if (Object.hasOwn(timeRange, 'start')) {
116
+ // current range is absolute
117
+ const absVal = timeRange;
118
+ extendEndsBy = (absVal.end.getTime() - absVal.start.getTime()) / 2; // half it to add 50% before current start and after current end
119
+ newStart = new Date(absVal.start.getTime() - extendEndsBy);
120
+ newEnd = new Date(absVal.end.getTime() + extendEndsBy);
121
+ } else {
122
+ // current range is relative
123
+ const relVal = timeRange;
124
+ extendEndsBy = fromDurationToMillis(relVal.pastDuration) / 2;
125
+ newEnd = typeof relVal.end === 'undefined' ? now : new Date(relVal.end.getTime() + extendEndsBy);
126
+ newStart = new Date(newEnd.getTime() - extendEndsBy * 4);
127
+ }
128
+ if (newEnd.getTime() > now.getTime()) {
129
+ // if the new computed end is in the future
130
+ newEnd = now;
131
+ newStart.setTime(now.getTime() - extendEndsBy * 4);
132
+ }
133
+ if (newStart.getTime() < 1) {
134
+ newStart.setTime(1);
135
+ }
136
+ return {
137
+ start: newStart,
138
+ end: newEnd
139
+ };
140
+ };
141
+ // Function to half current time range, cutting 25% before current start and 25% after current end
142
+ const halfTimeRange = ()=>{
143
+ let newStart, newEnd;
144
+ if (Object.hasOwn(timeRange, 'start')) {
145
+ const absVal = timeRange;
146
+ const shrinkEndsBy = (absVal.end.getTime() - absVal.start.getTime()) / 4;
147
+ newStart = new Date(absVal.start.getTime() + shrinkEndsBy);
148
+ newEnd = new Date(absVal.end.getTime() - shrinkEndsBy);
149
+ } else {
150
+ const relVal = timeRange;
151
+ const shrinkEndsBy = fromDurationToMillis(relVal.pastDuration) / 4; // 25% of it to cut after current start and before current end
152
+ const endIsAbsolute = typeof relVal.end !== 'undefined';
153
+ newEnd = endIsAbsolute ? new Date(relVal.end.getTime() - shrinkEndsBy) : new Date();
154
+ newStart = new Date(newEnd.getTime() - shrinkEndsBy * 2);
155
+ }
156
+ if (newStart.getTime() >= newEnd.getTime() - 1000) {
157
+ newStart.setTime(newEnd.getTime() - 1000);
158
+ }
159
+ return {
160
+ start: newStart,
161
+ end: newEnd
162
+ };
163
+ };
164
+ const setHalfTimeRange = ()=>setTimeRange(halfTimeRange());
165
+ const setDoubleTimeRange = ()=>setTimeRange(doubleTimeRange());
98
166
  return /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Stack, {
99
167
  direction: "row",
100
168
  spacing: 1,
@@ -106,6 +174,28 @@ function TimeRangeControls({ heightPx, showTimeRangeSelector = true, showRefresh
106
174
  height: height,
107
175
  showCustomTimeRange: showCustomTimeRangeValue
108
176
  }),
177
+ showZoomInOutButtons && /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.InfoTooltip, {
178
+ description: _constants.TOOLTIP_TEXT.zoomOut,
179
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.ToolbarIconButton, {
180
+ "aria-label": _constants.TOOLTIP_TEXT.zoomOut,
181
+ onClick: setDoubleTimeRange,
182
+ sx: {
183
+ height
184
+ },
185
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_MinusCircleOutline.default, {})
186
+ })
187
+ }),
188
+ showZoomInOutButtons && /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.InfoTooltip, {
189
+ description: _constants.TOOLTIP_TEXT.zoomIn,
190
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.ToolbarIconButton, {
191
+ "aria-label": _constants.TOOLTIP_TEXT.zoomIn,
192
+ onClick: setHalfTimeRange,
193
+ sx: {
194
+ height
195
+ },
196
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_PlusCircleOutline.default, {})
197
+ })
198
+ }),
109
199
  showRefreshButton && /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.InfoTooltip, {
110
200
  description: _constants.TOOLTIP_TEXT.refresh,
111
201
  children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.ToolbarIconButton, {
@@ -150,10 +150,12 @@ function ListVariableEditorForm({ action, control }) {
150
150
  const refreshPreview = ()=>{
151
151
  setPreviewSpec(form.getValues());
152
152
  };
153
- const kind = (0, _reacthookform.useWatch)({
154
- control: control,
155
- name: 'spec.plugin.kind'
153
+ const plugin = (0, _reacthookform.useWatch)({
154
+ control,
155
+ name: 'spec.plugin'
156
156
  });
157
+ const kind = plugin?.kind;
158
+ const pluginSpec = plugin?.spec;
157
159
  const _allowAllValue = (0, _reacthookform.useWatch)({
158
160
  control: control,
159
161
  name: 'spec.allowAllValue'
@@ -203,7 +205,8 @@ function ListVariableEditorForm({ action, control }) {
203
205
  children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_reacthookform.Controller, {
204
206
  control: control,
205
207
  name: "spec.plugin",
206
- render: ({ field })=>/*#__PURE__*/ (0, _jsxruntime.jsx)(_PluginEditor.PluginEditor, {
208
+ render: ({ field })=>{
209
+ return /*#__PURE__*/ (0, _jsxruntime.jsx)(_PluginEditor.PluginEditor, {
207
210
  width: "100%",
208
211
  pluginTypes: [
209
212
  'Variable'
@@ -212,9 +215,9 @@ function ListVariableEditorForm({ action, control }) {
212
215
  value: {
213
216
  selection: {
214
217
  type: 'Variable',
215
- kind: field.value?.kind ?? 'StaticListVariable'
218
+ kind: kind ?? 'StaticListVariable'
216
219
  },
217
- spec: field.value?.spec ?? {
220
+ spec: pluginSpec ?? {
218
221
  values: []
219
222
  }
220
223
  },
@@ -225,7 +228,8 @@ function ListVariableEditorForm({ action, control }) {
225
228
  spec: v.spec
226
229
  });
227
230
  }
228
- })
231
+ });
232
+ }
229
233
  })
230
234
  })
231
235
  ]
@@ -26,5 +26,7 @@ const TOOLTIP_TEXT = {
26
26
  copyVariableValues: 'Copy values to clipboard',
27
27
  // Time range controls buttons
28
28
  refresh: 'Refresh',
29
- refreshInterval: 'Auto refresh interval'
29
+ refreshInterval: 'Auto refresh interval',
30
+ zoomIn: 'Zoom in',
31
+ zoomOut: 'Zoom out'
30
32
  };