@perses-dev/plugin-system 0.53.0-beta.1 → 0.53.0-beta.3

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 (78) hide show
  1. package/dist/cjs/components/MultiQueryEditor/MultiQueryEditor.js +8 -3
  2. package/dist/cjs/components/MultiQueryEditor/QueryEditorContainer.js +74 -29
  3. package/dist/cjs/components/PanelSpecEditor/PanelSpecEditor.js +10 -1
  4. package/dist/cjs/components/PluginEditor/PluginEditor.js +11 -45
  5. package/dist/cjs/components/Variables/VariableEditorForm/VariableEditorForm.js +27 -10
  6. package/dist/cjs/components/Variables/VariableEditorForm/VariablePreview.js +1 -1
  7. package/dist/cjs/components/Variables/variable-model.js +3 -3
  8. package/dist/cjs/runtime/TimeRangeProvider/TimeRangeProvider.js +70 -33
  9. package/dist/cjs/runtime/TimeRangeProvider/{TimeRangeProviderWithQueryParams.js → TimeRangeProviders.js} +23 -5
  10. package/dist/cjs/runtime/TimeRangeProvider/index.js +1 -1
  11. package/dist/cjs/runtime/log-queries.js +2 -1
  12. package/dist/cjs/runtime/profile-queries.js +2 -1
  13. package/dist/cjs/runtime/time-series-queries.js +10 -16
  14. package/dist/cjs/runtime/trace-queries.js +3 -2
  15. package/dist/cjs/test/utils.js +4 -4
  16. package/dist/components/MultiQueryEditor/MultiQueryEditor.d.ts +3 -0
  17. package/dist/components/MultiQueryEditor/MultiQueryEditor.d.ts.map +1 -1
  18. package/dist/components/MultiQueryEditor/MultiQueryEditor.js +8 -3
  19. package/dist/components/MultiQueryEditor/MultiQueryEditor.js.map +1 -1
  20. package/dist/components/MultiQueryEditor/QueryEditorContainer.d.ts +3 -0
  21. package/dist/components/MultiQueryEditor/QueryEditorContainer.d.ts.map +1 -1
  22. package/dist/components/MultiQueryEditor/QueryEditorContainer.js +75 -30
  23. package/dist/components/MultiQueryEditor/QueryEditorContainer.js.map +1 -1
  24. package/dist/components/PanelSpecEditor/PanelSpecEditor.d.ts +1 -0
  25. package/dist/components/PanelSpecEditor/PanelSpecEditor.d.ts.map +1 -1
  26. package/dist/components/PanelSpecEditor/PanelSpecEditor.js +11 -2
  27. package/dist/components/PanelSpecEditor/PanelSpecEditor.js.map +1 -1
  28. package/dist/components/PluginEditor/PluginEditor.d.ts +3 -3
  29. package/dist/components/PluginEditor/PluginEditor.d.ts.map +1 -1
  30. package/dist/components/PluginEditor/PluginEditor.js +12 -46
  31. package/dist/components/PluginEditor/PluginEditor.js.map +1 -1
  32. package/dist/components/PluginEditor/plugin-editor-api.d.ts +1 -1
  33. package/dist/components/PluginEditor/plugin-editor-api.d.ts.map +1 -1
  34. package/dist/components/PluginEditor/plugin-editor-api.js.map +1 -1
  35. package/dist/components/Variables/VariableEditorForm/VariableEditorForm.d.ts.map +1 -1
  36. package/dist/components/Variables/VariableEditorForm/VariableEditorForm.js +28 -11
  37. package/dist/components/Variables/VariableEditorForm/VariableEditorForm.js.map +1 -1
  38. package/dist/components/Variables/VariableEditorForm/VariablePreview.d.ts.map +1 -1
  39. package/dist/components/Variables/VariableEditorForm/VariablePreview.js +1 -1
  40. package/dist/components/Variables/VariableEditorForm/VariablePreview.js.map +1 -1
  41. package/dist/components/Variables/variable-model.js +3 -3
  42. package/dist/components/Variables/variable-model.js.map +1 -1
  43. package/dist/model/plugin-base.d.ts +1 -6
  44. package/dist/model/plugin-base.d.ts.map +1 -1
  45. package/dist/model/plugin-base.js.map +1 -1
  46. package/dist/model/time-series-queries.d.ts +0 -1
  47. package/dist/model/time-series-queries.d.ts.map +1 -1
  48. package/dist/model/time-series-queries.js.map +1 -1
  49. package/dist/runtime/DataQueriesProvider/model.d.ts +1 -1
  50. package/dist/runtime/DataQueriesProvider/model.d.ts.map +1 -1
  51. package/dist/runtime/DataQueriesProvider/model.js.map +1 -1
  52. package/dist/runtime/TimeRangeProvider/TimeRangeProvider.d.ts +2 -3
  53. package/dist/runtime/TimeRangeProvider/TimeRangeProvider.d.ts.map +1 -1
  54. package/dist/runtime/TimeRangeProvider/TimeRangeProvider.js +70 -33
  55. package/dist/runtime/TimeRangeProvider/TimeRangeProvider.js.map +1 -1
  56. package/dist/runtime/TimeRangeProvider/TimeRangeProviders.d.ts +10 -0
  57. package/dist/runtime/TimeRangeProvider/TimeRangeProviders.d.ts.map +1 -0
  58. package/dist/runtime/TimeRangeProvider/{TimeRangeProviderWithQueryParams.js → TimeRangeProviders.js} +13 -3
  59. package/dist/runtime/TimeRangeProvider/TimeRangeProviders.js.map +1 -0
  60. package/dist/runtime/TimeRangeProvider/index.d.ts +1 -1
  61. package/dist/runtime/TimeRangeProvider/index.d.ts.map +1 -1
  62. package/dist/runtime/TimeRangeProvider/index.js +1 -1
  63. package/dist/runtime/TimeRangeProvider/index.js.map +1 -1
  64. package/dist/runtime/log-queries.js +2 -1
  65. package/dist/runtime/log-queries.js.map +1 -1
  66. package/dist/runtime/profile-queries.js +2 -1
  67. package/dist/runtime/profile-queries.js.map +1 -1
  68. package/dist/runtime/time-series-queries.d.ts.map +1 -1
  69. package/dist/runtime/time-series-queries.js +10 -16
  70. package/dist/runtime/time-series-queries.js.map +1 -1
  71. package/dist/runtime/trace-queries.js +3 -2
  72. package/dist/runtime/trace-queries.js.map +1 -1
  73. package/dist/test/utils.js +5 -5
  74. package/dist/test/utils.js.map +1 -1
  75. package/package.json +4 -4
  76. package/dist/runtime/TimeRangeProvider/TimeRangeProviderWithQueryParams.d.ts +0 -9
  77. package/dist/runtime/TimeRangeProvider/TimeRangeProviderWithQueryParams.d.ts.map +0 -1
  78. package/dist/runtime/TimeRangeProvider/TimeRangeProviderWithQueryParams.js.map +0 -1
@@ -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 = [], 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) {
@@ -132,11 +135,13 @@ const MultiQueryEditor = /*#__PURE__*/ (0, _react.forwardRef)((props, ref)=>{
132
135
  queryTypes: queryTypes,
133
136
  index: i,
134
137
  query: query,
138
+ queryResult: queryResults?.[i],
139
+ filteredQueryPlugins: filteredQueryPlugins,
135
140
  isCollapsed: !!queriesCollapsed[i],
136
141
  onChange: handleQueryChange,
142
+ onQueryRun: handleQueryRun,
137
143
  onDelete: queries.length > 1 ? handleQueryDelete : undefined,
138
- onCollapseExpand: handleQueryCollapseExpand,
139
- filteredQueryPlugins: filteredQueryPlugins
144
+ onCollapseExpand: handleQueryCollapseExpand
140
145
  }, i))
141
146
  }),
142
147
  /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Button, {
@@ -27,55 +27,101 @@ const _DeleteOutline = /*#__PURE__*/ _interop_require_default(require("mdi-mater
27
27
  const _ChevronDown = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/ChevronDown"));
28
28
  const _ChevronRight = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/ChevronRight"));
29
29
  const _react = require("react");
30
+ const _Alert = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/Alert"));
31
+ const _components = require("@perses-dev/components");
30
32
  const _PluginEditor = require("../PluginEditor");
31
- const _runtime = require("../../runtime");
32
33
  function _interop_require_default(obj) {
33
34
  return obj && obj.__esModule ? obj : {
34
35
  default: obj
35
36
  };
36
37
  }
37
38
  const QueryEditorContainer = /*#__PURE__*/ (0, _react.forwardRef)((props, ref)=>{
38
- const { queryTypes, filteredQueryPlugins, index, query, isCollapsed, onDelete, onChange, onCollapseExpand } = props;
39
+ const { queryTypes, index, query, queryResult, filteredQueryPlugins, isCollapsed, onDelete, onChange, onQueryRun, onCollapseExpand } = props;
39
40
  return /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Stack, {
40
41
  spacing: 1,
41
42
  children: [
42
43
  /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Stack, {
43
44
  direction: "row",
44
45
  alignItems: "center",
46
+ justifyContent: "space-between",
45
47
  borderBottom: 1,
46
48
  borderColor: (theme)=>theme.palette.divider,
47
49
  children: [
48
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.IconButton, {
49
- size: "small",
50
- onClick: ()=>onCollapseExpand(index),
51
- children: isCollapsed ? /*#__PURE__*/ (0, _jsxruntime.jsx)(_ChevronRight.default, {}) : /*#__PURE__*/ (0, _jsxruntime.jsx)(_ChevronDown.default, {})
52
- }),
53
- /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Typography, {
54
- variant: "overline",
55
- component: "h4",
50
+ /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Stack, {
51
+ direction: "row",
56
52
  children: [
57
- "Query #",
58
- index + 1
53
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.IconButton, {
54
+ size: "small",
55
+ onClick: ()=>onCollapseExpand(index),
56
+ children: isCollapsed ? /*#__PURE__*/ (0, _jsxruntime.jsx)(_ChevronRight.default, {}) : /*#__PURE__*/ (0, _jsxruntime.jsx)(_ChevronDown.default, {})
57
+ }),
58
+ /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Typography, {
59
+ variant: "overline",
60
+ component: "h4",
61
+ children: [
62
+ "Query #",
63
+ index + 1
64
+ ]
65
+ })
59
66
  ]
60
67
  }),
61
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.IconButton, {
62
- size: "small",
63
- // Use `visibility` to ensure that the row has the same height when delete button is visible or not visible
64
- sx: {
65
- marginLeft: 'auto',
66
- visibility: `${onDelete ? 'visible' : 'hidden'}`
67
- },
68
- onClick: ()=>onDelete && onDelete(index),
69
- children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_DeleteOutline.default, {})
68
+ /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Stack, {
69
+ direction: "row",
70
+ alignItems: "center",
71
+ children: [
72
+ queryResult?.isFetching && /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.CircularProgress, {
73
+ "aria-label": "loading",
74
+ size: "1.125rem"
75
+ }),
76
+ queryResult?.error && /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.InfoTooltip, {
77
+ description: queryResult.error.message,
78
+ children: /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Stack, {
79
+ direction: "row",
80
+ alignItems: "center",
81
+ sx: {
82
+ color: (theme)=>theme.palette.error.main
83
+ },
84
+ children: [
85
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.IconButton, {
86
+ "aria-label": "query error",
87
+ size: "small",
88
+ sx: {
89
+ color: (theme)=>theme.palette.error.main
90
+ },
91
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_Alert.default, {})
92
+ }),
93
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Typography, {
94
+ sx: {
95
+ maxWidth: 300,
96
+ whiteSpace: 'nowrap',
97
+ overflow: 'hidden',
98
+ textOverflow: 'ellipsis',
99
+ '&:hover ::after': {
100
+ content: '"Click to copy"'
101
+ }
102
+ },
103
+ children: queryResult.error.message
104
+ })
105
+ ]
106
+ })
107
+ }),
108
+ onDelete && /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.IconButton, {
109
+ "aria-label": "delete query",
110
+ size: "small",
111
+ onClick: ()=>onDelete && onDelete(index),
112
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_DeleteOutline.default, {})
113
+ })
114
+ ]
70
115
  })
71
116
  ]
72
117
  }),
73
118
  !isCollapsed && /*#__PURE__*/ (0, _jsxruntime.jsx)(QueryEditor, {
74
- filteredQueryPlugins: filteredQueryPlugins,
75
119
  ref: ref,
76
120
  queryTypes: queryTypes,
77
121
  value: query,
78
- onChange: (next)=>onChange(index, next)
122
+ filteredQueryPlugins: filteredQueryPlugins,
123
+ onChange: (next)=>onChange(index, next),
124
+ onQueryRun: ()=>onQueryRun(index, query)
79
125
  })
80
126
  ]
81
127
  }, index);
@@ -88,8 +134,7 @@ QueryEditorContainer.displayName = 'QueryEditorContainer';
88
134
  * @param props
89
135
  * @constructor
90
136
  */ const QueryEditor = /*#__PURE__*/ (0, _react.forwardRef)((props, ref)=>{
91
- const { value, onChange, queryTypes, filteredQueryPlugins, ...others } = props;
92
- const { refresh } = (0, _runtime.useTimeRange)();
137
+ const { queryTypes, value, filteredQueryPlugins, onChange, onQueryRun, ...others } = props;
93
138
  const handlePluginChange = (next)=>{
94
139
  onChange((0, _immer.produce)(value, (draft)=>{
95
140
  draft.kind = next.selection.type;
@@ -100,9 +145,7 @@ QueryEditorContainer.displayName = 'QueryEditorContainer';
100
145
  return /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Box, {
101
146
  ...others,
102
147
  children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_PluginEditor.PluginEditor, {
103
- postExecuteRunQuery: refresh,
104
148
  ref: ref,
105
- withRunQueryButton: true,
106
149
  pluginTypes: queryTypes,
107
150
  pluginKindLabel: "Query Type",
108
151
  value: {
@@ -112,8 +155,10 @@ QueryEditorContainer.displayName = 'QueryEditorContainer';
112
155
  },
113
156
  spec: value.spec.plugin.spec
114
157
  },
115
- onChange: handlePluginChange,
116
- filteredQueryPlugins: filteredQueryPlugins
158
+ filteredQueryPlugins: filteredQueryPlugins,
159
+ withRunQueryButton: true,
160
+ onRunQuery: onQueryRun,
161
+ onChange: handlePluginChange
117
162
  })
118
163
  });
119
164
  });
@@ -28,9 +28,10 @@ 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
+ const { queryResults } = (0, _runtime.useDataQueriesContext)();
34
35
  if (error) {
35
36
  return /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.ErrorAlert, {
36
37
  error: error
@@ -54,9 +55,17 @@ const PanelSpecEditor = /*#__PURE__*/ (0, _react.forwardRef)((props, ref)=>{
54
55
  ref: ref,
55
56
  queryTypes: plugin.supportedQueryTypes ?? [],
56
57
  queries: panelDefinition.spec.queries ?? [],
58
+ queryResults: queryResults,
57
59
  onChange: (queries)=>{
58
60
  field.onChange(queries);
59
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
+ }
60
69
  }
61
70
  })
62
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, postExecuteRunQuery: refresh, 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
- refresh?.();
39
+ const handleSpecChange = (0, _react.useCallback)((nextSpec)=>{
40
+ onSpecChange(nextSpec);
54
41
  }, [
55
- value.spec,
56
- onSpecChange,
57
- watchedQuery,
58
- watchedOtherSpecs,
59
- refresh
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
+ }
@@ -26,11 +26,11 @@ const _material = require("@mui/material");
26
26
  const _components = require("@perses-dev/components");
27
27
  const _reacthookform = require("react-hook-form");
28
28
  const _zod = require("@hookform/resolvers/zod");
29
+ const _reactquery = require("@tanstack/react-query");
29
30
  const _utils = require("../../../utils");
30
31
  const _PluginEditor = require("../../PluginEditor");
31
32
  const _context = require("../../../context");
32
33
  const _variablemodel = require("../variable-model");
33
- const _runtime = require("../../../runtime");
34
34
  const _VariablePreview = require("./VariablePreview");
35
35
  const _variableeditorformmodel = require("./variable-editor-form-model");
36
36
  function FallbackPreview() {
@@ -104,10 +104,29 @@ function TextVariableEditorForm({ action, control }) {
104
104
  }
105
105
  function ListVariableEditorForm({ action, control }) {
106
106
  const form = (0, _reacthookform.useFormContext)();
107
- /** We use `previewSpec` to know when to explicitly update the
108
- * spec that will be used for preview. The reason why we do this is to avoid
107
+ const queryClient = (0, _reactquery.useQueryClient)();
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
109
111
  * having to re-fetch the values when the user is still editing the spec.
110
- */ 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
+ ]);
111
130
  const plugin = (0, _reacthookform.useWatch)({
112
131
  control,
113
132
  name: 'spec.plugin'
@@ -124,7 +143,6 @@ function ListVariableEditorForm({ action, control }) {
124
143
  });
125
144
  // When variable kind is selected we need to provide default values
126
145
  // TODO: check if react-hook-form has a better way to do this
127
- const values = form.getValues();
128
146
  if (values.spec.allowAllValue === undefined) {
129
147
  form.setValue('spec.allowAllValue', false);
130
148
  }
@@ -140,7 +158,6 @@ function ListVariableEditorForm({ action, control }) {
140
158
  if (!values.spec.sort) {
141
159
  form.setValue('spec.sort', 'none');
142
160
  }
143
- const { refresh } = (0, _runtime.useTimeRange)();
144
161
  return /*#__PURE__*/ (0, _jsxruntime.jsxs)(_jsxruntime.Fragment, {
145
162
  children: [
146
163
  /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Typography, {
@@ -156,11 +173,11 @@ function ListVariableEditorForm({ action, control }) {
156
173
  children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.ErrorBoundary, {
157
174
  FallbackComponent: FallbackPreview,
158
175
  resetKeys: [
159
- previewSpec
176
+ previewDefinition
160
177
  ],
161
178
  children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_VariablePreview.VariableListPreview, {
162
179
  sortMethod: sortMethod,
163
- definition: previewSpec
180
+ definition: previewDefinition
164
181
  })
165
182
  })
166
183
  }),
@@ -172,7 +189,6 @@ function ListVariableEditorForm({ action, control }) {
172
189
  name: "spec.plugin",
173
190
  render: ({ field })=>{
174
191
  return /*#__PURE__*/ (0, _jsxruntime.jsx)(_PluginEditor.PluginEditor, {
175
- postExecuteRunQuery: refresh,
176
192
  withRunQueryButton: true,
177
193
  width: "100%",
178
194
  pluginTypes: [
@@ -192,7 +208,8 @@ function ListVariableEditorForm({ action, control }) {
192
208
  kind: v.selection.kind,
193
209
  spec: v.spec
194
210
  });
195
- }
211
+ },
212
+ onRunQuery: handleRunQuery
196
213
  });
197
214
  }
198
215
  })
@@ -159,7 +159,7 @@ function VariablePreview(props) {
159
159
  },
160
160
  children: [
161
161
  variablePreviewState,
162
- values?.slice(0, maxValues).map((val, index)=>/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Chip, {
162
+ values?.slice(0, maxValues).filter((val)=>val).map((val, index)=>/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Chip, {
163
163
  size: "small",
164
164
  label: val
165
165
  }, index)),
@@ -65,7 +65,7 @@ function useListVariablePluginValues(definition) {
65
65
  const { data: variablePlugin } = (0, _runtime.usePlugin)('Variable', definition.spec.plugin.kind);
66
66
  const datasourceStore = (0, _runtime.useDatasourceStore)();
67
67
  const allVariables = (0, _runtime.useAllVariableValues)();
68
- const { absoluteTimeRange: timeRange, refreshKey } = (0, _runtime.useTimeRange)();
68
+ const { absoluteTimeRange: timeRange } = (0, _runtime.useTimeRange)();
69
69
  const variablePluginCtx = {
70
70
  timeRange,
71
71
  datasourceStore,
@@ -88,10 +88,10 @@ function useListVariablePluginValues(definition) {
88
88
  const variablesValueKey = getVariableValuesKey(variables);
89
89
  return (0, _reactquery.useQuery)({
90
90
  queryKey: [
91
+ 'variable',
91
92
  definition,
92
- variablesValueKey,
93
93
  timeRange,
94
- refreshKey
94
+ variablesValueKey
95
95
  ],
96
96
  queryFn: async ({ signal })=>{
97
97
  const resp = await variablePlugin?.getVariableOptions(spec, {
@@ -40,6 +40,7 @@ _export(exports, {
40
40
  const _jsxruntime = require("react/jsx-runtime");
41
41
  const _react = /*#__PURE__*/ _interop_require_wildcard(require("react"));
42
42
  const _core = require("@perses-dev/core");
43
+ const _reactquery = require("@tanstack/react-query");
43
44
  const _refreshinterval = require("./refresh-interval");
44
45
  function _getRequireWildcardCache(nodeInterop) {
45
46
  if (typeof WeakMap !== "function") return null;
@@ -100,62 +101,98 @@ function useSuggestedStepMs(width) {
100
101
  }
101
102
  function TimeRangeProvider(props) {
102
103
  const { timeRange, refreshInterval, children, setTimeRange, setRefreshInterval } = props;
103
- /**
104
- * TODO: The hook needs refactor. There is a bug here with refreshKey. If the refreshInterval is not set,
105
- * refreshKey string includes an undefined xx:yy:zz:undefined:0
106
- * I think exposing refresh functionality also is very risky. A careless usage of refresh may cause
107
- * infinite rendering loop.
108
- */ const [localTimeRange, setLocalTimeRange] = (0, _react.useState)(timeRange);
109
- const [localRefreshInterval, setLocalRefreshInterval] = (0, _react.useState)(refreshInterval);
110
- const [refreshCounter, setRefreshCounter] = (0, _react.useState)(0);
111
- (0, _react.useEffect)(()=>{
112
- setLocalTimeRange(timeRange);
104
+ const queryClient = (0, _reactquery.useQueryClient)();
105
+ const [absoluteTimeRange, setAbsoluteTimeRange] = (0, _react.useState)((0, _core.isRelativeTimeRange)(timeRange) ? (0, _core.toAbsoluteTimeRange)(timeRange) : timeRange);
106
+ const handleSetTimeRange = (0, _react.useCallback)((value)=>{
107
+ setTimeRange(value);
108
+ setAbsoluteTimeRange((0, _core.isRelativeTimeRange)(value) ? (0, _core.toAbsoluteTimeRange)(value) : value);
113
109
  }, [
114
- timeRange,
115
- refreshCounter
110
+ setTimeRange
116
111
  ]);
117
- (0, _react.useEffect)(()=>{
118
- setLocalRefreshInterval(refreshInterval);
112
+ // Refresh is called when clicking on the refresh button, it refreshes all queries including variables
113
+ const refresh = (0, _react.useCallback)(()=>{
114
+ setAbsoluteTimeRange((0, _core.isRelativeTimeRange)(timeRange) ? (0, _core.toAbsoluteTimeRange)(timeRange) : timeRange);
115
+ queryClient.invalidateQueries({
116
+ queryKey: [
117
+ 'query'
118
+ ]
119
+ }).finally(()=>queryClient.removeQueries({
120
+ queryKey: [
121
+ 'query'
122
+ ],
123
+ type: 'inactive'
124
+ }));
125
+ queryClient.invalidateQueries({
126
+ queryKey: [
127
+ 'variable'
128
+ ]
129
+ }).finally(()=>queryClient.removeQueries({
130
+ queryKey: [
131
+ 'variable'
132
+ ],
133
+ type: 'inactive'
134
+ }));
119
135
  }, [
120
- refreshInterval
136
+ queryClient,
137
+ timeRange
121
138
  ]);
122
- const refresh = (0, _react.useCallback)(()=>{
123
- setRefreshCounter((counter)=>counter + 1);
139
+ // Auto refresh is only refreshing queries of panels
140
+ const autoRefresh = (0, _react.useCallback)(()=>{
141
+ setAbsoluteTimeRange((0, _core.isRelativeTimeRange)(timeRange) ? (0, _core.toAbsoluteTimeRange)(timeRange) : timeRange);
142
+ queryClient.invalidateQueries({
143
+ queryKey: [
144
+ 'query'
145
+ ]
146
+ }).finally(()=>{
147
+ queryClient.removeQueries({
148
+ queryKey: [
149
+ 'query'
150
+ ],
151
+ type: 'inactive'
152
+ });
153
+ queryClient.removeQueries({
154
+ queryKey: [
155
+ 'variable'
156
+ ],
157
+ type: 'inactive'
158
+ }); // Timerange is in queryKey, can lead to memory leak when using relative timerange
159
+ });
124
160
  }, [
125
- setRefreshCounter
161
+ queryClient,
162
+ timeRange
163
+ ]);
164
+ const refreshIntervalInMs = (0, _react.useMemo)(()=>(0, _refreshinterval.getRefreshIntervalInMs)(refreshInterval), [
165
+ refreshInterval
126
166
  ]);
127
- const refreshIntervalInMs = (0, _refreshinterval.getRefreshIntervalInMs)(localRefreshInterval);
128
167
  (0, _react.useEffect)(()=>{
129
168
  if (refreshIntervalInMs > 0) {
130
169
  const interval = setInterval(()=>{
131
- refresh();
170
+ autoRefresh();
132
171
  }, refreshIntervalInMs);
133
172
  return ()=>clearInterval(interval);
134
173
  }
135
174
  }, [
136
- refresh,
175
+ autoRefresh,
137
176
  refreshIntervalInMs
138
177
  ]);
139
178
  const ctx = (0, _react.useMemo)(()=>{
140
- const absoluteTimeRange = (0, _core.isRelativeTimeRange)(localTimeRange) ? (0, _core.toAbsoluteTimeRange)(localTimeRange) : localTimeRange;
141
179
  return {
142
- timeRange: localTimeRange,
143
- setTimeRange: setTimeRange ?? setLocalTimeRange,
144
- absoluteTimeRange,
180
+ timeRange: timeRange,
181
+ setTimeRange: handleSetTimeRange,
182
+ absoluteTimeRange: absoluteTimeRange,
145
183
  refresh,
146
- refreshKey: `${absoluteTimeRange.start}:${absoluteTimeRange.end}:${localRefreshInterval}:${refreshCounter}`,
147
- refreshInterval: localRefreshInterval,
184
+ refreshInterval: refreshInterval,
148
185
  refreshIntervalInMs: refreshIntervalInMs,
149
- setRefreshInterval: setRefreshInterval ?? setLocalRefreshInterval
186
+ setRefreshInterval: setRefreshInterval
150
187
  };
151
188
  }, [
152
- localTimeRange,
153
- setTimeRange,
189
+ absoluteTimeRange,
190
+ handleSetTimeRange,
154
191
  refresh,
155
- localRefreshInterval,
156
- refreshCounter,
192
+ refreshInterval,
157
193
  refreshIntervalInMs,
158
- setRefreshInterval
194
+ setRefreshInterval,
195
+ timeRange
159
196
  ]);
160
197
  return /*#__PURE__*/ (0, _jsxruntime.jsx)(TimeRangeContext.Provider, {
161
198
  value: ctx,
@@ -14,9 +14,17 @@
14
14
  Object.defineProperty(exports, "__esModule", {
15
15
  value: true
16
16
  });
17
- Object.defineProperty(exports, "TimeRangeProviderWithQueryParams", {
18
- enumerable: true,
19
- get: function() {
17
+ function _export(target, all) {
18
+ for(var name in all)Object.defineProperty(target, name, {
19
+ enumerable: true,
20
+ get: all[name]
21
+ });
22
+ }
23
+ _export(exports, {
24
+ TimeRangeProviderBasic: function() {
25
+ return TimeRangeProviderBasic;
26
+ },
27
+ TimeRangeProviderWithQueryParams: function() {
20
28
  return TimeRangeProviderWithQueryParams;
21
29
  }
22
30
  });
@@ -29,8 +37,7 @@ function _interop_require_default(obj) {
29
37
  default: obj
30
38
  };
31
39
  }
32
- function TimeRangeProviderWithQueryParams(props) {
33
- const { initialTimeRange, initialRefreshInterval, children } = props;
40
+ function TimeRangeProviderWithQueryParams({ initialTimeRange, initialRefreshInterval, children }) {
34
41
  const { timeRange, setTimeRange } = (0, _queryparams.useTimeRangeParams)(initialTimeRange);
35
42
  const { refreshInterval, setRefreshInterval } = (0, _queryparams.useSetRefreshIntervalParams)(initialRefreshInterval);
36
43
  return /*#__PURE__*/ (0, _jsxruntime.jsx)(_TimeRangeProvider.TimeRangeProvider, {
@@ -41,3 +48,14 @@ function TimeRangeProviderWithQueryParams(props) {
41
48
  children: children
42
49
  });
43
50
  }
51
+ function TimeRangeProviderBasic({ initialTimeRange, initialRefreshInterval, children }) {
52
+ const [timeRange, setTimeRange] = _react.default.useState(initialTimeRange);
53
+ const [refreshInterval, setRefreshInterval] = _react.default.useState(initialRefreshInterval);
54
+ return /*#__PURE__*/ (0, _jsxruntime.jsx)(_TimeRangeProvider.TimeRangeProvider, {
55
+ timeRange: timeRange,
56
+ refreshInterval: refreshInterval,
57
+ setTimeRange: setTimeRange,
58
+ setRefreshInterval: setRefreshInterval,
59
+ children: children
60
+ });
61
+ }
@@ -15,7 +15,7 @@ Object.defineProperty(exports, "__esModule", {
15
15
  value: true
16
16
  });
17
17
  _export_star(require("./TimeRangeProvider"), exports);
18
- _export_star(require("./TimeRangeProviderWithQueryParams"), exports);
18
+ _export_star(require("./TimeRangeProviders"), exports);
19
19
  _export_star(require("./TimeRangeSettingsProvider"), exports);
20
20
  _export_star(require("./query-params"), exports);
21
21
  function _export_star(from, to) {
@@ -48,8 +48,9 @@ function useLogQueries(definitions) {
48
48
  return (0, _reactquery.useQueries)({
49
49
  queries: definitions.map((definition)=>{
50
50
  const queryKey = [
51
+ 'query',
52
+ LOG_QUERY_KEY,
51
53
  definition,
52
- datasourceStore,
53
54
  absoluteTimeRange,
54
55
  variableValues
55
56
  ];
@@ -46,8 +46,9 @@ function useProfileQueries(definitions) {
46
46
  return (0, _reactquery.useQueries)({
47
47
  queries: definitions.map((definition)=>{
48
48
  const queryKey = [
49
+ 'query',
50
+ PROFILE_QUERY_KEY,
49
51
  definition,
50
- datasourceStore,
51
52
  absoluteTimeRange
52
53
  ]; // `queryKey` watches and reruns `queryFn` if keys in the array change
53
54
  const profileQueryKind = definition?.spec?.plugin?.kind;