@perses-dev/plugin-system 0.41.1 → 0.42.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/DatasourceEditorForm/DatasourceEditorForm.js +26 -55
- package/dist/cjs/components/DatasourceSelect.js +22 -10
- package/dist/cjs/components/PanelSpecEditor/PanelSpecEditor.js +1 -0
- package/dist/cjs/components/PluginEditor/PluginEditor.js +2 -1
- package/dist/cjs/components/ProjectSelect.js +96 -0
- package/dist/cjs/components/TimeSeriesQueryEditor/TimeSeriesQueryEditor.js +14 -12
- package/dist/cjs/components/Variables/VariableEditorForm/VariableEditorForm.js +50 -2
- package/dist/cjs/components/Variables/VariableEditorForm/variable-editor-form-model.js +11 -8
- package/dist/cjs/components/index.js +1 -0
- package/dist/cjs/context/ProjectStoreProvider.js +78 -0
- package/dist/cjs/context/index.js +30 -0
- package/dist/cjs/context/query-params.js +49 -0
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/model/index.js +1 -0
- package/dist/cjs/model/trace-queries.js +16 -0
- package/dist/cjs/runtime/DataQueriesProvider/DataQueriesProvider.js +17 -5
- package/dist/cjs/runtime/DataQueriesProvider/model.js +27 -7
- package/dist/cjs/runtime/TimeRangeProvider/TimeRangeProvider.js +27 -18
- package/dist/cjs/runtime/TimeRangeProvider/TimeRangeProviderWithQueryParams.js +43 -0
- package/dist/cjs/runtime/TimeRangeProvider/index.js +1 -0
- package/dist/cjs/runtime/TimeRangeProvider/query-params.js +7 -39
- package/dist/cjs/runtime/TimeRangeProvider/refresh-interval.js +30 -0
- package/dist/cjs/runtime/datasources.js +3 -2
- package/dist/cjs/runtime/index.js +1 -0
- package/dist/cjs/runtime/trace-queries.js +59 -0
- package/dist/cjs/stories/shared-utils/decorators/WithPluginRegistry.js +2 -1
- package/dist/cjs/stories/shared-utils/decorators/WithPluginSystemDatasourceStore.js +12 -0
- package/dist/cjs/stories/shared-utils/decorators/WithTimeRange.js +2 -2
- package/dist/cjs/test/mock-data.js +26 -3
- package/dist/cjs/validation/role.js +85 -0
- package/dist/cjs/validation/rolebinding.js +55 -0
- package/dist/components/DatasourceEditorForm/DatasourceEditorForm.d.ts +7 -7
- package/dist/components/DatasourceEditorForm/DatasourceEditorForm.d.ts.map +1 -1
- package/dist/components/DatasourceEditorForm/DatasourceEditorForm.js +26 -16
- package/dist/components/DatasourceEditorForm/DatasourceEditorForm.js.map +1 -1
- package/dist/components/DatasourceSelect.d.ts +1 -0
- package/dist/components/DatasourceSelect.d.ts.map +1 -1
- package/dist/components/DatasourceSelect.js +22 -10
- package/dist/components/DatasourceSelect.js.map +1 -1
- package/dist/components/PanelSpecEditor/PanelSpecEditor.d.ts +1 -1
- package/dist/components/PanelSpecEditor/PanelSpecEditor.d.ts.map +1 -1
- package/dist/components/PanelSpecEditor/PanelSpecEditor.js +1 -0
- package/dist/components/PanelSpecEditor/PanelSpecEditor.js.map +1 -1
- package/dist/components/PluginEditor/PluginEditor.d.ts.map +1 -1
- package/dist/components/PluginEditor/PluginEditor.js +2 -1
- package/dist/components/PluginEditor/PluginEditor.js.map +1 -1
- package/dist/components/PluginEditor/plugin-editor-api.d.ts +1 -0
- package/dist/components/PluginEditor/plugin-editor-api.d.ts.map +1 -1
- package/dist/components/PluginEditor/plugin-editor-api.js.map +1 -1
- package/dist/components/PluginSpecEditor/PluginSpecEditor.d.ts +1 -0
- package/dist/components/PluginSpecEditor/PluginSpecEditor.d.ts.map +1 -1
- package/dist/components/PluginSpecEditor/PluginSpecEditor.js.map +1 -1
- package/dist/components/ProjectSelect.d.ts +15 -0
- package/dist/components/ProjectSelect.d.ts.map +1 -0
- package/dist/components/ProjectSelect.js +91 -0
- package/dist/components/ProjectSelect.js.map +1 -0
- package/dist/components/TimeSeriesQueryEditor/TimeSeriesQueryEditor.d.ts.map +1 -1
- package/dist/components/TimeSeriesQueryEditor/TimeSeriesQueryEditor.js +15 -13
- package/dist/components/TimeSeriesQueryEditor/TimeSeriesQueryEditor.js.map +1 -1
- package/dist/components/Variables/VariableEditorForm/VariableEditorForm.d.ts +1 -2
- package/dist/components/Variables/VariableEditorForm/VariableEditorForm.d.ts.map +1 -1
- package/dist/components/Variables/VariableEditorForm/VariableEditorForm.js +50 -2
- package/dist/components/Variables/VariableEditorForm/VariableEditorForm.js.map +1 -1
- package/dist/components/Variables/VariableEditorForm/variable-editor-form-model.d.ts +2 -1
- package/dist/components/Variables/VariableEditorForm/variable-editor-form-model.d.ts.map +1 -1
- package/dist/components/Variables/VariableEditorForm/variable-editor-form-model.js +11 -8
- package/dist/components/Variables/VariableEditorForm/variable-editor-form-model.js.map +1 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +1 -0
- package/dist/components/index.js.map +1 -1
- package/dist/context/ProjectStoreProvider.d.ts +16 -0
- package/dist/context/ProjectStoreProvider.d.ts.map +1 -0
- package/dist/context/ProjectStoreProvider.js +56 -0
- package/dist/context/ProjectStoreProvider.js.map +1 -0
- package/dist/context/index.d.ts +2 -0
- package/dist/context/index.d.ts.map +1 -0
- package/dist/context/index.js +15 -0
- package/dist/context/index.js.map +1 -0
- package/dist/context/query-params.d.ts +5 -0
- package/dist/context/query-params.d.ts.map +1 -0
- package/dist/context/query-params.js +41 -0
- package/dist/context/query-params.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/model/index.d.ts +1 -0
- package/dist/model/index.d.ts.map +1 -1
- package/dist/model/index.js +1 -0
- package/dist/model/index.js.map +1 -1
- package/dist/model/plugin-base.d.ts +1 -0
- package/dist/model/plugin-base.d.ts.map +1 -1
- package/dist/model/plugin-base.js.map +1 -1
- package/dist/model/plugins.d.ts +2 -0
- package/dist/model/plugins.d.ts.map +1 -1
- package/dist/model/plugins.js.map +1 -1
- package/dist/model/trace-queries.d.ts +18 -0
- package/dist/model/trace-queries.d.ts.map +1 -0
- package/dist/model/trace-queries.js +15 -0
- package/dist/model/trace-queries.js.map +1 -0
- package/dist/runtime/DataQueriesProvider/DataQueriesProvider.d.ts.map +1 -1
- package/dist/runtime/DataQueriesProvider/DataQueriesProvider.js +17 -5
- package/dist/runtime/DataQueriesProvider/DataQueriesProvider.js.map +1 -1
- package/dist/runtime/DataQueriesProvider/model.d.ts +1 -1
- package/dist/runtime/DataQueriesProvider/model.d.ts.map +1 -1
- package/dist/runtime/DataQueriesProvider/model.js +27 -7
- package/dist/runtime/DataQueriesProvider/model.js.map +1 -1
- package/dist/runtime/TimeRangeProvider/TimeRangeProvider.d.ts +4 -3
- package/dist/runtime/TimeRangeProvider/TimeRangeProvider.d.ts.map +1 -1
- package/dist/runtime/TimeRangeProvider/TimeRangeProvider.js +28 -19
- package/dist/runtime/TimeRangeProvider/TimeRangeProvider.js.map +1 -1
- package/dist/runtime/TimeRangeProvider/TimeRangeProviderWithQueryParams.d.ts +9 -0
- package/dist/runtime/TimeRangeProvider/TimeRangeProviderWithQueryParams.d.ts.map +1 -0
- package/dist/runtime/TimeRangeProvider/TimeRangeProviderWithQueryParams.js +30 -0
- package/dist/runtime/TimeRangeProvider/TimeRangeProviderWithQueryParams.js.map +1 -0
- package/dist/runtime/TimeRangeProvider/index.d.ts +1 -0
- package/dist/runtime/TimeRangeProvider/index.d.ts.map +1 -1
- package/dist/runtime/TimeRangeProvider/index.js +1 -0
- package/dist/runtime/TimeRangeProvider/index.js.map +1 -1
- package/dist/runtime/TimeRangeProvider/query-params.d.ts +4 -4
- package/dist/runtime/TimeRangeProvider/query-params.d.ts.map +1 -1
- package/dist/runtime/TimeRangeProvider/query-params.js +8 -40
- package/dist/runtime/TimeRangeProvider/query-params.js.map +1 -1
- package/dist/runtime/TimeRangeProvider/refresh-interval.d.ts +7 -0
- package/dist/runtime/TimeRangeProvider/refresh-interval.d.ts.map +1 -0
- package/dist/runtime/TimeRangeProvider/refresh-interval.js +25 -0
- package/dist/runtime/TimeRangeProvider/refresh-interval.js.map +1 -0
- package/dist/runtime/datasources.d.ts +29 -2
- package/dist/runtime/datasources.d.ts.map +1 -1
- package/dist/runtime/datasources.js +3 -2
- package/dist/runtime/datasources.js.map +1 -1
- package/dist/runtime/index.d.ts +1 -0
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +1 -0
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/trace-queries.d.ts +10 -0
- package/dist/runtime/trace-queries.d.ts.map +1 -0
- package/dist/runtime/trace-queries.js +47 -0
- package/dist/runtime/trace-queries.js.map +1 -0
- package/dist/stories/shared-utils/decorators/WithPluginRegistry.d.ts.map +1 -1
- package/dist/stories/shared-utils/decorators/WithPluginRegistry.js +2 -1
- package/dist/stories/shared-utils/decorators/WithPluginRegistry.js.map +1 -1
- package/dist/stories/shared-utils/decorators/WithPluginSystemDatasourceStore.d.ts.map +1 -1
- package/dist/stories/shared-utils/decorators/WithPluginSystemDatasourceStore.js +12 -0
- package/dist/stories/shared-utils/decorators/WithPluginSystemDatasourceStore.js.map +1 -1
- package/dist/stories/shared-utils/decorators/WithTimeRange.d.ts +2 -2
- package/dist/stories/shared-utils/decorators/WithTimeRange.d.ts.map +1 -1
- package/dist/stories/shared-utils/decorators/WithTimeRange.js +2 -2
- package/dist/stories/shared-utils/decorators/WithTimeRange.js.map +1 -1
- package/dist/test/mock-data.d.ts +2 -1
- package/dist/test/mock-data.d.ts.map +1 -1
- package/dist/test/mock-data.js +15 -0
- package/dist/test/mock-data.js.map +1 -1
- package/dist/utils/action.d.ts +1 -1
- package/dist/utils/action.d.ts.map +1 -1
- package/dist/utils/action.js.map +1 -1
- package/dist/validation/role.d.ts +228 -0
- package/dist/validation/role.d.ts.map +1 -0
- package/dist/validation/role.js +66 -0
- package/dist/validation/role.js.map +1 -0
- package/dist/validation/rolebinding.d.ts +137 -0
- package/dist/validation/rolebinding.d.ts.map +1 -0
- package/dist/validation/rolebinding.js +47 -0
- package/dist/validation/rolebinding.js.map +1 -0
- package/package.json +5 -4
|
@@ -23,75 +23,36 @@ Object.defineProperty(exports, "DatasourceEditorForm", {
|
|
|
23
23
|
const _jsxruntime = require("react/jsx-runtime");
|
|
24
24
|
const _useimmer = require("use-immer");
|
|
25
25
|
const _material = require("@mui/material");
|
|
26
|
-
const _react =
|
|
26
|
+
const _react = require("react");
|
|
27
27
|
const _components = require("@perses-dev/components");
|
|
28
28
|
const _reacthookform = require("react-hook-form");
|
|
29
29
|
const _zod = require("@hookform/resolvers/zod");
|
|
30
30
|
const _PluginEditor = require("../PluginEditor");
|
|
31
31
|
const _utils = require("../../utils");
|
|
32
32
|
const _validation = require("../../validation");
|
|
33
|
-
function _getRequireWildcardCache(nodeInterop) {
|
|
34
|
-
if (typeof WeakMap !== "function") return null;
|
|
35
|
-
var cacheBabelInterop = new WeakMap();
|
|
36
|
-
var cacheNodeInterop = new WeakMap();
|
|
37
|
-
return (_getRequireWildcardCache = function(nodeInterop) {
|
|
38
|
-
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|
39
|
-
})(nodeInterop);
|
|
40
|
-
}
|
|
41
|
-
function _interop_require_wildcard(obj, nodeInterop) {
|
|
42
|
-
if (!nodeInterop && obj && obj.__esModule) {
|
|
43
|
-
return obj;
|
|
44
|
-
}
|
|
45
|
-
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
|
46
|
-
return {
|
|
47
|
-
default: obj
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
var cache = _getRequireWildcardCache(nodeInterop);
|
|
51
|
-
if (cache && cache.has(obj)) {
|
|
52
|
-
return cache.get(obj);
|
|
53
|
-
}
|
|
54
|
-
var newObj = {};
|
|
55
|
-
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|
56
|
-
for(var key in obj){
|
|
57
|
-
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
58
|
-
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
|
59
|
-
if (desc && (desc.get || desc.set)) {
|
|
60
|
-
Object.defineProperty(newObj, key, desc);
|
|
61
|
-
} else {
|
|
62
|
-
newObj[key] = obj[key];
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
newObj.default = obj;
|
|
67
|
-
if (cache) {
|
|
68
|
-
cache.set(obj, newObj);
|
|
69
|
-
}
|
|
70
|
-
return newObj;
|
|
71
|
-
}
|
|
72
33
|
/**
|
|
73
34
|
* This preprocessing ensures that we always have a defined object for the `display` property
|
|
74
35
|
* @param datasource
|
|
75
|
-
*/ function getInitialState(
|
|
76
|
-
var
|
|
77
|
-
var
|
|
36
|
+
*/ function getInitialState(name, spec) {
|
|
37
|
+
var _spec_display, _spec_display1;
|
|
38
|
+
var _spec_display_name, _spec_display_description;
|
|
78
39
|
const patchedDisplay = {
|
|
79
|
-
name: (
|
|
80
|
-
description: (
|
|
40
|
+
name: (_spec_display_name = (_spec_display = spec.display) === null || _spec_display === void 0 ? void 0 : _spec_display.name) !== null && _spec_display_name !== void 0 ? _spec_display_name : '',
|
|
41
|
+
description: (_spec_display_description = (_spec_display1 = spec.display) === null || _spec_display1 === void 0 ? void 0 : _spec_display1.description) !== null && _spec_display_description !== void 0 ? _spec_display_description : ''
|
|
81
42
|
};
|
|
82
43
|
return {
|
|
83
|
-
|
|
44
|
+
name: name,
|
|
84
45
|
spec: {
|
|
85
|
-
...
|
|
46
|
+
...spec,
|
|
86
47
|
display: patchedDisplay
|
|
87
48
|
}
|
|
88
49
|
};
|
|
89
50
|
}
|
|
90
51
|
function DatasourceEditorForm(props) {
|
|
91
52
|
var _state_spec_display, _state_spec_display1;
|
|
92
|
-
const {
|
|
93
|
-
const
|
|
94
|
-
const [state, setState] = (0, _useimmer.useImmer)(
|
|
53
|
+
const { initialName , initialSpec , initialAction , isDraft , isReadonly , onSave , onClose , onDelete } = props;
|
|
54
|
+
const initialState = getInitialState(initialName, initialSpec);
|
|
55
|
+
const [state, setState] = (0, _useimmer.useImmer)(initialState);
|
|
95
56
|
const [isDiscardDialogOpened, setDiscardDialogOpened] = (0, _react.useState)(false);
|
|
96
57
|
const [action, setAction] = (0, _react.useState)(initialAction);
|
|
97
58
|
const titleAction = (0, _utils.getTitleAction)(action, isDraft);
|
|
@@ -100,28 +61,38 @@ function DatasourceEditorForm(props) {
|
|
|
100
61
|
resolver: (0, _zod.zodResolver)(_validation.datasourceEditValidationSchema),
|
|
101
62
|
mode: 'onBlur',
|
|
102
63
|
defaultValues: {
|
|
103
|
-
name: state.
|
|
64
|
+
name: state.name,
|
|
104
65
|
title: (_state_spec_display = state.spec.display) === null || _state_spec_display === void 0 ? void 0 : _state_spec_display.name,
|
|
105
66
|
description: (_state_spec_display1 = state.spec.display) === null || _state_spec_display1 === void 0 ? void 0 : _state_spec_display1.description,
|
|
106
67
|
default: state.spec.default
|
|
107
68
|
}
|
|
108
69
|
});
|
|
109
70
|
const processForm = ()=>{
|
|
110
|
-
|
|
71
|
+
var _state_spec_display;
|
|
72
|
+
// reset display name to undefined when empty, because we don't want an empty string as value
|
|
73
|
+
const name = (_state_spec_display = state.spec.display) === null || _state_spec_display === void 0 ? void 0 : _state_spec_display.name;
|
|
74
|
+
const finalDisplay = {
|
|
75
|
+
...state.spec.display,
|
|
76
|
+
name: name ? name : undefined
|
|
77
|
+
};
|
|
78
|
+
onSave(state.name, {
|
|
79
|
+
...state.spec,
|
|
80
|
+
display: finalDisplay
|
|
81
|
+
});
|
|
111
82
|
};
|
|
112
83
|
// When user click on cancel, several possibilities:
|
|
113
84
|
// - create action: ask for discard approval
|
|
114
85
|
// - update action: ask for discard approval if changed
|
|
115
86
|
// - read action: don´t ask for discard approval
|
|
116
87
|
const handleCancel = (0, _react.useCallback)(()=>{
|
|
117
|
-
if (JSON.stringify(
|
|
88
|
+
if (JSON.stringify(initialState) !== JSON.stringify(state)) {
|
|
118
89
|
setDiscardDialogOpened(true);
|
|
119
90
|
} else {
|
|
120
91
|
onClose();
|
|
121
92
|
}
|
|
122
93
|
}, [
|
|
123
94
|
state,
|
|
124
|
-
|
|
95
|
+
initialState,
|
|
125
96
|
setDiscardDialogOpened,
|
|
126
97
|
onClose
|
|
127
98
|
]);
|
|
@@ -237,7 +208,7 @@ function DatasourceEditorForm(props) {
|
|
|
237
208
|
onChange: (event)=>{
|
|
238
209
|
field.onChange(event);
|
|
239
210
|
setState((draft)=>{
|
|
240
|
-
draft.
|
|
211
|
+
draft.name = event.target.value;
|
|
241
212
|
});
|
|
242
213
|
}
|
|
243
214
|
});
|
|
@@ -39,8 +39,8 @@ function _interop_require_default(obj) {
|
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
41
|
function DatasourceSelect(props) {
|
|
42
|
-
const { datasourcePluginKind , value , onChange , ...others } = props;
|
|
43
|
-
const { data , isLoading } = (0, _runtime.useListDatasourceSelectItems)(datasourcePluginKind);
|
|
42
|
+
const { datasourcePluginKind , value , project , onChange , ...others } = props;
|
|
43
|
+
const { data , isLoading } = (0, _runtime.useListDatasourceSelectItems)(datasourcePluginKind, project);
|
|
44
44
|
// Rebuild the group of the value if not provided
|
|
45
45
|
const defaultValue = (0, _react.useMemo)(()=>{
|
|
46
46
|
var _flatMap_find;
|
|
@@ -57,6 +57,7 @@ function DatasourceSelect(props) {
|
|
|
57
57
|
]);
|
|
58
58
|
// Convert the datasource list into menu items with name/group?/value strings that the Select input can work with
|
|
59
59
|
const menuItems = (0, _react.useMemo)(()=>{
|
|
60
|
+
var _item_saved;
|
|
60
61
|
return (data !== null && data !== void 0 ? data : []).map((itemGroup)=>({
|
|
61
62
|
group: itemGroup.group,
|
|
62
63
|
editLink: itemGroup.editLink,
|
|
@@ -64,6 +65,7 @@ function DatasourceSelect(props) {
|
|
|
64
65
|
name: item.name,
|
|
65
66
|
overriding: item.overriding,
|
|
66
67
|
overridden: item.overridden,
|
|
68
|
+
saved: (_item_saved = item.saved) !== null && _item_saved !== void 0 ? _item_saved : true,
|
|
67
69
|
group: item.selector.group,
|
|
68
70
|
value: selectorToOptionValue(item.selector)
|
|
69
71
|
}))
|
|
@@ -96,7 +98,7 @@ function DatasourceSelect(props) {
|
|
|
96
98
|
/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Divider, {}, `${menuItemGroup.group}-divider`),
|
|
97
99
|
...menuItemGroup.items.map((menuItem)=>/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.MenuItem, {
|
|
98
100
|
value: menuItem.value,
|
|
99
|
-
disabled: menuItem.overridden,
|
|
101
|
+
disabled: menuItem.overridden || !menuItem.saved,
|
|
100
102
|
children: /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Stack, {
|
|
101
103
|
direction: "row",
|
|
102
104
|
alignItems: "center",
|
|
@@ -110,6 +112,9 @@ function DatasourceSelect(props) {
|
|
|
110
112
|
overriding: menuItem.overriding
|
|
111
113
|
})
|
|
112
114
|
}),
|
|
115
|
+
!menuItem.saved && /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.ListItemText, {
|
|
116
|
+
children: "Save the dashboard to enable this datasource"
|
|
117
|
+
}),
|
|
113
118
|
/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.ListItemText, {
|
|
114
119
|
style: {
|
|
115
120
|
textAlign: 'right'
|
|
@@ -151,8 +156,11 @@ function DatasourceName(props) {
|
|
|
151
156
|
}
|
|
152
157
|
// Delimiter used to stringify/parse option values
|
|
153
158
|
const OPTION_VALUE_DELIMITER = '_____';
|
|
154
|
-
|
|
155
|
-
|
|
159
|
+
/**
|
|
160
|
+
* Given a DatasourceSelectItemSelector,
|
|
161
|
+
* returns a string value like `{kind}_____{group}_____{name}` that can be used as a Select input value.
|
|
162
|
+
* @param selector
|
|
163
|
+
*/ function selectorToOptionValue(selector) {
|
|
156
164
|
var _selector_group, _selector_name;
|
|
157
165
|
return [
|
|
158
166
|
selector.kind,
|
|
@@ -160,15 +168,19 @@ function selectorToOptionValue(selector) {
|
|
|
160
168
|
(_selector_name = selector.name) !== null && _selector_name !== void 0 ? _selector_name : ''
|
|
161
169
|
].join(OPTION_VALUE_DELIMITER);
|
|
162
170
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
171
|
+
/**
|
|
172
|
+
* Given an option value name like `{kind}_____{group}_____{name}`,
|
|
173
|
+
* returns a DatasourceSelector to be used by the query data model.
|
|
174
|
+
* @param optionValue
|
|
175
|
+
*/ function optionValueToSelector(optionValue) {
|
|
176
|
+
const words = optionValue.split(OPTION_VALUE_DELIMITER);
|
|
177
|
+
const kind = words[0];
|
|
178
|
+
const name = words[2];
|
|
179
|
+
if (kind === undefined || name === undefined) {
|
|
167
180
|
throw new Error('Invalid optionValue string');
|
|
168
181
|
}
|
|
169
182
|
return {
|
|
170
183
|
kind,
|
|
171
|
-
group: group === '' ? undefined : group,
|
|
172
184
|
name: name === '' ? undefined : name
|
|
173
185
|
};
|
|
174
186
|
}
|
|
@@ -27,7 +27,7 @@ const _PluginSpecEditor = require("../PluginSpecEditor");
|
|
|
27
27
|
const _plugineditorapi = require("./plugin-editor-api");
|
|
28
28
|
function PluginEditor(props) {
|
|
29
29
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
30
|
-
const { value , pluginType , pluginKindLabel , onChange: _ , isReadonly , ...others } = props;
|
|
30
|
+
const { value , pluginType , pluginKindLabel , onChange: _ , isReadonly , isExplore , ...others } = props;
|
|
31
31
|
const { pendingKind , isLoading , error , onKindChange , onSpecChange } = (0, _plugineditorapi.usePluginEditor)(props);
|
|
32
32
|
return /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Box, {
|
|
33
33
|
...others,
|
|
@@ -51,6 +51,7 @@ function PluginEditor(props) {
|
|
|
51
51
|
onChange: onKindChange
|
|
52
52
|
}),
|
|
53
53
|
/*#__PURE__*/ (0, _jsxruntime.jsx)(_PluginSpecEditor.PluginSpecEditor, {
|
|
54
|
+
isExplore: isExplore,
|
|
54
55
|
pluginType: pluginType,
|
|
55
56
|
pluginKind: value.kind,
|
|
56
57
|
value: value.spec,
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// Copyright 2023 The Perses Authors
|
|
2
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
+
// you may not use this file except in compliance with the License.
|
|
4
|
+
// You may obtain a copy of the License at
|
|
5
|
+
//
|
|
6
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
//
|
|
8
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
+
// See the License for the specific language governing permissions and
|
|
12
|
+
// limitations under the License.
|
|
13
|
+
"use strict";
|
|
14
|
+
Object.defineProperty(exports, "__esModule", {
|
|
15
|
+
value: true
|
|
16
|
+
});
|
|
17
|
+
Object.defineProperty(exports, "ProjectSelect", {
|
|
18
|
+
enumerable: true,
|
|
19
|
+
get: function() {
|
|
20
|
+
return ProjectSelect;
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
const _jsxruntime = require("react/jsx-runtime");
|
|
24
|
+
const _material = require("@mui/material");
|
|
25
|
+
const _context = require("../context");
|
|
26
|
+
function ProjectSelect(props) {
|
|
27
|
+
const { onChange , value , ...others } = props;
|
|
28
|
+
const { data , isLoading } = (0, _context.useProjectList)();
|
|
29
|
+
// While loading available values, just use an empty string so MUI select doesn't warn about values out of range
|
|
30
|
+
const optionValue = isLoading ? '' : projectToOptionValue(value);
|
|
31
|
+
// When the user makes a selection, convert the string option value back to a DatasourceSelector
|
|
32
|
+
const handleChange = (e)=>{
|
|
33
|
+
const next = optionValueToSelector(e.target.value);
|
|
34
|
+
onChange(next);
|
|
35
|
+
};
|
|
36
|
+
// TODO:
|
|
37
|
+
// - Does this need a loading indicator of some kind?
|
|
38
|
+
// - The group's edit link is not clickable once selected.
|
|
39
|
+
// - The group's edit link is disabled if datasource is overridden.
|
|
40
|
+
// Ref: https://github.com/mui/material-ui/issues/36572
|
|
41
|
+
return /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Select, {
|
|
42
|
+
...others,
|
|
43
|
+
value: optionValue,
|
|
44
|
+
onChange: handleChange,
|
|
45
|
+
children: [
|
|
46
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.MenuItem, {
|
|
47
|
+
value: 'none',
|
|
48
|
+
children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Stack, {
|
|
49
|
+
direction: "row",
|
|
50
|
+
alignItems: "center",
|
|
51
|
+
justifyContent: "space-between",
|
|
52
|
+
width: "100%",
|
|
53
|
+
height: 32,
|
|
54
|
+
children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.ListItemText, {
|
|
55
|
+
children: "None"
|
|
56
|
+
})
|
|
57
|
+
})
|
|
58
|
+
}),
|
|
59
|
+
data === null || data === void 0 ? void 0 : data.map((project)=>[
|
|
60
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.MenuItem, {
|
|
61
|
+
value: project.metadata.name,
|
|
62
|
+
children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Stack, {
|
|
63
|
+
direction: "row",
|
|
64
|
+
alignItems: "center",
|
|
65
|
+
justifyContent: "space-between",
|
|
66
|
+
width: "100%",
|
|
67
|
+
height: 32,
|
|
68
|
+
children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.ListItemText, {
|
|
69
|
+
children: project.metadata.name
|
|
70
|
+
})
|
|
71
|
+
})
|
|
72
|
+
}, project.metadata.name)
|
|
73
|
+
])
|
|
74
|
+
]
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Given a ProjectSelectItemSelector,
|
|
79
|
+
* returns a string value that can be used as a Select input value.
|
|
80
|
+
* @param selector
|
|
81
|
+
*/ function projectToOptionValue(project) {
|
|
82
|
+
var _project_metadata_name;
|
|
83
|
+
return (_project_metadata_name = project.metadata.name) !== null && _project_metadata_name !== void 0 ? _project_metadata_name : 'none';
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Given an option value name,
|
|
87
|
+
* returns a ProjectResource to be used by the query data model.
|
|
88
|
+
* @param optionValue
|
|
89
|
+
*/ function optionValueToSelector(optionValue) {
|
|
90
|
+
return {
|
|
91
|
+
kind: 'Project',
|
|
92
|
+
metadata: {
|
|
93
|
+
name: optionValue
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
}
|
|
@@ -119,26 +119,28 @@ function TimeSeriesQueryEditor({ queries =[] , onChange }) {
|
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
];
|
|
122
|
-
return /*#__PURE__*/ (0, _jsxruntime.jsxs)(
|
|
123
|
-
spacing: 1,
|
|
122
|
+
return /*#__PURE__*/ (0, _jsxruntime.jsxs)(_jsxruntime.Fragment, {
|
|
124
123
|
children: [
|
|
124
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Stack, {
|
|
125
|
+
spacing: 1,
|
|
126
|
+
children: queryDefinitions.map((query, i)=>/*#__PURE__*/ (0, _jsxruntime.jsx)(_TimeSeriesQueryInput.TimeSeriesQueryInput, {
|
|
127
|
+
index: i,
|
|
128
|
+
query: query,
|
|
129
|
+
isCollapsed: !!queriesCollapsed[i],
|
|
130
|
+
onChange: handleQueryChange,
|
|
131
|
+
onDelete: hasMoreThanOneQuery ? handleQueryDelete : undefined,
|
|
132
|
+
onCollapseExpand: handleQueryCollapseExpand
|
|
133
|
+
}, i))
|
|
134
|
+
}),
|
|
125
135
|
/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Button, {
|
|
126
136
|
variant: "contained",
|
|
127
137
|
startIcon: /*#__PURE__*/ (0, _jsxruntime.jsx)(_Plus.default, {}),
|
|
128
138
|
sx: {
|
|
129
|
-
|
|
139
|
+
marginTop: 1
|
|
130
140
|
},
|
|
131
141
|
onClick: handleQueryAdd,
|
|
132
142
|
children: "Add Query"
|
|
133
|
-
})
|
|
134
|
-
queryDefinitions.map((query, i)=>/*#__PURE__*/ (0, _jsxruntime.jsx)(_TimeSeriesQueryInput.TimeSeriesQueryInput, {
|
|
135
|
-
index: i,
|
|
136
|
-
query: query,
|
|
137
|
-
isCollapsed: !!queriesCollapsed[i],
|
|
138
|
-
onChange: handleQueryChange,
|
|
139
|
-
onDelete: hasMoreThanOneQuery ? handleQueryDelete : undefined,
|
|
140
|
-
onCollapseExpand: handleQueryCollapseExpand
|
|
141
|
-
}, i))
|
|
143
|
+
})
|
|
142
144
|
]
|
|
143
145
|
});
|
|
144
146
|
}
|
|
@@ -122,7 +122,7 @@ function VariableEditorForm(props) {
|
|
|
122
122
|
setDiscardDialogOpened,
|
|
123
123
|
onClose
|
|
124
124
|
]);
|
|
125
|
-
var _state_textVariableFields_constant;
|
|
125
|
+
var _state_textVariableFields_constant, _state_listVariableFields_capturingRegexp, _state_listVariableFields_sort;
|
|
126
126
|
return /*#__PURE__*/ (0, _jsxruntime.jsxs)(_reacthookform.FormProvider, {
|
|
127
127
|
...form,
|
|
128
128
|
children: [
|
|
@@ -434,7 +434,7 @@ function VariableEditorForm(props) {
|
|
|
434
434
|
/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Stack, {
|
|
435
435
|
children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.TextField, {
|
|
436
436
|
label: "Capturing Regexp Filter",
|
|
437
|
-
value: state.listVariableFields.capturingRegexp
|
|
437
|
+
value: (_state_listVariableFields_capturingRegexp = state.listVariableFields.capturingRegexp) !== null && _state_listVariableFields_capturingRegexp !== void 0 ? _state_listVariableFields_capturingRegexp : '',
|
|
438
438
|
InputLabelProps: {
|
|
439
439
|
shrink: action === 'read' ? true : undefined
|
|
440
440
|
},
|
|
@@ -453,6 +453,54 @@ function VariableEditorForm(props) {
|
|
|
453
453
|
},
|
|
454
454
|
helperText: "Optional, if you want to filter on captured result."
|
|
455
455
|
})
|
|
456
|
+
}),
|
|
457
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Stack, {
|
|
458
|
+
children: /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.TextField, {
|
|
459
|
+
select: true,
|
|
460
|
+
label: "Sort",
|
|
461
|
+
value: (_state_listVariableFields_sort = state.listVariableFields.sort) !== null && _state_listVariableFields_sort !== void 0 ? _state_listVariableFields_sort : '',
|
|
462
|
+
InputLabelProps: {
|
|
463
|
+
shrink: action === 'read' ? true : undefined
|
|
464
|
+
},
|
|
465
|
+
InputProps: {
|
|
466
|
+
readOnly: isReadonly
|
|
467
|
+
},
|
|
468
|
+
onChange: (e)=>{
|
|
469
|
+
setState((draft)=>{
|
|
470
|
+
draft.listVariableFields.sort = e.target.value;
|
|
471
|
+
});
|
|
472
|
+
},
|
|
473
|
+
children: [
|
|
474
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.MenuItem, {
|
|
475
|
+
value: "none",
|
|
476
|
+
children: "None"
|
|
477
|
+
}),
|
|
478
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.MenuItem, {
|
|
479
|
+
value: "alphabetical-asc",
|
|
480
|
+
children: "Alphabetical, asc"
|
|
481
|
+
}),
|
|
482
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.MenuItem, {
|
|
483
|
+
value: "alphabetical-desc",
|
|
484
|
+
children: "Alphabetical, desc"
|
|
485
|
+
}),
|
|
486
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.MenuItem, {
|
|
487
|
+
value: "numerical-asc",
|
|
488
|
+
children: "Numerical, asc"
|
|
489
|
+
}),
|
|
490
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.MenuItem, {
|
|
491
|
+
value: "numerical-desc",
|
|
492
|
+
children: "Numerical, desc"
|
|
493
|
+
}),
|
|
494
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.MenuItem, {
|
|
495
|
+
value: "alphabetical-ci-asc",
|
|
496
|
+
children: "Alphabetical, case-insensitive, asc"
|
|
497
|
+
}),
|
|
498
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.MenuItem, {
|
|
499
|
+
value: "alphabetical-ci-desc",
|
|
500
|
+
children: "Alphabetical, case-insensitive, desc"
|
|
501
|
+
})
|
|
502
|
+
]
|
|
503
|
+
})
|
|
456
504
|
})
|
|
457
505
|
]
|
|
458
506
|
}),
|
|
@@ -38,21 +38,23 @@ function getInitialState(initialVariableDefinition) {
|
|
|
38
38
|
const listVariableFields = {
|
|
39
39
|
allowMultiple: false,
|
|
40
40
|
allowAll: false,
|
|
41
|
+
customAllValue: undefined,
|
|
41
42
|
capturingRegexp: undefined,
|
|
43
|
+
sort: undefined,
|
|
42
44
|
plugin: {
|
|
43
45
|
kind: '',
|
|
44
46
|
spec: {}
|
|
45
|
-
}
|
|
46
|
-
customAllValue: undefined
|
|
47
|
+
}
|
|
47
48
|
};
|
|
48
49
|
if (initialVariableDefinition.kind === 'ListVariable') {
|
|
50
|
+
var _initialVariableDefinition_spec_allowMultiple;
|
|
51
|
+
listVariableFields.allowMultiple = (_initialVariableDefinition_spec_allowMultiple = initialVariableDefinition.spec.allowMultiple) !== null && _initialVariableDefinition_spec_allowMultiple !== void 0 ? _initialVariableDefinition_spec_allowMultiple : false;
|
|
49
52
|
var _initialVariableDefinition_spec_allowAllValue;
|
|
50
|
-
listVariableFields.
|
|
51
|
-
|
|
52
|
-
listVariableFields.allowAll = (_initialVariableDefinition_spec_allowAllValue1 = initialVariableDefinition.spec.allowAllValue) !== null && _initialVariableDefinition_spec_allowAllValue1 !== void 0 ? _initialVariableDefinition_spec_allowAllValue1 : false;
|
|
53
|
+
listVariableFields.allowAll = (_initialVariableDefinition_spec_allowAllValue = initialVariableDefinition.spec.allowAllValue) !== null && _initialVariableDefinition_spec_allowAllValue !== void 0 ? _initialVariableDefinition_spec_allowAllValue : false;
|
|
54
|
+
listVariableFields.customAllValue = initialVariableDefinition.spec.customAllValue;
|
|
53
55
|
listVariableFields.capturingRegexp = initialVariableDefinition.spec.capturingRegexp;
|
|
56
|
+
listVariableFields.sort = initialVariableDefinition.spec.sort;
|
|
54
57
|
listVariableFields.plugin = initialVariableDefinition.spec.plugin;
|
|
55
|
-
listVariableFields.customAllValue = initialVariableDefinition.spec.customAllValue;
|
|
56
58
|
}
|
|
57
59
|
var _initialVariableDefinition_spec_display_name, _initialVariableDefinition_spec_display_description;
|
|
58
60
|
return {
|
|
@@ -88,9 +90,10 @@ function getVariableDefinitionFromState(state) {
|
|
|
88
90
|
display,
|
|
89
91
|
allowMultiple: state.listVariableFields.allowMultiple,
|
|
90
92
|
allowAllValue: state.listVariableFields.allowAll,
|
|
93
|
+
customAllValue: state.listVariableFields.customAllValue,
|
|
91
94
|
capturingRegexp: state.listVariableFields.capturingRegexp,
|
|
92
|
-
|
|
93
|
-
|
|
95
|
+
sort: state.listVariableFields.sort,
|
|
96
|
+
plugin: state.listVariableFields.plugin
|
|
94
97
|
}
|
|
95
98
|
};
|
|
96
99
|
}
|
|
@@ -27,6 +27,7 @@ _export_star(require("./PluginRegistry"), exports);
|
|
|
27
27
|
_export_star(require("./PluginSpecEditor"), exports);
|
|
28
28
|
_export_star(require("./TimeSeriesQueryEditor"), exports);
|
|
29
29
|
_export_star(require("./Variables"), exports);
|
|
30
|
+
_export_star(require("./ProjectSelect"), exports);
|
|
30
31
|
function _export_star(from, to) {
|
|
31
32
|
Object.keys(from).forEach(function(k) {
|
|
32
33
|
if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// Copyright 2023 The Perses Authors
|
|
2
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
+
// you may not use this file except in compliance with the License.
|
|
4
|
+
// You may obtain a copy of the License at
|
|
5
|
+
//
|
|
6
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
//
|
|
8
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
+
// See the License for the specific language governing permissions and
|
|
12
|
+
// limitations under the License.
|
|
13
|
+
"use strict";
|
|
14
|
+
Object.defineProperty(exports, "__esModule", {
|
|
15
|
+
value: true
|
|
16
|
+
});
|
|
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
|
+
ProjectStoreContext: function() {
|
|
25
|
+
return ProjectStoreContext;
|
|
26
|
+
},
|
|
27
|
+
useProjectList: function() {
|
|
28
|
+
return useProjectList;
|
|
29
|
+
},
|
|
30
|
+
useProjectStore: function() {
|
|
31
|
+
return useProjectStore;
|
|
32
|
+
},
|
|
33
|
+
ProjectStoreProvider: function() {
|
|
34
|
+
return ProjectStoreProvider;
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
const _jsxruntime = require("react/jsx-runtime");
|
|
38
|
+
const _reactquery = require("@tanstack/react-query");
|
|
39
|
+
const _react = require("react");
|
|
40
|
+
const _core = require("@perses-dev/core");
|
|
41
|
+
const _queryparams = require("./query-params");
|
|
42
|
+
const ProjectStoreContext = /*#__PURE__*/ (0, _react.createContext)(undefined);
|
|
43
|
+
function useProjectList() {
|
|
44
|
+
return (0, _reactquery.useQuery)([
|
|
45
|
+
'projects'
|
|
46
|
+
], ()=>{
|
|
47
|
+
return (0, _core.fetchJson)('/api/v1/projects');
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
function useProjectStore() {
|
|
51
|
+
const ctx = (0, _react.useContext)(ProjectStoreContext);
|
|
52
|
+
if (ctx === undefined) {
|
|
53
|
+
throw new Error('No ProjectStoreContext found. Did you forget a Provider?');
|
|
54
|
+
}
|
|
55
|
+
return ctx;
|
|
56
|
+
}
|
|
57
|
+
function ProjectStoreProvider(props) {
|
|
58
|
+
const { children , enabledURLParams } = props;
|
|
59
|
+
const { project , setProject } = (0, _queryparams.useSetProjectParams)(enabledURLParams);
|
|
60
|
+
const contextValue = (0, _react.useMemo)(()=>({
|
|
61
|
+
project: {
|
|
62
|
+
kind: 'Project',
|
|
63
|
+
metadata: {
|
|
64
|
+
name: project
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
setProject: (project)=>{
|
|
68
|
+
setProject(project.metadata.name);
|
|
69
|
+
}
|
|
70
|
+
}), [
|
|
71
|
+
project,
|
|
72
|
+
setProject
|
|
73
|
+
]);
|
|
74
|
+
return /*#__PURE__*/ (0, _jsxruntime.jsx)(ProjectStoreContext.Provider, {
|
|
75
|
+
value: contextValue,
|
|
76
|
+
children: children
|
|
77
|
+
});
|
|
78
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Copyright 2023 The Perses Authors
|
|
2
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
+
// you may not use this file except in compliance with the License.
|
|
4
|
+
// You may obtain a copy of the License at
|
|
5
|
+
//
|
|
6
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
//
|
|
8
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
+
// See the License for the specific language governing permissions and
|
|
12
|
+
// limitations under the License.
|
|
13
|
+
"use strict";
|
|
14
|
+
Object.defineProperty(exports, "__esModule", {
|
|
15
|
+
value: true
|
|
16
|
+
});
|
|
17
|
+
_export_star(require("./ProjectStoreProvider"), exports);
|
|
18
|
+
function _export_star(from, to) {
|
|
19
|
+
Object.keys(from).forEach(function(k) {
|
|
20
|
+
if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
|
|
21
|
+
Object.defineProperty(to, k, {
|
|
22
|
+
enumerable: true,
|
|
23
|
+
get: function() {
|
|
24
|
+
return from[k];
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
return from;
|
|
30
|
+
}
|