@perses-dev/plugin-system 0.51.0-beta.1 → 0.51.0-rc.1
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.
- package/dist/cjs/components/DatasourceSelect.js +163 -81
- package/dist/cjs/components/HTTPSettingsEditor/HTTPSettingsEditor.js +5 -2
- package/dist/cjs/components/MultiQueryEditor/MultiQueryEditor.js +1 -1
- package/dist/cjs/components/PanelSpecEditor/PanelSpecEditor.js +2 -2
- package/dist/cjs/components/TimeRangeControls/TimeRangeControls.js +91 -1
- package/dist/cjs/components/Variables/VariableEditorForm/VariableEditorForm.js +11 -7
- package/dist/cjs/components/Variables/variable-model.js +4 -2
- package/dist/cjs/constants/user-interface-text.js +3 -1
- package/dist/cjs/remote/PluginRuntime.js +168 -162
- package/dist/cjs/runtime/TimeRangeProvider/TimeRangeSettingsProvider.js +13 -0
- package/dist/cjs/runtime/time-series-queries.js +5 -14
- package/dist/cjs/runtime/trace-queries.js +46 -16
- package/dist/cjs/runtime/utils.js +39 -0
- package/dist/cjs/test/render-hook.js +31 -0
- package/dist/cjs/test/render.js +4 -21
- package/dist/cjs/test/utils.js +49 -0
- package/dist/components/DatasourceSelect.d.ts +20 -3
- package/dist/components/DatasourceSelect.d.ts.map +1 -1
- package/dist/components/DatasourceSelect.js +150 -74
- package/dist/components/DatasourceSelect.js.map +1 -1
- package/dist/components/HTTPSettingsEditor/HTTPSettingsEditor.d.ts.map +1 -1
- package/dist/components/HTTPSettingsEditor/HTTPSettingsEditor.js +5 -2
- package/dist/components/HTTPSettingsEditor/HTTPSettingsEditor.js.map +1 -1
- package/dist/components/MultiQueryEditor/MultiQueryEditor.js +1 -1
- package/dist/components/MultiQueryEditor/MultiQueryEditor.js.map +1 -1
- package/dist/components/PanelSpecEditor/PanelSpecEditor.js +2 -2
- package/dist/components/PanelSpecEditor/PanelSpecEditor.js.map +1 -1
- package/dist/components/PluginRegistry/PluginRegistry.js.map +1 -1
- package/dist/components/PluginRegistry/plugin-indexes.d.ts +1 -1
- package/dist/components/PluginRegistry/plugin-indexes.d.ts.map +1 -1
- package/dist/components/PluginRegistry/plugin-indexes.js.map +1 -1
- package/dist/components/TimeRangeControls/TimeRangeControls.d.ts +2 -1
- package/dist/components/TimeRangeControls/TimeRangeControls.d.ts.map +1 -1
- package/dist/components/TimeRangeControls/TimeRangeControls.js +94 -2
- package/dist/components/TimeRangeControls/TimeRangeControls.js.map +1 -1
- package/dist/components/Variables/VariableEditorForm/VariableEditorForm.d.ts.map +1 -1
- package/dist/components/Variables/VariableEditorForm/VariableEditorForm.js +11 -7
- package/dist/components/Variables/VariableEditorForm/VariableEditorForm.js.map +1 -1
- package/dist/components/Variables/variable-model.d.ts.map +1 -1
- package/dist/components/Variables/variable-model.js +4 -2
- package/dist/components/Variables/variable-model.js.map +1 -1
- package/dist/constants/user-interface-text.d.ts +2 -0
- package/dist/constants/user-interface-text.d.ts.map +1 -1
- package/dist/constants/user-interface-text.js +3 -1
- package/dist/constants/user-interface-text.js.map +1 -1
- package/dist/model/trace-queries.d.ts +13 -1
- package/dist/model/trace-queries.d.ts.map +1 -1
- package/dist/model/trace-queries.js.map +1 -1
- package/dist/remote/PluginRuntime.d.ts +0 -1
- package/dist/remote/PluginRuntime.d.ts.map +1 -1
- package/dist/remote/PluginRuntime.js +169 -160
- package/dist/remote/PluginRuntime.js.map +1 -1
- package/dist/runtime/TimeRangeProvider/TimeRangeSettingsProvider.d.ts +7 -0
- package/dist/runtime/TimeRangeProvider/TimeRangeSettingsProvider.d.ts.map +1 -1
- package/dist/runtime/TimeRangeProvider/TimeRangeSettingsProvider.js +13 -0
- package/dist/runtime/TimeRangeProvider/TimeRangeSettingsProvider.js.map +1 -1
- package/dist/runtime/plugin-registry.d.ts +2 -2
- package/dist/runtime/plugin-registry.d.ts.map +1 -1
- package/dist/runtime/plugin-registry.js.map +1 -1
- package/dist/runtime/time-series-queries.d.ts +1 -1
- package/dist/runtime/time-series-queries.d.ts.map +1 -1
- package/dist/runtime/time-series-queries.js +4 -13
- package/dist/runtime/time-series-queries.js.map +1 -1
- package/dist/runtime/trace-queries.d.ts.map +1 -1
- package/dist/runtime/trace-queries.js +47 -17
- package/dist/runtime/trace-queries.js.map +1 -1
- package/dist/runtime/utils.d.ts +7 -0
- package/dist/runtime/utils.d.ts.map +1 -0
- package/dist/runtime/utils.js +25 -0
- package/dist/runtime/utils.js.map +1 -0
- package/dist/test/render-hook.d.ts +8 -0
- package/dist/test/render-hook.d.ts.map +1 -0
- package/dist/test/render-hook.js +26 -0
- package/dist/test/render-hook.js.map +1 -0
- package/dist/test/render.d.ts +1 -5
- package/dist/test/render.d.ts.map +1 -1
- package/dist/test/render.js +4 -21
- package/dist/test/render.js.map +1 -1
- package/dist/test/utils.d.ts +9 -0
- package/dist/test/utils.d.ts.map +1 -0
- package/dist/test/utils.js +41 -0
- package/dist/test/utils.js.map +1 -0
- package/package.json +5 -5
|
@@ -26,23 +26,48 @@ _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
|
+
optionValueToSelector: function() {
|
|
37
|
+
return optionValueToSelector;
|
|
38
|
+
},
|
|
39
|
+
selectorToOptionValue: function() {
|
|
40
|
+
return selectorToOptionValue;
|
|
41
|
+
},
|
|
42
|
+
useDatasourceSelectValueToSelector: function() {
|
|
43
|
+
return useDatasourceSelectValueToSelector;
|
|
29
44
|
}
|
|
30
45
|
});
|
|
31
46
|
const _jsxruntime = require("react/jsx-runtime");
|
|
47
|
+
const _react = require("react");
|
|
32
48
|
const _OpenInNew = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/OpenInNew"));
|
|
33
49
|
const _material = require("@mui/material");
|
|
34
|
-
const _react = require("react");
|
|
35
50
|
const _runtime = require("../runtime");
|
|
51
|
+
const _utils = require("../utils");
|
|
36
52
|
function _interop_require_default(obj) {
|
|
37
53
|
return obj && obj.__esModule ? obj : {
|
|
38
54
|
default: obj
|
|
39
55
|
};
|
|
40
56
|
}
|
|
57
|
+
const DATASOURCE_VARIABLE_VALUE_PREFIX = '__DATASOURCE_VARIABLE_VALUE__';
|
|
58
|
+
const VARIABLE_IDENTIFIER = '$';
|
|
59
|
+
const emptyDatasourceOption = {
|
|
60
|
+
name: '',
|
|
61
|
+
value: ''
|
|
62
|
+
};
|
|
41
63
|
function DatasourceSelect(props) {
|
|
42
64
|
const { datasourcePluginKind, value, project, onChange, ...others } = props;
|
|
43
65
|
const { data, isLoading } = (0, _runtime.useListDatasourceSelectItems)(datasourcePluginKind, project);
|
|
44
|
-
|
|
66
|
+
const variables = (0, _runtime.useVariableValues)();
|
|
45
67
|
const defaultValue = (0, _react.useMemo)(()=>{
|
|
68
|
+
if (isVariableDatasource(value)) {
|
|
69
|
+
return value;
|
|
70
|
+
}
|
|
46
71
|
const group = (data ?? []).flatMap((itemGroup)=>itemGroup.items).find((item)=>{
|
|
47
72
|
return value.kind === item.selector.kind && value.name === item.selector.name && !item.overridden;
|
|
48
73
|
})?.selector.group;
|
|
@@ -54,87 +79,112 @@ function DatasourceSelect(props) {
|
|
|
54
79
|
value,
|
|
55
80
|
data
|
|
56
81
|
]);
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
82
|
+
const options = (0, _react.useMemo)(()=>{
|
|
83
|
+
const datasourceOptions = (data || []).flatMap((itemGroup)=>itemGroup.items.map((item)=>({
|
|
84
|
+
groupLabel: itemGroup.group,
|
|
85
|
+
groupEditLink: itemGroup.editLink,
|
|
86
|
+
name: item.name,
|
|
87
|
+
overriding: item.overriding,
|
|
88
|
+
overridden: item.overridden,
|
|
89
|
+
saved: item.saved ?? true,
|
|
90
|
+
group: item.selector.group,
|
|
91
|
+
value: selectorToOptionValue(item.selector)
|
|
92
|
+
})));
|
|
93
|
+
const datasourceOptionsMap = new Map(datasourceOptions.map((option)=>[
|
|
94
|
+
option.name,
|
|
95
|
+
option
|
|
96
|
+
]));
|
|
97
|
+
const variableOptions = Object.entries(variables).flatMap(([name, variable])=>{
|
|
98
|
+
if (Array.isArray(variable.value)) return [];
|
|
99
|
+
const associatedDatasource = datasourceOptionsMap.get(variable.value ?? '');
|
|
100
|
+
if (!associatedDatasource) return [];
|
|
101
|
+
return {
|
|
102
|
+
groupLabel: 'Variables',
|
|
103
|
+
name: `${VARIABLE_IDENTIFIER}${name}`,
|
|
104
|
+
saved: true,
|
|
105
|
+
value: `${DATASOURCE_VARIABLE_VALUE_PREFIX}${VARIABLE_IDENTIFIER}${name}`
|
|
106
|
+
};
|
|
107
|
+
});
|
|
108
|
+
return [
|
|
109
|
+
...datasourceOptions,
|
|
110
|
+
...variableOptions
|
|
111
|
+
];
|
|
71
112
|
}, [
|
|
72
|
-
data
|
|
113
|
+
data,
|
|
114
|
+
variables
|
|
73
115
|
]);
|
|
74
|
-
// While loading available values, just use an empty
|
|
75
|
-
const optionValue = isLoading ?
|
|
116
|
+
// While loading available values, just use an empty datasource option so MUI select doesn't warn about values out of range
|
|
117
|
+
const optionValue = isLoading ? emptyDatasourceOption : options.find((option)=>option.value === selectorToOptionValue(defaultValue));
|
|
76
118
|
// When the user makes a selection, convert the string option value back to a DatasourceSelector
|
|
77
|
-
const handleChange = (
|
|
78
|
-
|
|
79
|
-
|
|
119
|
+
const handleChange = (selectedOption)=>{
|
|
120
|
+
if (selectedOption) {
|
|
121
|
+
const next = optionValueToSelector(selectedOption?.value || '');
|
|
122
|
+
onChange(next);
|
|
123
|
+
} else {
|
|
124
|
+
onChange({
|
|
125
|
+
kind: datasourcePluginKind
|
|
126
|
+
});
|
|
127
|
+
}
|
|
80
128
|
};
|
|
81
129
|
// We use a fake action event when we click on the action of the chip (hijack the "delete" feature).
|
|
82
130
|
// This is because the href link action is on the `deleteIcon` property already, but the `onDelete` property
|
|
83
131
|
// controls its visibility.
|
|
84
132
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
85
133
|
const fakeActionEvent = ()=>{};
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
134
|
+
return /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Autocomplete, {
|
|
135
|
+
options: options,
|
|
136
|
+
renderInput: (params)=>/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.TextField, {
|
|
137
|
+
...params,
|
|
138
|
+
label: others.label,
|
|
139
|
+
placeholder: ""
|
|
140
|
+
}),
|
|
141
|
+
groupBy: (option)=>option.groupLabel || 'No group',
|
|
142
|
+
getOptionLabel: (option)=>{
|
|
143
|
+
return option.name;
|
|
144
|
+
},
|
|
145
|
+
onChange: (_, v)=>handleChange(v),
|
|
93
146
|
value: optionValue,
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_OpenInNew.default, {
|
|
129
|
-
fontSize: "small"
|
|
130
|
-
})
|
|
131
|
-
}) : undefined
|
|
132
|
-
})
|
|
147
|
+
renderOption: (props, option)=>{
|
|
148
|
+
return /*#__PURE__*/ (0, _react.createElement)("li", {
|
|
149
|
+
...props,
|
|
150
|
+
key: option.value
|
|
151
|
+
}, /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Stack, {
|
|
152
|
+
direction: "row",
|
|
153
|
+
alignItems: "center",
|
|
154
|
+
justifyContent: "space-between",
|
|
155
|
+
width: "100%",
|
|
156
|
+
children: [
|
|
157
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.ListItemText, {
|
|
158
|
+
children: /*#__PURE__*/ (0, _jsxruntime.jsx)(DatasourceName, {
|
|
159
|
+
name: option.name,
|
|
160
|
+
overridden: option.overridden,
|
|
161
|
+
overriding: option.overriding
|
|
162
|
+
})
|
|
163
|
+
}),
|
|
164
|
+
!option.saved && /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.ListItemText, {
|
|
165
|
+
children: "Save the dashboard to enable this datasource"
|
|
166
|
+
}),
|
|
167
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.ListItemText, {
|
|
168
|
+
style: {
|
|
169
|
+
textAlign: 'right'
|
|
170
|
+
},
|
|
171
|
+
children: option.groupLabel && option.groupLabel.length > 0 && /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Chip, {
|
|
172
|
+
disabled: false,
|
|
173
|
+
label: option.groupLabel,
|
|
174
|
+
size: "small",
|
|
175
|
+
onDelete: option.groupEditLink ? fakeActionEvent : undefined,
|
|
176
|
+
deleteIcon: option.groupEditLink ? /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.IconButton, {
|
|
177
|
+
href: option.groupEditLink,
|
|
178
|
+
target: "_blank",
|
|
179
|
+
children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_OpenInNew.default, {
|
|
180
|
+
fontSize: "small"
|
|
133
181
|
})
|
|
134
|
-
|
|
182
|
+
}) : undefined
|
|
135
183
|
})
|
|
136
|
-
}
|
|
137
|
-
|
|
184
|
+
})
|
|
185
|
+
]
|
|
186
|
+
}));
|
|
187
|
+
}
|
|
138
188
|
});
|
|
139
189
|
}
|
|
140
190
|
function DatasourceName(props) {
|
|
@@ -154,22 +204,20 @@ function DatasourceName(props) {
|
|
|
154
204
|
}
|
|
155
205
|
// Delimiter used to stringify/parse option values
|
|
156
206
|
const OPTION_VALUE_DELIMITER = '_____';
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
*/ function selectorToOptionValue(selector) {
|
|
207
|
+
function selectorToOptionValue(selector) {
|
|
208
|
+
if (isVariableDatasource(selector)) {
|
|
209
|
+
return `${DATASOURCE_VARIABLE_VALUE_PREFIX}${selector}`;
|
|
210
|
+
}
|
|
162
211
|
return [
|
|
163
212
|
selector.kind,
|
|
164
213
|
selector.group ?? '',
|
|
165
214
|
selector.name ?? ''
|
|
166
215
|
].join(OPTION_VALUE_DELIMITER);
|
|
167
216
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
*/ function optionValueToSelector(optionValue) {
|
|
217
|
+
function optionValueToSelector(optionValue) {
|
|
218
|
+
if (optionValue.startsWith(DATASOURCE_VARIABLE_VALUE_PREFIX)) {
|
|
219
|
+
return optionValue.split(DATASOURCE_VARIABLE_VALUE_PREFIX)[1];
|
|
220
|
+
}
|
|
173
221
|
const words = optionValue.split(OPTION_VALUE_DELIMITER);
|
|
174
222
|
const kind = words[0];
|
|
175
223
|
const name = words[2];
|
|
@@ -181,3 +229,37 @@ const OPTION_VALUE_DELIMITER = '_____';
|
|
|
181
229
|
name: name === '' ? undefined : name
|
|
182
230
|
};
|
|
183
231
|
}
|
|
232
|
+
function isVariableDatasource(value) {
|
|
233
|
+
return typeof value === 'string' && value.startsWith(VARIABLE_IDENTIFIER);
|
|
234
|
+
}
|
|
235
|
+
const datasourceSelectValueToSelector = (value, variables, datasourceSelectItemGroups)=>{
|
|
236
|
+
if (!isVariableDatasource(value)) {
|
|
237
|
+
return value;
|
|
238
|
+
}
|
|
239
|
+
const [variableName] = (0, _utils.parseVariables)(value);
|
|
240
|
+
const variable = variables[variableName ?? ''];
|
|
241
|
+
// If the variable is not defined or if its value is an array, we cannot determine a selector and return undefined
|
|
242
|
+
if (!variable || Array.isArray(variable.value)) {
|
|
243
|
+
return undefined;
|
|
244
|
+
}
|
|
245
|
+
const associatedDatasource = (datasourceSelectItemGroups || []).flatMap((itemGroup)=>itemGroup.items).find((datasource)=>datasource.name === variable.value);
|
|
246
|
+
// If the variable value is not a datasource, we cannot determine a selector and return undefined
|
|
247
|
+
if (associatedDatasource === undefined) {
|
|
248
|
+
return undefined;
|
|
249
|
+
}
|
|
250
|
+
const datasourceSelector = {
|
|
251
|
+
kind: associatedDatasource.selector.kind,
|
|
252
|
+
name: associatedDatasource.selector.name
|
|
253
|
+
};
|
|
254
|
+
return datasourceSelector;
|
|
255
|
+
};
|
|
256
|
+
const useDatasourceSelectValueToSelector = (value, datasourcePluginKind)=>{
|
|
257
|
+
const { data } = (0, _runtime.useListDatasourceSelectItems)(datasourcePluginKind);
|
|
258
|
+
const variables = (0, _runtime.useVariableValues)();
|
|
259
|
+
if (!isVariableDatasource(value)) {
|
|
260
|
+
return value;
|
|
261
|
+
}
|
|
262
|
+
return datasourceSelectValueToSelector(value, variables, data) ?? {
|
|
263
|
+
kind: datasourcePluginKind
|
|
264
|
+
};
|
|
265
|
+
};
|
|
@@ -78,6 +78,10 @@ function HTTPSettingsEditor(props) {
|
|
|
78
78
|
const { value, onChange, isReadonly, initialSpecDirect, initialSpecProxy } = props;
|
|
79
79
|
const strDirect = 'Direct access';
|
|
80
80
|
const strProxy = 'Proxy';
|
|
81
|
+
// Initialize Proxy mode by default, if neither direct nor proxy mode is selected.
|
|
82
|
+
if (!value.directUrl && !value.proxy) {
|
|
83
|
+
Object.assign(value, initialSpecProxy);
|
|
84
|
+
}
|
|
81
85
|
// utilitary function used for headers when renaming a property
|
|
82
86
|
// -> TODO it would be cleaner to manipulate headers as an intermediary list instead, to avoid doing this.
|
|
83
87
|
const buildNewHeaders = (oldHeaders, oldName, newName)=>{
|
|
@@ -487,8 +491,7 @@ function HTTPSettingsEditor(props) {
|
|
|
487
491
|
// bug in case the tabs get eventually swapped in the future.
|
|
488
492
|
const directModeId = tabs.findIndex((tab)=>tab.label === strDirect);
|
|
489
493
|
const proxyModeId = tabs.findIndex((tab)=>tab.label === strProxy);
|
|
490
|
-
//
|
|
491
|
-
// Otherwise (create datasource), set defaultTab to Direct access.
|
|
494
|
+
// Set defaultTab to the mode that this datasource is currently relying on.
|
|
492
495
|
const defaultTab = value.proxy ? proxyModeId : directModeId;
|
|
493
496
|
// For better user experience, save previous states in mind for both mode.
|
|
494
497
|
// This avoids losing everything when the user changes their mind back.
|
|
@@ -43,7 +43,7 @@ function useDefaultQueryDefinition(queryTypes) {
|
|
|
43
43
|
const { defaultPluginKinds } = (0, _runtime.usePluginRegistry)();
|
|
44
44
|
const defaultQueryKind = defaultPluginKinds?.[defaultQueryType] ?? queryPlugins?.[0]?.spec.name ?? '';
|
|
45
45
|
const { data: defaultQueryPlugin } = (0, _runtime.usePlugin)(defaultQueryType, defaultQueryKind, {
|
|
46
|
-
|
|
46
|
+
useErrorBoundary: true,
|
|
47
47
|
enabled: true
|
|
48
48
|
});
|
|
49
49
|
// This default query definition is used if no query is provided initially or when we add a new query
|
|
@@ -29,14 +29,14 @@ const _MultiQueryEditor = require("../MultiQueryEditor");
|
|
|
29
29
|
function PanelSpecEditor(props) {
|
|
30
30
|
const { control, panelDefinition, onJSONChange, onQueriesChange, onPluginSpecChange } = props;
|
|
31
31
|
const { kind } = panelDefinition.spec.plugin;
|
|
32
|
-
const { data: plugin,
|
|
32
|
+
const { data: plugin, isLoading, error } = (0, _runtime.usePlugin)('Panel', kind);
|
|
33
33
|
if (error) {
|
|
34
34
|
return /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.ErrorAlert, {
|
|
35
35
|
error: error
|
|
36
36
|
});
|
|
37
37
|
}
|
|
38
38
|
// TODO: Proper loading indicator
|
|
39
|
-
if (
|
|
39
|
+
if (isLoading) {
|
|
40
40
|
return null;
|
|
41
41
|
}
|
|
42
42
|
if (plugin === undefined) {
|
|
@@ -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
|
|
154
|
-
control
|
|
155
|
-
name: 'spec.plugin
|
|
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 })
|
|
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:
|
|
218
|
+
kind: kind ?? 'StaticListVariable'
|
|
216
219
|
},
|
|
217
|
-
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
|
]
|
|
@@ -73,11 +73,13 @@ function useListVariablePluginValues(definition) {
|
|
|
73
73
|
};
|
|
74
74
|
const spec = definition.spec.plugin.spec;
|
|
75
75
|
const capturingRegexp = definition.spec.capturingRegexp !== undefined ? new RegExp(definition.spec.capturingRegexp, 'g') : undefined;
|
|
76
|
-
let dependsOnVariables;
|
|
76
|
+
let dependsOnVariables = Object.keys(allVariables); // Default to all variables
|
|
77
77
|
if (variablePlugin?.dependsOn) {
|
|
78
78
|
const dependencies = variablePlugin.dependsOn(spec, variablePluginCtx);
|
|
79
|
-
dependsOnVariables = dependencies.variables;
|
|
79
|
+
dependsOnVariables = dependencies.variables ? dependencies.variables : dependsOnVariables;
|
|
80
80
|
}
|
|
81
|
+
// Exclude self variable to avoid circular dependency
|
|
82
|
+
dependsOnVariables = dependsOnVariables.filter((v)=>v !== definition.spec.name);
|
|
81
83
|
const variables = (0, _runtime.useAllVariableValues)(dependsOnVariables);
|
|
82
84
|
let waitToLoad = false;
|
|
83
85
|
if (dependsOnVariables) {
|
|
@@ -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
|
};
|