@perses-dev/plugin-system 0.53.0-beta.2 → 0.53.0-beta.4

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 (101) hide show
  1. package/dist/cjs/components/DatasourceSelect/DatasourceSelect.js +8 -8
  2. package/dist/cjs/components/HTTPSettingsEditor/HTTPSettingsEditor.js +104 -73
  3. package/dist/cjs/components/MultiQueryEditor/MultiQueryEditor.js +5 -1
  4. package/dist/cjs/components/MultiQueryEditor/QueryEditorContainer.js +6 -6
  5. package/dist/cjs/components/PanelSpecEditor/PanelSpecEditor.js +8 -1
  6. package/dist/cjs/components/PluginEditor/PluginEditor.js +11 -45
  7. package/dist/cjs/components/PluginEditor/plugin-editor-api.js +2 -1
  8. package/dist/cjs/components/PluginRegistry/plugin-indexes.js +3 -3
  9. package/dist/cjs/components/TimeRangeControls/TimeRangeControls.js +3 -3
  10. package/dist/cjs/components/Variables/VariableEditorForm/VariableEditorForm.js +24 -18
  11. package/dist/cjs/components/Variables/VariableEditorForm/VariablePreview.js +3 -3
  12. package/dist/cjs/components/Variables/VariableEditorForm/variable-editor-form-model.js +4 -4
  13. package/dist/cjs/components/Variables/variable-model.js +5 -5
  14. package/dist/cjs/context/ValidationProvider.js +4 -4
  15. package/dist/cjs/model/legend.js +8 -8
  16. package/dist/cjs/model/panels.js +0 -6
  17. package/dist/cjs/model/plugin-base.js +0 -6
  18. package/dist/cjs/remote/PluginRuntime.js +13 -13
  19. package/dist/cjs/runtime/DataQueriesProvider/DataQueriesProvider.js +5 -5
  20. package/dist/cjs/runtime/DataQueriesProvider/model.js +3 -3
  21. package/dist/cjs/runtime/QueryCountProvider.js +3 -3
  22. package/dist/cjs/runtime/RouterProvider.js +5 -5
  23. package/dist/cjs/runtime/TimeRangeProvider/TimeRangeProvider.js +6 -6
  24. package/dist/cjs/runtime/TimeRangeProvider/TimeRangeProviders.js +3 -3
  25. package/dist/cjs/runtime/TimeRangeProvider/TimeRangeSettingsProvider.js +8 -8
  26. package/dist/cjs/runtime/TimeRangeProvider/query-params.js +10 -10
  27. package/dist/cjs/runtime/UsageMetricsProvider.js +5 -5
  28. package/dist/cjs/runtime/builtin-variables.js +5 -5
  29. package/dist/cjs/runtime/datasources.js +6 -6
  30. package/dist/cjs/runtime/log-queries.js +9 -5
  31. package/dist/cjs/runtime/plugin-registry.js +7 -7
  32. package/dist/cjs/runtime/profile-queries.js +11 -6
  33. package/dist/cjs/runtime/time-series-queries.js +10 -6
  34. package/dist/cjs/runtime/trace-queries.js +9 -5
  35. package/dist/cjs/runtime/utils.js +3 -3
  36. package/dist/cjs/runtime/variables.js +7 -7
  37. package/dist/cjs/test/mock-data.js +13 -13
  38. package/dist/cjs/test/test-plugins/bert/index.js +3 -3
  39. package/dist/cjs/test/test-plugins/ernie/index.js +3 -3
  40. package/dist/cjs/test-utils/mock-plugin-registry.js +3 -3
  41. package/dist/cjs/utils/action.js +3 -3
  42. package/dist/cjs/utils/variables.js +7 -7
  43. package/dist/components/HTTPSettingsEditor/HTTPSettingsEditor.d.ts.map +1 -1
  44. package/dist/components/HTTPSettingsEditor/HTTPSettingsEditor.js +105 -74
  45. package/dist/components/HTTPSettingsEditor/HTTPSettingsEditor.js.map +1 -1
  46. package/dist/components/MultiQueryEditor/MultiQueryEditor.d.ts +1 -0
  47. package/dist/components/MultiQueryEditor/MultiQueryEditor.d.ts.map +1 -1
  48. package/dist/components/MultiQueryEditor/MultiQueryEditor.js +5 -1
  49. package/dist/components/MultiQueryEditor/MultiQueryEditor.js.map +1 -1
  50. package/dist/components/MultiQueryEditor/QueryEditorContainer.d.ts +1 -0
  51. package/dist/components/MultiQueryEditor/QueryEditorContainer.d.ts.map +1 -1
  52. package/dist/components/MultiQueryEditor/QueryEditorContainer.js +6 -6
  53. package/dist/components/MultiQueryEditor/QueryEditorContainer.js.map +1 -1
  54. package/dist/components/PanelSpecEditor/PanelSpecEditor.d.ts +1 -0
  55. package/dist/components/PanelSpecEditor/PanelSpecEditor.d.ts.map +1 -1
  56. package/dist/components/PanelSpecEditor/PanelSpecEditor.js +8 -1
  57. package/dist/components/PanelSpecEditor/PanelSpecEditor.js.map +1 -1
  58. package/dist/components/PluginEditor/PluginEditor.d.ts +3 -3
  59. package/dist/components/PluginEditor/PluginEditor.d.ts.map +1 -1
  60. package/dist/components/PluginEditor/PluginEditor.js +12 -46
  61. package/dist/components/PluginEditor/PluginEditor.js.map +1 -1
  62. package/dist/components/PluginEditor/plugin-editor-api.d.ts +1 -1
  63. package/dist/components/PluginEditor/plugin-editor-api.d.ts.map +1 -1
  64. package/dist/components/PluginEditor/plugin-editor-api.js +2 -1
  65. package/dist/components/PluginEditor/plugin-editor-api.js.map +1 -1
  66. package/dist/components/Variables/VariableEditorForm/VariableEditorForm.d.ts.map +1 -1
  67. package/dist/components/Variables/VariableEditorForm/VariableEditorForm.js +24 -18
  68. package/dist/components/Variables/VariableEditorForm/VariableEditorForm.js.map +1 -1
  69. package/dist/components/Variables/VariableEditorForm/VariablePreview.d.ts.map +1 -1
  70. package/dist/components/Variables/VariableEditorForm/VariablePreview.js.map +1 -1
  71. package/dist/model/log-queries.d.ts +1 -1
  72. package/dist/model/log-queries.d.ts.map +1 -1
  73. package/dist/model/log-queries.js.map +1 -1
  74. package/dist/model/panels.js +1 -1
  75. package/dist/model/panels.js.map +1 -1
  76. package/dist/model/plugin-base.d.ts +1 -6
  77. package/dist/model/plugin-base.d.ts.map +1 -1
  78. package/dist/model/plugin-base.js +3 -1
  79. package/dist/model/plugin-base.js.map +1 -1
  80. package/dist/model/profile-queries.d.ts +1 -1
  81. package/dist/model/profile-queries.d.ts.map +1 -1
  82. package/dist/model/profile-queries.js.map +1 -1
  83. package/dist/model/trace-queries.d.ts +1 -1
  84. package/dist/model/trace-queries.d.ts.map +1 -1
  85. package/dist/model/trace-queries.js.map +1 -1
  86. package/dist/remote/PluginRuntime.js +10 -10
  87. package/dist/remote/PluginRuntime.js.map +1 -1
  88. package/dist/runtime/log-queries.d.ts.map +1 -1
  89. package/dist/runtime/log-queries.js +6 -2
  90. package/dist/runtime/log-queries.js.map +1 -1
  91. package/dist/runtime/profile-queries.d.ts.map +1 -1
  92. package/dist/runtime/profile-queries.js +8 -3
  93. package/dist/runtime/profile-queries.js.map +1 -1
  94. package/dist/runtime/time-series-queries.d.ts.map +1 -1
  95. package/dist/runtime/time-series-queries.js +4 -0
  96. package/dist/runtime/time-series-queries.js.map +1 -1
  97. package/dist/runtime/trace-queries.d.ts.map +1 -1
  98. package/dist/runtime/trace-queries.js +6 -2
  99. package/dist/runtime/trace-queries.js.map +1 -1
  100. package/package.json +6 -5
  101. package/LICENSE +0 -201
@@ -17,29 +17,29 @@ Object.defineProperty(exports, "__esModule", {
17
17
  function _export(target, all) {
18
18
  for(var name in all)Object.defineProperty(target, name, {
19
19
  enumerable: true,
20
- get: all[name]
20
+ get: Object.getOwnPropertyDescriptor(all, name).get
21
21
  });
22
22
  }
23
23
  _export(exports, {
24
- DatasourceName: function() {
24
+ get DatasourceName () {
25
25
  return DatasourceName;
26
26
  },
27
- DatasourceSelect: function() {
27
+ get DatasourceSelect () {
28
28
  return DatasourceSelect;
29
29
  },
30
- datasourceSelectValueToSelector: function() {
30
+ get datasourceSelectValueToSelector () {
31
31
  return datasourceSelectValueToSelector;
32
32
  },
33
- isVariableDatasource: function() {
33
+ get isVariableDatasource () {
34
34
  return isVariableDatasource;
35
35
  },
36
- optionValueToSelector: function() {
36
+ get optionValueToSelector () {
37
37
  return optionValueToSelector;
38
38
  },
39
- selectorToOptionValue: function() {
39
+ get selectorToOptionValue () {
40
40
  return selectorToOptionValue;
41
41
  },
42
- useDatasourceSelectValueToSelector: function() {
42
+ get useDatasourceSelectValueToSelector () {
43
43
  return useDatasourceSelectValueToSelector;
44
44
  }
45
45
  });
@@ -82,22 +82,50 @@ function HTTPSettingsEditor(props) {
82
82
  if (value.directUrl === undefined && value.proxy === undefined) {
83
83
  Object.assign(value, initialSpecProxy);
84
84
  }
85
- // utilitary function used for headers when renaming a property
86
- // -> TODO it would be cleaner to manipulate headers as an intermediary list instead, to avoid doing this.
87
- const buildNewHeaders = (oldHeaders, oldName, newName)=>{
88
- if (oldHeaders === undefined) return oldHeaders;
89
- const keys = Object.keys(oldHeaders);
90
- const newHeaders = keys.reduce((acc, val)=>{
91
- if (val === oldName) {
92
- acc[newName] = oldHeaders[oldName] || '';
93
- } else {
94
- acc[val] = oldHeaders[val] || '';
85
+ // Use local state to maintain an array of header entries during editing, instead of
86
+ // manipulating a map directly which causes weird UX.
87
+ const headersForm = (0, _reacthookform.useForm)({
88
+ defaultValues: {
89
+ headers: Object.entries(value.proxy?.spec.headers ?? {}).map(([name, headerValue])=>({
90
+ name,
91
+ value: headerValue
92
+ }))
93
+ }
94
+ });
95
+ const { fields, append, remove } = (0, _reacthookform.useFieldArray)({
96
+ control: headersForm.control,
97
+ name: 'headers'
98
+ });
99
+ // Watch the headers array for changes to detect duplicates
100
+ const watchedHeaders = headersForm.watch('headers');
101
+ // Check for duplicate header names
102
+ // TODO: duplication detection logic to be replaced by proper zod schema validation in the future
103
+ // ref https://github.com/perses/perses/issues/3014
104
+ const nameMap = new Map();
105
+ const duplicateNames = new Set();
106
+ watchedHeaders.forEach(({ name })=>{
107
+ if (name !== '') {
108
+ const count = (nameMap.get(name) || 0) + 1;
109
+ nameMap.set(name, count);
110
+ if (count > 1) {
111
+ duplicateNames.add(name);
95
112
  }
96
- return acc;
97
- }, {});
98
- return {
99
- ...newHeaders
100
- };
113
+ }
114
+ });
115
+ const hasDuplicates = duplicateNames.size > 0;
116
+ // Sync headers to parent
117
+ const syncHeadersToParent = (headers)=>{
118
+ const headersObject = {};
119
+ headers.forEach(({ name, value: headerValue })=>{
120
+ if (name !== '') {
121
+ headersObject[name] = headerValue;
122
+ }
123
+ });
124
+ onChange((0, _immer.produce)(value, (draft)=>{
125
+ if (draft.proxy !== undefined) {
126
+ draft.proxy.spec.headers = Object.keys(headersObject).length > 0 ? headersObject : undefined;
127
+ }
128
+ }));
101
129
  };
102
130
  const tabs = [
103
131
  {
@@ -133,7 +161,7 @@ function HTTPSettingsEditor(props) {
133
161
  })
134
162
  }),
135
163
  /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Typography, {
136
- variant: "h4",
164
+ variant: "h5",
137
165
  mb: 2,
138
166
  children: "Allowed endpoints"
139
167
  }),
@@ -308,7 +336,7 @@ function HTTPSettingsEditor(props) {
308
336
  ]
309
337
  }),
310
338
  /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Typography, {
311
- variant: "h4",
339
+ variant: "h5",
312
340
  mb: 2,
313
341
  children: "Request Headers"
314
342
  }),
@@ -317,20 +345,19 @@ function HTTPSettingsEditor(props) {
317
345
  spacing: 2,
318
346
  mb: 2,
319
347
  children: [
320
- value.proxy?.spec.headers && Object.keys(value.proxy.spec.headers).map((headerName, i)=>{
321
- return /*#__PURE__*/ (0, _jsxruntime.jsxs)(_react.Fragment, {
348
+ fields.length > 0 ? fields.map((field, index)=>/*#__PURE__*/ (0, _jsxruntime.jsxs)(_react.Fragment, {
322
349
  children: [
323
350
  /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Grid, {
324
351
  item: true,
325
352
  xs: 4,
326
353
  children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_reacthookform.Controller, {
327
- name: `Header name ${i}`,
328
- render: ({ field, fieldState })=>/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.TextField, {
329
- ...field,
354
+ control: headersForm.control,
355
+ name: `headers.${index}.name`,
356
+ render: ({ field: controllerField, fieldState })=>/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.TextField, {
357
+ ...controllerField,
330
358
  fullWidth: true,
331
359
  label: "Header name",
332
- value: headerName,
333
- error: !!fieldState.error,
360
+ error: !!fieldState.error || duplicateNames.has(controllerField.value),
334
361
  helperText: fieldState.error?.message,
335
362
  InputProps: {
336
363
  readOnly: isReadonly
@@ -339,12 +366,15 @@ function HTTPSettingsEditor(props) {
339
366
  shrink: isReadonly ? true : undefined
340
367
  },
341
368
  onChange: (e)=>{
342
- field.onChange(e);
343
- onChange((0, _immer.produce)(value, (draft)=>{
344
- if (draft.proxy !== undefined) {
345
- draft.proxy.spec.headers = buildNewHeaders(draft.proxy.spec.headers, headerName, e.target.value);
346
- }
347
- }));
369
+ controllerField.onChange(e);
370
+ const updatedHeaders = [
371
+ ...watchedHeaders
372
+ ];
373
+ updatedHeaders[index] = {
374
+ name: e.target.value,
375
+ value: updatedHeaders[index]?.value ?? ''
376
+ };
377
+ syncHeadersToParent(updatedHeaders);
348
378
  }
349
379
  })
350
380
  })
@@ -353,12 +383,12 @@ function HTTPSettingsEditor(props) {
353
383
  item: true,
354
384
  xs: 7,
355
385
  children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_reacthookform.Controller, {
356
- name: `Header value ${i}`,
357
- render: ({ field, fieldState })=>/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.TextField, {
358
- ...field,
386
+ control: headersForm.control,
387
+ name: `headers.${index}.value`,
388
+ render: ({ field: controllerField, fieldState })=>/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.TextField, {
389
+ ...controllerField,
359
390
  fullWidth: true,
360
391
  label: "Header value",
361
- value: value.proxy?.spec.headers?.[headerName],
362
392
  error: !!fieldState.error,
363
393
  helperText: fieldState.error?.message,
364
394
  InputProps: {
@@ -368,15 +398,15 @@ function HTTPSettingsEditor(props) {
368
398
  shrink: isReadonly ? true : undefined
369
399
  },
370
400
  onChange: (e)=>{
371
- field.onChange(e);
372
- onChange((0, _immer.produce)(value, (draft)=>{
373
- if (draft.proxy !== undefined) {
374
- draft.proxy.spec.headers = {
375
- ...draft.proxy.spec.headers,
376
- [headerName]: e.target.value
377
- };
378
- }
379
- }));
401
+ controllerField.onChange(e);
402
+ const updatedHeaders = [
403
+ ...watchedHeaders
404
+ ];
405
+ updatedHeaders[index] = {
406
+ name: updatedHeaders[index]?.name ?? '',
407
+ value: e.target.value
408
+ };
409
+ syncHeadersToParent(updatedHeaders);
380
410
  }
381
411
  })
382
412
  })
@@ -384,30 +414,36 @@ function HTTPSettingsEditor(props) {
384
414
  /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Grid, {
385
415
  item: true,
386
416
  xs: 1,
387
- children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_reacthookform.Controller, {
388
- name: `Remove Header ${i}`,
389
- render: ({ field })=>/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.IconButton, {
390
- ...field,
391
- disabled: isReadonly,
392
- // Remove the given header from the list
393
- onClick: (e)=>{
394
- field.onChange(e);
395
- const newHeaders = {
396
- ...value.proxy?.spec.headers
397
- };
398
- delete newHeaders[headerName];
399
- onChange((0, _immer.produce)(value, (draft)=>{
400
- if (draft.proxy !== undefined) {
401
- draft.proxy.spec.headers = newHeaders;
402
- }
403
- }));
404
- },
405
- children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_Minus.default, {})
406
- })
417
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.IconButton, {
418
+ disabled: isReadonly,
419
+ "aria-label": `Remove header ${watchedHeaders[index]?.name || index}`,
420
+ onClick: ()=>{
421
+ remove(index);
422
+ const updatedHeaders = watchedHeaders.filter((_, i)=>i !== index);
423
+ syncHeadersToParent(updatedHeaders);
424
+ },
425
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_Minus.default, {})
407
426
  })
408
427
  })
409
428
  ]
410
- }, i);
429
+ }, field.id)) : /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Grid, {
430
+ item: true,
431
+ xs: 4,
432
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Typography, {
433
+ sx: {
434
+ fontStyle: 'italic'
435
+ },
436
+ children: "None"
437
+ })
438
+ }),
439
+ hasDuplicates && /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Grid, {
440
+ item: true,
441
+ xs: 12,
442
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Typography, {
443
+ variant: "body2",
444
+ color: "error",
445
+ children: "Duplicate header names detected. Each header name must be unique."
446
+ })
411
447
  }),
412
448
  /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Grid, {
413
449
  item: true,
@@ -418,15 +454,10 @@ function HTTPSettingsEditor(props) {
418
454
  },
419
455
  children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.IconButton, {
420
456
  disabled: isReadonly,
421
- // Add a new (empty) header to the list
422
- onClick: ()=>onChange((0, _immer.produce)(value, (draft)=>{
423
- if (draft.proxy !== undefined) {
424
- draft.proxy.spec.headers = {
425
- ...draft.proxy.spec.headers,
426
- '': ''
427
- };
428
- }
429
- })),
457
+ onClick: ()=>append({
458
+ name: '',
459
+ value: ''
460
+ }),
430
461
  children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_Plus.default, {})
431
462
  })
432
463
  })
@@ -66,7 +66,7 @@ function useDefaultQueryDefinition(queryTypes, filteredQueryPlugins) {
66
66
  };
67
67
  }
68
68
  const MultiQueryEditor = /*#__PURE__*/ (0, _react.forwardRef)((props, ref)=>{
69
- const { queryTypes, queries = [], queryResults, filteredQueryPlugins, onChange } = props;
69
+ const { queryTypes, queries = [], queryResults, filteredQueryPlugins, onChange, onQueryRun } = props;
70
70
  const { defaultInitialQueryDefinition, isLoading } = useDefaultQueryDefinition(queryTypes, filteredQueryPlugins);
71
71
  // State for which queries are collapsed
72
72
  const [queriesCollapsed, setQueriesCollapsed] = (0, _react.useState)(queries.map(()=>false));
@@ -82,6 +82,9 @@ const MultiQueryEditor = /*#__PURE__*/ (0, _react.forwardRef)((props, ref)=>{
82
82
  }
83
83
  }));
84
84
  };
85
+ const handleQueryRun = (index, queryDef)=>{
86
+ onQueryRun(index, queryDef);
87
+ };
85
88
  const handleQueryAdd = ()=>{
86
89
  onChange((0, _immer.produce)(queries, (draft)=>{
87
90
  if (draft) {
@@ -136,6 +139,7 @@ const MultiQueryEditor = /*#__PURE__*/ (0, _react.forwardRef)((props, ref)=>{
136
139
  filteredQueryPlugins: filteredQueryPlugins,
137
140
  isCollapsed: !!queriesCollapsed[i],
138
141
  onChange: handleQueryChange,
142
+ onQueryRun: handleQueryRun,
139
143
  onDelete: queries.length > 1 ? handleQueryDelete : undefined,
140
144
  onCollapseExpand: handleQueryCollapseExpand
141
145
  }, i))
@@ -36,7 +36,7 @@ function _interop_require_default(obj) {
36
36
  };
37
37
  }
38
38
  const QueryEditorContainer = /*#__PURE__*/ (0, _react.forwardRef)((props, ref)=>{
39
- const { queryTypes, index, query, queryResult, filteredQueryPlugins, isCollapsed, onDelete, onChange, onCollapseExpand } = props;
39
+ const { queryTypes, index, query, queryResult, filteredQueryPlugins, isCollapsed, onDelete, onChange, onQueryRun, onCollapseExpand } = props;
40
40
  return /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Stack, {
41
41
  spacing: 1,
42
42
  children: [
@@ -119,9 +119,9 @@ const QueryEditorContainer = /*#__PURE__*/ (0, _react.forwardRef)((props, ref)=>
119
119
  ref: ref,
120
120
  queryTypes: queryTypes,
121
121
  value: query,
122
- queryResult: queryResult,
123
122
  filteredQueryPlugins: filteredQueryPlugins,
124
- onChange: (next)=>onChange(index, next)
123
+ onChange: (next)=>onChange(index, next),
124
+ onQueryRun: ()=>onQueryRun(index, query)
125
125
  })
126
126
  ]
127
127
  }, index);
@@ -134,7 +134,7 @@ QueryEditorContainer.displayName = 'QueryEditorContainer';
134
134
  * @param props
135
135
  * @constructor
136
136
  */ const QueryEditor = /*#__PURE__*/ (0, _react.forwardRef)((props, ref)=>{
137
- const { value, onChange, queryTypes, queryResult, filteredQueryPlugins, ...others } = props;
137
+ const { queryTypes, value, filteredQueryPlugins, onChange, onQueryRun, ...others } = props;
138
138
  const handlePluginChange = (next)=>{
139
139
  onChange((0, _immer.produce)(value, (draft)=>{
140
140
  draft.kind = next.selection.type;
@@ -146,7 +146,6 @@ QueryEditorContainer.displayName = 'QueryEditorContainer';
146
146
  ...others,
147
147
  children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_PluginEditor.PluginEditor, {
148
148
  ref: ref,
149
- withRunQueryButton: true,
150
149
  pluginTypes: queryTypes,
151
150
  pluginKindLabel: "Query Type",
152
151
  value: {
@@ -157,7 +156,8 @@ QueryEditorContainer.displayName = 'QueryEditorContainer';
157
156
  spec: value.spec.plugin.spec
158
157
  },
159
158
  filteredQueryPlugins: filteredQueryPlugins,
160
- onQueryRefresh: queryResult?.refetch,
159
+ withRunQueryButton: true,
160
+ onRunQuery: onQueryRun,
161
161
  onChange: handlePluginChange
162
162
  })
163
163
  });
@@ -28,7 +28,7 @@ const _runtime = require("../../runtime");
28
28
  const _OptionsEditorTabs = require("../OptionsEditorTabs");
29
29
  const _MultiQueryEditor = require("../MultiQueryEditor");
30
30
  const PanelSpecEditor = /*#__PURE__*/ (0, _react.forwardRef)((props, ref)=>{
31
- const { control, panelDefinition, onJSONChange, onQueriesChange, onPluginSpecChange } = props;
31
+ const { control, panelDefinition, onQueriesChange, onQueryRun, onPluginSpecChange, onJSONChange } = props;
32
32
  const { kind } = panelDefinition.spec.plugin;
33
33
  const { data: plugin, isLoading, error } = (0, _runtime.usePlugin)('Panel', kind);
34
34
  const { queryResults } = (0, _runtime.useDataQueriesContext)();
@@ -59,6 +59,13 @@ const PanelSpecEditor = /*#__PURE__*/ (0, _react.forwardRef)((props, ref)=>{
59
59
  onChange: (queries)=>{
60
60
  field.onChange(queries);
61
61
  onQueriesChange(queries);
62
+ },
63
+ onQueryRun: (index, query)=>{
64
+ onQueryRun(index, query);
65
+ // If spec has not changed, refetch to update the data
66
+ if (JSON.stringify(panelDefinition.spec.queries?.[index]) === JSON.stringify(query)) {
67
+ queryResults[index]?.refetch?.();
68
+ }
62
69
  }
63
70
  })
64
71
  })
@@ -33,47 +33,14 @@ function _interop_require_default(obj) {
33
33
  default: obj
34
34
  };
35
35
  }
36
- const PluginEditor = /*#__PURE__*/ (0, _react.forwardRef)((props, ref)=>{
37
- const { value, withRunQueryButton = true, pluginTypes, pluginKindLabel, onChange: _, isReadonly, onQueryRefresh, filteredQueryPlugins, ...others } = props;
36
+ function PluginEditor(props) {
37
+ const { value, withRunQueryButton = true, pluginTypes, pluginKindLabel, onChange: _, isReadonly, onRunQuery, filteredQueryPlugins, ...others } = props;
38
38
  const { pendingSelection, isLoading, error, onSelectionChange, onSpecChange } = (0, _plugineditorapi.usePluginEditor)(props);
39
- /*
40
- We could technically merge the watchedQuery, watchedOtherSpecs into a single watched-object,
41
- because at the end of the day, they are all specs.
42
- However, let's have them separated to keep the code simple and readable.
43
- Reason: Only Query string field is common between all of them. Other specs may be different
44
- Example: Legend, and MinSteps
45
- */ const [watchedQuery, setWatchQuery] = (0, _react.useState)(value.spec['query']);
46
- const [watchedOtherSpecs, setWatchOtherSpecs] = (0, _react.useState)(value.spec);
47
- const runQueryHandler = (0, _react.useCallback)(()=>{
48
- onSpecChange({
49
- ...value.spec,
50
- ...watchedOtherSpecs,
51
- query: watchedQuery
52
- });
53
- onQueryRefresh?.();
39
+ const handleSpecChange = (0, _react.useCallback)((nextSpec)=>{
40
+ onSpecChange(nextSpec);
54
41
  }, [
55
- onQueryRefresh,
56
- onSpecChange,
57
- value.spec,
58
- watchedOtherSpecs,
59
- watchedQuery
42
+ onSpecChange
60
43
  ]);
61
- const queryHandlerSettings = (0, _react.useMemo)(()=>{
62
- return withRunQueryButton ? {
63
- runWithOnBlur: false,
64
- watchQueryChanges: (query)=>{
65
- setWatchQuery(query);
66
- },
67
- setWatchOtherSpecs: (otherSpecs)=>{
68
- setWatchOtherSpecs(otherSpecs);
69
- }
70
- } : undefined;
71
- }, [
72
- withRunQueryButton
73
- ]);
74
- (0, _react.useImperativeHandle)(ref, ()=>({
75
- flushChanges: runQueryHandler
76
- }));
77
44
  return /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Box, {
78
45
  ...others,
79
46
  children: [
@@ -107,11 +74,12 @@ const PluginEditor = /*#__PURE__*/ (0, _react.forwardRef)((props, ref)=>{
107
74
  onChange: onSelectionChange,
108
75
  filteredQueryPlugins: filteredQueryPlugins
109
76
  }),
110
- withRunQueryButton && !isLoading && /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Button, {
77
+ withRunQueryButton && /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Button, {
111
78
  "data-testid": "run_query_button",
112
79
  variant: "contained",
113
80
  startIcon: /*#__PURE__*/ (0, _jsxruntime.jsx)(_Reload.default, {}),
114
- onClick: runQueryHandler,
81
+ onClick: onRunQuery,
82
+ disabled: isLoading,
115
83
  children: "Run Query"
116
84
  })
117
85
  ]
@@ -121,12 +89,10 @@ const PluginEditor = /*#__PURE__*/ (0, _react.forwardRef)((props, ref)=>{
121
89
  children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_PluginSpecEditor.PluginSpecEditor, {
122
90
  pluginSelection: value.selection,
123
91
  value: value.spec,
124
- onChange: onSpecChange,
125
- isReadonly: isReadonly,
126
- queryHandlerSettings: queryHandlerSettings
92
+ onChange: handleSpecChange,
93
+ isReadonly: isReadonly
127
94
  })
128
95
  })
129
96
  ]
130
97
  });
131
- });
132
- PluginEditor.displayName = 'PluginEditor';
98
+ }
@@ -73,7 +73,7 @@ function usePluginEditor(props) {
73
73
  // Nothing to do if no new plugin kind is pending
74
74
  if (!pendingSelection) return;
75
75
  // Can't get spec value until we have a plugin
76
- if (plugin === undefined) return;
76
+ if (plugin === undefined || isFetching) return;
77
77
  // Fire an onChange to change to the pending kind with initial values from the plugin
78
78
  rememberCurrentSpecState();
79
79
  onChange({
@@ -91,6 +91,7 @@ function usePluginEditor(props) {
91
91
  }, [
92
92
  pendingSelection,
93
93
  plugin,
94
+ isFetching,
94
95
  rememberCurrentSpecState,
95
96
  onChange,
96
97
  onHideQuery,
@@ -17,14 +17,14 @@ Object.defineProperty(exports, "__esModule", {
17
17
  function _export(target, all) {
18
18
  for(var name in all)Object.defineProperty(target, name, {
19
19
  enumerable: true,
20
- get: all[name]
20
+ get: Object.getOwnPropertyDescriptor(all, name).get
21
21
  });
22
22
  }
23
23
  _export(exports, {
24
- getTypeAndKindKey: function() {
24
+ get getTypeAndKindKey () {
25
25
  return getTypeAndKindKey;
26
26
  },
27
- usePluginIndexes: function() {
27
+ get usePluginIndexes () {
28
28
  return usePluginIndexes;
29
29
  }
30
30
  });
@@ -17,14 +17,14 @@ Object.defineProperty(exports, "__esModule", {
17
17
  function _export(target, all) {
18
18
  for(var name in all)Object.defineProperty(target, name, {
19
19
  enumerable: true,
20
- get: all[name]
20
+ get: Object.getOwnPropertyDescriptor(all, name).get
21
21
  });
22
22
  }
23
23
  _export(exports, {
24
- DEFAULT_REFRESH_INTERVAL_OPTIONS: function() {
24
+ get DEFAULT_REFRESH_INTERVAL_OPTIONS () {
25
25
  return DEFAULT_REFRESH_INTERVAL_OPTIONS;
26
26
  },
27
- TimeRangeControls: function() {
27
+ get TimeRangeControls () {
28
28
  return TimeRangeControls;
29
29
  }
30
30
  });
@@ -105,10 +105,28 @@ function TextVariableEditorForm({ action, control }) {
105
105
  function ListVariableEditorForm({ action, control }) {
106
106
  const form = (0, _reacthookform.useFormContext)();
107
107
  const queryClient = (0, _reactquery.useQueryClient)();
108
- /** We use `previewSpec` to know when to explicitly update the
109
- * spec that will be used for preview. The reason why we do this is to avoid
108
+ const values = form.getValues();
109
+ /* We use `previewDefinition` to explicitly update the spec
110
+ * that will be used for preview when running query. The reason why we do this is to avoid
110
111
  * having to re-fetch the values when the user is still editing the spec.
111
- */ const previewSpec = form.getValues();
112
+ * Using structuredClone to not have reference issues with nested objects.
113
+ */ const [previewDefinition, setPreviewDefinition] = (0, _react.useState)(structuredClone(values));
114
+ const handleRunQuery = (0, _react.useCallback)(async ()=>{
115
+ if (JSON.stringify(previewDefinition) === JSON.stringify(values)) {
116
+ await queryClient.invalidateQueries({
117
+ queryKey: [
118
+ 'variable',
119
+ previewDefinition
120
+ ]
121
+ });
122
+ } else {
123
+ setPreviewDefinition(structuredClone(values));
124
+ }
125
+ }, [
126
+ previewDefinition,
127
+ queryClient,
128
+ values
129
+ ]);
112
130
  const plugin = (0, _reacthookform.useWatch)({
113
131
  control,
114
132
  name: 'spec.plugin'
@@ -123,20 +141,8 @@ function ListVariableEditorForm({ action, control }) {
123
141
  control: control,
124
142
  name: 'spec.sort'
125
143
  });
126
- const handleRefresh = (0, _react.useCallback)(async ()=>{
127
- await queryClient.invalidateQueries({
128
- queryKey: [
129
- 'variable',
130
- previewSpec
131
- ]
132
- });
133
- }, [
134
- previewSpec,
135
- queryClient
136
- ]);
137
144
  // When variable kind is selected we need to provide default values
138
145
  // TODO: check if react-hook-form has a better way to do this
139
- const values = form.getValues();
140
146
  if (values.spec.allowAllValue === undefined) {
141
147
  form.setValue('spec.allowAllValue', false);
142
148
  }
@@ -167,11 +173,11 @@ function ListVariableEditorForm({ action, control }) {
167
173
  children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.ErrorBoundary, {
168
174
  FallbackComponent: FallbackPreview,
169
175
  resetKeys: [
170
- previewSpec
176
+ previewDefinition
171
177
  ],
172
178
  children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_VariablePreview.VariableListPreview, {
173
179
  sortMethod: sortMethod,
174
- definition: previewSpec
180
+ definition: previewDefinition
175
181
  })
176
182
  })
177
183
  }),
@@ -203,7 +209,7 @@ function ListVariableEditorForm({ action, control }) {
203
209
  spec: v.spec
204
210
  });
205
211
  },
206
- onQueryRefresh: handleRefresh
212
+ onRunQuery: handleRunQuery
207
213
  });
208
214
  }
209
215
  })
@@ -17,14 +17,14 @@ Object.defineProperty(exports, "__esModule", {
17
17
  function _export(target, all) {
18
18
  for(var name in all)Object.defineProperty(target, name, {
19
19
  enumerable: true,
20
- get: all[name]
20
+ get: Object.getOwnPropertyDescriptor(all, name).get
21
21
  });
22
22
  }
23
23
  _export(exports, {
24
- VariableListPreview: function() {
24
+ get VariableListPreview () {
25
25
  return VariableListPreview;
26
26
  },
27
- VariablePreview: function() {
27
+ get VariablePreview () {
28
28
  return VariablePreview;
29
29
  }
30
30
  });
@@ -17,17 +17,17 @@ Object.defineProperty(exports, "__esModule", {
17
17
  function _export(target, all) {
18
18
  for(var name in all)Object.defineProperty(target, name, {
19
19
  enumerable: true,
20
- get: all[name]
20
+ get: Object.getOwnPropertyDescriptor(all, name).get
21
21
  });
22
22
  }
23
23
  _export(exports, {
24
- SORT_METHODS: function() {
24
+ get SORT_METHODS () {
25
25
  return SORT_METHODS;
26
26
  },
27
- getInitialState: function() {
27
+ get getInitialState () {
28
28
  return getInitialState;
29
29
  },
30
- getVariableDefinitionFromState: function() {
30
+ get getVariableDefinitionFromState () {
31
31
  return getVariableDefinitionFromState;
32
32
  }
33
33
  });