@perses-dev/plugin-system 0.51.1 → 0.52.0-beta.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.
Files changed (52) hide show
  1. package/dist/cjs/components/PluginEditor/PluginEditor.js +41 -15
  2. package/dist/cjs/model/index.js +1 -0
  3. package/dist/cjs/model/profile-queries.js +16 -0
  4. package/dist/cjs/runtime/DataQueriesProvider/DataQueriesProvider.js +10 -2
  5. package/dist/cjs/runtime/DataQueriesProvider/model.js +17 -4
  6. package/dist/cjs/runtime/RouterProvider.js +113 -0
  7. package/dist/cjs/runtime/index.js +2 -0
  8. package/dist/cjs/runtime/profile-queries.js +65 -0
  9. package/dist/cjs/test/mock-data.js +23 -0
  10. package/dist/components/PluginEditor/PluginEditor.d.ts.map +1 -1
  11. package/dist/components/PluginEditor/PluginEditor.js +37 -16
  12. package/dist/components/PluginEditor/PluginEditor.js.map +1 -1
  13. package/dist/components/PluginKindSelect/PluginKindSelect.d.ts +1 -1
  14. package/dist/components/PluginKindSelect/PluginKindSelect.js +1 -1
  15. package/dist/components/PluginKindSelect/PluginKindSelect.js.map +1 -1
  16. package/dist/model/index.d.ts +1 -0
  17. package/dist/model/index.d.ts.map +1 -1
  18. package/dist/model/index.js +1 -0
  19. package/dist/model/index.js.map +1 -1
  20. package/dist/model/panels.d.ts +8 -0
  21. package/dist/model/panels.d.ts.map +1 -1
  22. package/dist/model/panels.js.map +1 -1
  23. package/dist/model/plugins.d.ts +2 -0
  24. package/dist/model/plugins.d.ts.map +1 -1
  25. package/dist/model/plugins.js.map +1 -1
  26. package/dist/model/profile-queries.d.ts +19 -0
  27. package/dist/model/profile-queries.d.ts.map +1 -0
  28. package/dist/model/profile-queries.js +15 -0
  29. package/dist/model/profile-queries.js.map +1 -0
  30. package/dist/runtime/DataQueriesProvider/DataQueriesProvider.d.ts.map +1 -1
  31. package/dist/runtime/DataQueriesProvider/DataQueriesProvider.js +10 -2
  32. package/dist/runtime/DataQueriesProvider/DataQueriesProvider.js.map +1 -1
  33. package/dist/runtime/DataQueriesProvider/model.d.ts.map +1 -1
  34. package/dist/runtime/DataQueriesProvider/model.js +17 -4
  35. package/dist/runtime/DataQueriesProvider/model.js.map +1 -1
  36. package/dist/runtime/RouterProvider.d.ts +32 -0
  37. package/dist/runtime/RouterProvider.d.ts.map +1 -0
  38. package/dist/runtime/RouterProvider.js +58 -0
  39. package/dist/runtime/RouterProvider.js.map +1 -0
  40. package/dist/runtime/index.d.ts +2 -0
  41. package/dist/runtime/index.d.ts.map +1 -1
  42. package/dist/runtime/index.js +2 -0
  43. package/dist/runtime/index.js.map +1 -1
  44. package/dist/runtime/profile-queries.d.ts +10 -0
  45. package/dist/runtime/profile-queries.d.ts.map +1 -0
  46. package/dist/runtime/profile-queries.js +52 -0
  47. package/dist/runtime/profile-queries.js.map +1 -0
  48. package/dist/test/mock-data.d.ts +2 -1
  49. package/dist/test/mock-data.d.ts.map +1 -1
  50. package/dist/test/mock-data.js +20 -0
  51. package/dist/test/mock-data.js.map +1 -1
  52. package/package.json +3 -3
@@ -22,10 +22,16 @@ Object.defineProperty(exports, "PluginEditor", {
22
22
  });
23
23
  const _jsxruntime = require("react/jsx-runtime");
24
24
  const _material = require("@mui/material");
25
+ const _Reload = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/Reload"));
25
26
  const _components = require("@perses-dev/components");
26
27
  const _PluginKindSelect = require("../PluginKindSelect");
27
28
  const _PluginSpecEditor = require("../PluginSpecEditor");
28
29
  const _plugineditorapi = require("./plugin-editor-api");
30
+ function _interop_require_default(obj) {
31
+ return obj && obj.__esModule ? obj : {
32
+ default: obj
33
+ };
34
+ }
29
35
  function PluginEditor(props) {
30
36
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
31
37
  const { value, pluginTypes, pluginKindLabel, onChange: _, isReadonly, ...others } = props;
@@ -33,23 +39,43 @@ function PluginEditor(props) {
33
39
  return /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Box, {
34
40
  ...others,
35
41
  children: [
36
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_PluginKindSelect.PluginKindSelect, {
37
- fullWidth: false,
42
+ /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Box, {
38
43
  sx: {
39
- mb: 2,
40
- minWidth: 120
41
- },
42
- margin: "dense",
43
- label: pluginKindLabel,
44
- pluginTypes: pluginTypes,
45
- disabled: isLoading,
46
- value: pendingSelection ? pendingSelection : value.selection,
47
- InputProps: {
48
- readOnly: isReadonly
44
+ display: 'flex',
45
+ flexDirection: 'row'
49
46
  },
50
- error: !!error,
51
- helperText: error?.message,
52
- onChange: onSelectionChange
47
+ children: [
48
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_PluginKindSelect.PluginKindSelect, {
49
+ fullWidth: false,
50
+ sx: {
51
+ mb: 2,
52
+ minWidth: 120
53
+ },
54
+ margin: "dense",
55
+ label: pluginKindLabel,
56
+ pluginTypes: pluginTypes,
57
+ disabled: isLoading,
58
+ value: pendingSelection ? pendingSelection : value.selection,
59
+ InputProps: {
60
+ readOnly: isReadonly
61
+ },
62
+ error: !!error,
63
+ helperText: error?.message,
64
+ onChange: onSelectionChange
65
+ }),
66
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Button, {
67
+ variant: "contained",
68
+ sx: {
69
+ marginTop: 1.5,
70
+ marginBottom: 1.5,
71
+ paddingTop: 0.5,
72
+ marginLeft: 'auto'
73
+ },
74
+ startIcon: /*#__PURE__*/ (0, _jsxruntime.jsx)(_Reload.default, {}),
75
+ onClick: ()=>onSpecChange(value.spec),
76
+ children: "Run Query"
77
+ })
78
+ ]
53
79
  }),
54
80
  /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.ErrorBoundary, {
55
81
  FallbackComponent: _components.ErrorAlert,
@@ -22,6 +22,7 @@ _export_star(require("./plugin-base"), exports);
22
22
  _export_star(require("./plugin-loading"), exports);
23
23
  _export_star(require("./time-series-queries"), exports);
24
24
  _export_star(require("./trace-queries"), exports);
25
+ _export_star(require("./profile-queries"), exports);
25
26
  _export_star(require("./variables"), exports);
26
27
  function _export_star(from, to) {
27
28
  Object.keys(from).forEach(function(k) {
@@ -0,0 +1,16 @@
1
+ // Copyright 2025 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
+ });
@@ -38,6 +38,7 @@ const _jsxruntime = require("react/jsx-runtime");
38
38
  const _react = require("react");
39
39
  const _timeseriesqueries = require("../time-series-queries");
40
40
  const _tracequeries = require("../trace-queries");
41
+ const _profilequeries = require("../profile-queries");
41
42
  const _UsageMetricsProvider = require("../UsageMetricsProvider");
42
43
  const _model = require("./model");
43
44
  const DataQueriesContext = /*#__PURE__*/ (0, _react.createContext)(undefined);
@@ -83,17 +84,22 @@ function DataQueriesProvider(props) {
83
84
  const timeSeriesResults = (0, _timeseriesqueries.useTimeSeriesQueries)(timeSeriesQueries, options, queryOptions);
84
85
  const traceQueries = queryDefinitions.filter((definition)=>definition.kind === 'TraceQuery');
85
86
  const traceResults = (0, _tracequeries.useTraceQueries)(traceQueries);
87
+ const profileQueries = queryDefinitions.filter((definition)=>definition.kind === 'ProfileQuery');
88
+ const profileResults = (0, _profilequeries.useProfileQueries)(profileQueries);
86
89
  const refetchAll = (0, _react.useCallback)(()=>{
87
90
  timeSeriesResults.forEach((result)=>result.refetch());
88
91
  traceResults.forEach((result)=>result.refetch());
92
+ profileResults.forEach((result)=>result.refetch());
89
93
  }, [
90
94
  timeSeriesResults,
91
- traceResults
95
+ traceResults,
96
+ profileResults
92
97
  ]);
93
98
  const ctx = (0, _react.useMemo)(()=>{
94
99
  const mergedQueryResults = [
95
100
  ...(0, _model.transformQueryResults)(timeSeriesResults, timeSeriesQueries),
96
- ...(0, _model.transformQueryResults)(traceResults, traceQueries)
101
+ ...(0, _model.transformQueryResults)(traceResults, traceQueries),
102
+ ...(0, _model.transformQueryResults)(profileResults, profileQueries)
97
103
  ];
98
104
  if (queryOptions?.enabled) {
99
105
  for (const result of mergedQueryResults){
@@ -118,6 +124,8 @@ function DataQueriesProvider(props) {
118
124
  timeSeriesResults,
119
125
  traceQueries,
120
126
  traceResults,
127
+ profileQueries,
128
+ profileResults,
121
129
  refetchAll,
122
130
  queryOptions?.enabled,
123
131
  usageMetrics
@@ -49,11 +49,15 @@ function useQueryType() {
49
49
  const { data: traceQueryPlugins, isLoading: isTraceQueryPluginLoading } = (0, _pluginregistry.useListPluginMetadata)([
50
50
  'TraceQuery'
51
51
  ]);
52
+ const { data: profileQueryPlugins, isLoading: isProfileQueryPluginLoading } = (0, _pluginregistry.useListPluginMetadata)([
53
+ 'ProfileQuery'
54
+ ]);
52
55
  // For example, `map: {"TimeSeriesQuery":["PrometheusTimeSeriesQuery"],"TraceQuery":["TempoTraceQuery"]}`
53
56
  const queryTypeMap = (0, _react.useMemo)(()=>{
54
57
  const map = {
55
58
  TimeSeriesQuery: [],
56
- TraceQuery: []
59
+ TraceQuery: [],
60
+ ProfileQuery: []
57
61
  };
58
62
  if (timeSeriesQueryPlugins) {
59
63
  timeSeriesQueryPlugins.forEach((plugin)=>{
@@ -65,10 +69,16 @@ function useQueryType() {
65
69
  map[plugin.kind]?.push(plugin.spec.name);
66
70
  });
67
71
  }
72
+ if (profileQueryPlugins) {
73
+ profileQueryPlugins.forEach((plugin)=>{
74
+ map[plugin.kind]?.push(plugin.spec.name);
75
+ });
76
+ }
68
77
  return map;
69
78
  }, [
70
79
  timeSeriesQueryPlugins,
71
- traceQueryPlugins
80
+ traceQueryPlugins,
81
+ profileQueryPlugins
72
82
  ]);
73
83
  const getQueryType = (0, _react.useCallback)((pluginKind)=>{
74
84
  const isLoading = (pluginKind)=>{
@@ -77,8 +87,10 @@ function useQueryType() {
77
87
  return isTimeSeriesQueryLoading;
78
88
  case 'TempoTraceQuery':
79
89
  return isTraceQueryPluginLoading;
90
+ case 'PyroscopeProfileQuery':
91
+ return isProfileQueryPluginLoading;
80
92
  }
81
- return isTraceQueryPluginLoading || isTimeSeriesQueryLoading;
93
+ return isTraceQueryPluginLoading || isTimeSeriesQueryLoading || isProfileQueryPluginLoading;
82
94
  };
83
95
  if (isLoading(pluginKind)) {
84
96
  return undefined;
@@ -92,7 +104,8 @@ function useQueryType() {
92
104
  }, [
93
105
  queryTypeMap,
94
106
  isTimeSeriesQueryLoading,
95
- isTraceQueryPluginLoading
107
+ isTraceQueryPluginLoading,
108
+ isProfileQueryPluginLoading
96
109
  ]);
97
110
  return getQueryType;
98
111
  }
@@ -0,0 +1,113 @@
1
+ // Copyright 2025 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
+ ReactRouterProvider: function() {
25
+ return ReactRouterProvider;
26
+ },
27
+ RouterContext: function() {
28
+ return RouterContext;
29
+ },
30
+ RouterProvider: function() {
31
+ return RouterProvider;
32
+ },
33
+ useRouterContext: function() {
34
+ return useRouterContext;
35
+ }
36
+ });
37
+ const _jsxruntime = require("react/jsx-runtime");
38
+ const _react = /*#__PURE__*/ _interop_require_wildcard(require("react"));
39
+ const _reactrouterdom = require("react-router-dom");
40
+ function _getRequireWildcardCache(nodeInterop) {
41
+ if (typeof WeakMap !== "function") return null;
42
+ var cacheBabelInterop = new WeakMap();
43
+ var cacheNodeInterop = new WeakMap();
44
+ return (_getRequireWildcardCache = function(nodeInterop) {
45
+ return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
46
+ })(nodeInterop);
47
+ }
48
+ function _interop_require_wildcard(obj, nodeInterop) {
49
+ if (!nodeInterop && obj && obj.__esModule) {
50
+ return obj;
51
+ }
52
+ if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
53
+ return {
54
+ default: obj
55
+ };
56
+ }
57
+ var cache = _getRequireWildcardCache(nodeInterop);
58
+ if (cache && cache.has(obj)) {
59
+ return cache.get(obj);
60
+ }
61
+ var newObj = {
62
+ __proto__: null
63
+ };
64
+ var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
65
+ for(var key in obj){
66
+ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
67
+ var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
68
+ if (desc && (desc.get || desc.set)) {
69
+ Object.defineProperty(newObj, key, desc);
70
+ } else {
71
+ newObj[key] = obj[key];
72
+ }
73
+ }
74
+ }
75
+ newObj.default = obj;
76
+ if (cache) {
77
+ cache.set(obj, newObj);
78
+ }
79
+ return newObj;
80
+ }
81
+ const RouterContext = /*#__PURE__*/ (0, _react.createContext)(undefined);
82
+ function useRouterContext() {
83
+ const ctx = (0, _react.useContext)(RouterContext);
84
+ if (ctx === undefined) {
85
+ throw new Error('No RouterContext found. Did you forget a <RouterProvider>?');
86
+ }
87
+ return ctx;
88
+ }
89
+ function RouterProvider(props) {
90
+ const { RouterComponent, navigate, children } = props;
91
+ const ctx = (0, _react.useMemo)(()=>{
92
+ return {
93
+ RouterComponent,
94
+ navigate
95
+ };
96
+ }, [
97
+ RouterComponent,
98
+ navigate
99
+ ]);
100
+ return /*#__PURE__*/ (0, _jsxruntime.jsx)(RouterContext.Provider, {
101
+ value: ctx,
102
+ children: children
103
+ });
104
+ }
105
+ function ReactRouterProvider(props) {
106
+ const { children } = props;
107
+ const navigate = (0, _reactrouterdom.useNavigate)();
108
+ return /*#__PURE__*/ (0, _jsxruntime.jsx)(RouterProvider, {
109
+ RouterComponent: _reactrouterdom.Link,
110
+ navigate: navigate,
111
+ children: children
112
+ });
113
+ }
@@ -21,8 +21,10 @@ _export_star(require("./variables"), exports);
21
21
  _export_star(require("./TimeRangeProvider"), exports);
22
22
  _export_star(require("./time-series-queries"), exports);
23
23
  _export_star(require("./trace-queries"), exports);
24
+ _export_star(require("./profile-queries"), exports);
24
25
  _export_star(require("./DataQueriesProvider"), exports);
25
26
  _export_star(require("./QueryCountProvider"), exports);
27
+ _export_star(require("./RouterProvider"), exports);
26
28
  _export_star(require("./UsageMetricsProvider"), exports);
27
29
  function _export_star(from, to) {
28
30
  Object.keys(from).forEach(function(k) {
@@ -0,0 +1,65 @@
1
+ // Copyright 2025 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
+ PROFILE_QUERY_KEY: function() {
25
+ return PROFILE_QUERY_KEY;
26
+ },
27
+ useProfileQueries: function() {
28
+ return useProfileQueries;
29
+ }
30
+ });
31
+ const _reactquery = require("@tanstack/react-query");
32
+ const _datasources = require("./datasources");
33
+ const _pluginregistry = require("./plugin-registry");
34
+ const _TimeRangeProvider = require("./TimeRangeProvider");
35
+ const PROFILE_QUERY_KEY = 'ProfileQuery';
36
+ function useProfileQueries(definitions) {
37
+ const { getPlugin } = (0, _pluginregistry.usePluginRegistry)();
38
+ const datasourceStore = (0, _datasources.useDatasourceStore)();
39
+ const { absoluteTimeRange } = (0, _TimeRangeProvider.useTimeRange)();
40
+ const context = {
41
+ datasourceStore,
42
+ absoluteTimeRange
43
+ };
44
+ // useQueries() handles data fetching from query plugins (e.g. traceQL queries, promQL queries)
45
+ // https://tanstack.com/query/v4/docs/react/reference/useQuery
46
+ return (0, _reactquery.useQueries)({
47
+ queries: definitions.map((definition)=>{
48
+ const queryKey = [
49
+ definition,
50
+ datasourceStore,
51
+ absoluteTimeRange
52
+ ]; // `queryKey` watches and reruns `queryFn` if keys in the array change
53
+ const profileQueryKind = definition?.spec?.plugin?.kind;
54
+ return {
55
+ queryKey: queryKey,
56
+ queryFn: async ()=>{
57
+ const plugin = await getPlugin(PROFILE_QUERY_KEY, profileQueryKind);
58
+ const data = await plugin.getProfileData(definition.spec.plugin.spec, context);
59
+ return data;
60
+ },
61
+ structuralSharing: false
62
+ };
63
+ })
64
+ });
65
+ }
@@ -21,6 +21,9 @@ function _export(target, all) {
21
21
  });
22
22
  }
23
23
  _export(exports, {
24
+ MOCK_PROFILE_DATA: function() {
25
+ return MOCK_PROFILE_DATA;
26
+ },
24
27
  MOCK_TIME_SERIES_DATA: function() {
25
28
  return MOCK_TIME_SERIES_DATA;
26
29
  },
@@ -99,3 +102,23 @@ const MOCK_TRACE_DATA = {
99
102
  executedQueryString: '{ duration > 1000ms }'
100
103
  }
101
104
  };
105
+ const MOCK_PROFILE_DATA = {
106
+ profile: {
107
+ stackTrace: {
108
+ id: 0,
109
+ name: 'root',
110
+ level: 0,
111
+ start: 1699916103945861,
112
+ end: 1699916105065861,
113
+ total: 1000,
114
+ self: 500,
115
+ children: []
116
+ }
117
+ },
118
+ metadata: {
119
+ spyName: '',
120
+ sampleRate: 1000000000,
121
+ units: 'samples',
122
+ name: 'cpu'
123
+ }
124
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"PluginEditor.d.ts","sourceRoot":"","sources":["../../../src/components/PluginEditor/PluginEditor.tsx"],"names":[],"mappings":"AAeA,OAAO,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAGrC,OAAO,EAAE,iBAAiB,EAAmB,MAAM,qBAAqB,CAAC;AAEzE;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,YAAY,CA6BnE"}
1
+ {"version":3,"file":"PluginEditor.d.ts","sourceRoot":"","sources":["../../../src/components/PluginEditor/PluginEditor.tsx"],"names":[],"mappings":"AAgBA,OAAO,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAGrC,OAAO,EAAE,iBAAiB,EAAmB,MAAM,qBAAqB,CAAC;AAEzE;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,YAAY,CAyCnE"}
@@ -11,7 +11,8 @@
11
11
  // See the License for the specific language governing permissions and
12
12
  // limitations under the License.
13
13
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
14
- import { Box } from '@mui/material';
14
+ import { Box, Button } from '@mui/material';
15
+ import Reload from 'mdi-material-ui/Reload';
15
16
  import { ErrorAlert, ErrorBoundary } from '@perses-dev/components';
16
17
  import { PluginKindSelect } from '../PluginKindSelect';
17
18
  import { PluginSpecEditor } from '../PluginSpecEditor';
@@ -30,23 +31,43 @@ import { usePluginEditor } from './plugin-editor-api';
30
31
  return /*#__PURE__*/ _jsxs(Box, {
31
32
  ...others,
32
33
  children: [
33
- /*#__PURE__*/ _jsx(PluginKindSelect, {
34
- fullWidth: false,
34
+ /*#__PURE__*/ _jsxs(Box, {
35
35
  sx: {
36
- mb: 2,
37
- minWidth: 120
36
+ display: 'flex',
37
+ flexDirection: 'row'
38
38
  },
39
- margin: "dense",
40
- label: pluginKindLabel,
41
- pluginTypes: pluginTypes,
42
- disabled: isLoading,
43
- value: pendingSelection ? pendingSelection : value.selection,
44
- InputProps: {
45
- readOnly: isReadonly
46
- },
47
- error: !!error,
48
- helperText: error?.message,
49
- onChange: onSelectionChange
39
+ children: [
40
+ /*#__PURE__*/ _jsx(PluginKindSelect, {
41
+ fullWidth: false,
42
+ sx: {
43
+ mb: 2,
44
+ minWidth: 120
45
+ },
46
+ margin: "dense",
47
+ label: pluginKindLabel,
48
+ pluginTypes: pluginTypes,
49
+ disabled: isLoading,
50
+ value: pendingSelection ? pendingSelection : value.selection,
51
+ InputProps: {
52
+ readOnly: isReadonly
53
+ },
54
+ error: !!error,
55
+ helperText: error?.message,
56
+ onChange: onSelectionChange
57
+ }),
58
+ /*#__PURE__*/ _jsx(Button, {
59
+ variant: "contained",
60
+ sx: {
61
+ marginTop: 1.5,
62
+ marginBottom: 1.5,
63
+ paddingTop: 0.5,
64
+ marginLeft: 'auto'
65
+ },
66
+ startIcon: /*#__PURE__*/ _jsx(Reload, {}),
67
+ onClick: ()=>onSpecChange(value.spec),
68
+ children: "Run Query"
69
+ })
70
+ ]
50
71
  }),
51
72
  /*#__PURE__*/ _jsx(ErrorBoundary, {
52
73
  FallbackComponent: ErrorAlert,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/PluginEditor/PluginEditor.tsx"],"sourcesContent":["// Copyright 2023 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { Box } from '@mui/material';\nimport { ErrorAlert, ErrorBoundary } from '@perses-dev/components';\nimport { ReactElement } from 'react';\nimport { PluginKindSelect } from '../PluginKindSelect';\nimport { PluginSpecEditor } from '../PluginSpecEditor';\nimport { PluginEditorProps, usePluginEditor } from './plugin-editor-api';\n\n/**\n * A combination `PluginKindSelect` and `PluginSpecEditor` component. This is meant for editing the `plugin` property\n * that's common in our JSON specs where a user selects a plugin `kind` and then edits the `spec` via that plugin's\n * editor component. It takes care of transitioning from one plugin kind to another \"all at once\" so that when the\n * plugin's kind changes, the spec is also changed at the same time so those options editor components don't see a\n * previous plugin's spec state. If you just want this behavior, but in a different UI layout from this, try the\n * `usePluginEditor` hook that powers this component.\n */\nexport function PluginEditor(props: PluginEditorProps): ReactElement {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { value, pluginTypes, pluginKindLabel, onChange: _, isReadonly, ...others } = props;\n const { pendingSelection, isLoading, error, onSelectionChange, onSpecChange } = usePluginEditor(props);\n return (\n <Box {...others}>\n <PluginKindSelect\n fullWidth={false}\n sx={{ mb: 2, minWidth: 120 }}\n margin=\"dense\"\n label={pluginKindLabel}\n pluginTypes={pluginTypes}\n disabled={isLoading}\n value={pendingSelection ? pendingSelection : value.selection}\n InputProps={{ readOnly: isReadonly }}\n error={!!error}\n helperText={error?.message}\n onChange={onSelectionChange}\n />\n <ErrorBoundary FallbackComponent={ErrorAlert}>\n <PluginSpecEditor\n pluginSelection={value.selection}\n value={value.spec}\n onChange={onSpecChange}\n isReadonly={isReadonly}\n />\n </ErrorBoundary>\n </Box>\n );\n}\n"],"names":["Box","ErrorAlert","ErrorBoundary","PluginKindSelect","PluginSpecEditor","usePluginEditor","PluginEditor","props","value","pluginTypes","pluginKindLabel","onChange","_","isReadonly","others","pendingSelection","isLoading","error","onSelectionChange","onSpecChange","fullWidth","sx","mb","minWidth","margin","label","disabled","selection","InputProps","readOnly","helperText","message","FallbackComponent","pluginSelection","spec"],"mappings":"AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;;AAEjC,SAASA,GAAG,QAAQ,gBAAgB;AACpC,SAASC,UAAU,EAAEC,aAAa,QAAQ,yBAAyB;AAEnE,SAASC,gBAAgB,QAAQ,sBAAsB;AACvD,SAASC,gBAAgB,QAAQ,sBAAsB;AACvD,SAA4BC,eAAe,QAAQ,sBAAsB;AAEzE;;;;;;;CAOC,GACD,OAAO,SAASC,aAAaC,KAAwB;IACnD,6DAA6D;IAC7D,MAAM,EAAEC,KAAK,EAAEC,WAAW,EAAEC,eAAe,EAAEC,UAAUC,CAAC,EAAEC,UAAU,EAAE,GAAGC,QAAQ,GAAGP;IACpF,MAAM,EAAEQ,gBAAgB,EAAEC,SAAS,EAAEC,KAAK,EAAEC,iBAAiB,EAAEC,YAAY,EAAE,GAAGd,gBAAgBE;IAChG,qBACE,MAACP;QAAK,GAAGc,MAAM;;0BACb,KAACX;gBACCiB,WAAW;gBACXC,IAAI;oBAAEC,IAAI;oBAAGC,UAAU;gBAAI;gBAC3BC,QAAO;gBACPC,OAAOf;gBACPD,aAAaA;gBACbiB,UAAUV;gBACVR,OAAOO,mBAAmBA,mBAAmBP,MAAMmB,SAAS;gBAC5DC,YAAY;oBAAEC,UAAUhB;gBAAW;gBACnCI,OAAO,CAAC,CAACA;gBACTa,YAAYb,OAAOc;gBACnBpB,UAAUO;;0BAEZ,KAAChB;gBAAc8B,mBAAmB/B;0BAChC,cAAA,KAACG;oBACC6B,iBAAiBzB,MAAMmB,SAAS;oBAChCnB,OAAOA,MAAM0B,IAAI;oBACjBvB,UAAUQ;oBACVN,YAAYA;;;;;AAKtB"}
1
+ {"version":3,"sources":["../../../src/components/PluginEditor/PluginEditor.tsx"],"sourcesContent":["// Copyright 2023 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { Box, Button } from '@mui/material';\nimport Reload from 'mdi-material-ui/Reload';\nimport { ErrorAlert, ErrorBoundary } from '@perses-dev/components';\nimport { ReactElement } from 'react';\nimport { PluginKindSelect } from '../PluginKindSelect';\nimport { PluginSpecEditor } from '../PluginSpecEditor';\nimport { PluginEditorProps, usePluginEditor } from './plugin-editor-api';\n\n/**\n * A combination `PluginKindSelect` and `PluginSpecEditor` component. This is meant for editing the `plugin` property\n * that's common in our JSON specs where a user selects a plugin `kind` and then edits the `spec` via that plugin's\n * editor component. It takes care of transitioning from one plugin kind to another \"all at once\" so that when the\n * plugin's kind changes, the spec is also changed at the same time so those options editor components don't see a\n * previous plugin's spec state. If you just want this behavior, but in a different UI layout from this, try the\n * `usePluginEditor` hook that powers this component.\n */\nexport function PluginEditor(props: PluginEditorProps): ReactElement {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { value, pluginTypes, pluginKindLabel, onChange: _, isReadonly, ...others } = props;\n const { pendingSelection, isLoading, error, onSelectionChange, onSpecChange } = usePluginEditor(props);\n return (\n <Box {...others}>\n <Box sx={{ display: 'flex', flexDirection: 'row' }}>\n <PluginKindSelect\n fullWidth={false}\n sx={{ mb: 2, minWidth: 120 }}\n margin=\"dense\"\n label={pluginKindLabel}\n pluginTypes={pluginTypes}\n disabled={isLoading}\n value={pendingSelection ? pendingSelection : value.selection}\n InputProps={{ readOnly: isReadonly }}\n error={!!error}\n helperText={error?.message}\n onChange={onSelectionChange}\n />\n\n <Button\n variant=\"contained\"\n sx={{ marginTop: 1.5, marginBottom: 1.5, paddingTop: 0.5, marginLeft: 'auto' }}\n startIcon={<Reload />}\n onClick={() => onSpecChange(value.spec)}\n >\n Run Query\n </Button>\n </Box>\n\n <ErrorBoundary FallbackComponent={ErrorAlert}>\n <PluginSpecEditor\n pluginSelection={value.selection}\n value={value.spec}\n onChange={onSpecChange}\n isReadonly={isReadonly}\n />\n </ErrorBoundary>\n </Box>\n );\n}\n"],"names":["Box","Button","Reload","ErrorAlert","ErrorBoundary","PluginKindSelect","PluginSpecEditor","usePluginEditor","PluginEditor","props","value","pluginTypes","pluginKindLabel","onChange","_","isReadonly","others","pendingSelection","isLoading","error","onSelectionChange","onSpecChange","sx","display","flexDirection","fullWidth","mb","minWidth","margin","label","disabled","selection","InputProps","readOnly","helperText","message","variant","marginTop","marginBottom","paddingTop","marginLeft","startIcon","onClick","spec","FallbackComponent","pluginSelection"],"mappings":"AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;;AAEjC,SAASA,GAAG,EAAEC,MAAM,QAAQ,gBAAgB;AAC5C,OAAOC,YAAY,yBAAyB;AAC5C,SAASC,UAAU,EAAEC,aAAa,QAAQ,yBAAyB;AAEnE,SAASC,gBAAgB,QAAQ,sBAAsB;AACvD,SAASC,gBAAgB,QAAQ,sBAAsB;AACvD,SAA4BC,eAAe,QAAQ,sBAAsB;AAEzE;;;;;;;CAOC,GACD,OAAO,SAASC,aAAaC,KAAwB;IACnD,6DAA6D;IAC7D,MAAM,EAAEC,KAAK,EAAEC,WAAW,EAAEC,eAAe,EAAEC,UAAUC,CAAC,EAAEC,UAAU,EAAE,GAAGC,QAAQ,GAAGP;IACpF,MAAM,EAAEQ,gBAAgB,EAAEC,SAAS,EAAEC,KAAK,EAAEC,iBAAiB,EAAEC,YAAY,EAAE,GAAGd,gBAAgBE;IAChG,qBACE,MAACT;QAAK,GAAGgB,MAAM;;0BACb,MAAChB;gBAAIsB,IAAI;oBAAEC,SAAS;oBAAQC,eAAe;gBAAM;;kCAC/C,KAACnB;wBACCoB,WAAW;wBACXH,IAAI;4BAAEI,IAAI;4BAAGC,UAAU;wBAAI;wBAC3BC,QAAO;wBACPC,OAAOjB;wBACPD,aAAaA;wBACbmB,UAAUZ;wBACVR,OAAOO,mBAAmBA,mBAAmBP,MAAMqB,SAAS;wBAC5DC,YAAY;4BAAEC,UAAUlB;wBAAW;wBACnCI,OAAO,CAAC,CAACA;wBACTe,YAAYf,OAAOgB;wBACnBtB,UAAUO;;kCAGZ,KAACnB;wBACCmC,SAAQ;wBACRd,IAAI;4BAAEe,WAAW;4BAAKC,cAAc;4BAAKC,YAAY;4BAAKC,YAAY;wBAAO;wBAC7EC,yBAAW,KAACvC;wBACZwC,SAAS,IAAMrB,aAAaX,MAAMiC,IAAI;kCACvC;;;;0BAKH,KAACvC;gBAAcwC,mBAAmBzC;0BAChC,cAAA,KAACG;oBACCuC,iBAAiBnC,MAAMqB,SAAS;oBAChCrB,OAAOA,MAAMiC,IAAI;oBACjB9B,UAAUQ;oBACVN,YAAYA;;;;;AAKtB"}
@@ -10,7 +10,7 @@ export interface PluginKindSelectProps extends Omit<TextFieldProps, 'value' | 'o
10
10
  /**
11
11
  * Displays a MUI Select input for selecting a plugin's kind from a list of all the available plugins of some specific
12
12
  * plugin types. (e.g. "Show a list of all the Panel plugins", or "Show a list of all the Variable plugins", or "Show
13
- * a list of all the TimeSeriesQuery, TraceQuery, and LogQuery plugins").
13
+ * a list of all the TimeSeriesQuery, TraceQuery, ProfileQuery, and LogQuery plugins").
14
14
  * The value of the select is the kind of the plugin, but you can also listen to the `onPluginTypeChange` event to know
15
15
  * when the user changes the plugin type (it fires at start for the default value.)
16
16
  */
@@ -17,7 +17,7 @@ import { useListPluginMetadata } from '../../runtime';
17
17
  /**
18
18
  * Displays a MUI Select input for selecting a plugin's kind from a list of all the available plugins of some specific
19
19
  * plugin types. (e.g. "Show a list of all the Panel plugins", or "Show a list of all the Variable plugins", or "Show
20
- * a list of all the TimeSeriesQuery, TraceQuery, and LogQuery plugins").
20
+ * a list of all the TimeSeriesQuery, TraceQuery, ProfileQuery, and LogQuery plugins").
21
21
  * The value of the select is the kind of the plugin, but you can also listen to the `onPluginTypeChange` event to know
22
22
  * when the user changes the plugin type (it fires at start for the default value.)
23
23
  */ export const PluginKindSelect = /*#__PURE__*/ forwardRef((props, ref)=>{
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/PluginKindSelect/PluginKindSelect.tsx"],"sourcesContent":["// Copyright 2023 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { MenuItem, TextField, TextFieldProps } from '@mui/material';\nimport { forwardRef, ReactElement, useCallback } from 'react';\nimport { PluginType } from '../../model';\nimport { useListPluginMetadata } from '../../runtime';\nimport { PluginEditorSelection } from '../PluginEditor';\n\nexport interface PluginKindSelectProps extends Omit<TextFieldProps, 'value' | 'onChange' | 'children'> {\n pluginTypes: PluginType[];\n value?: PluginEditorSelection;\n onChange?: (s: PluginEditorSelection) => void;\n}\n\n/**\n * Displays a MUI Select input for selecting a plugin's kind from a list of all the available plugins of some specific\n * plugin types. (e.g. \"Show a list of all the Panel plugins\", or \"Show a list of all the Variable plugins\", or \"Show\n * a list of all the TimeSeriesQuery, TraceQuery, and LogQuery plugins\").\n * The value of the select is the kind of the plugin, but you can also listen to the `onPluginTypeChange` event to know\n * when the user changes the plugin type (it fires at start for the default value.)\n */\nexport const PluginKindSelect = forwardRef((props: PluginKindSelectProps, ref): ReactElement => {\n const { pluginTypes, value: propValue, onChange, ...others } = props;\n const { data, isLoading } = useListPluginMetadata(pluginTypes);\n\n // Pass an empty value while options are still loading so MUI doesn't complain about us using an \"out of range\" value\n const value = !propValue || isLoading ? '' : selectionToOptionValue(propValue);\n\n const handleChange = (event: { target: { value: string } }): void => {\n onChange?.(optionValueToSelection(event.target.value));\n };\n\n const renderValue = useCallback(\n (selected: unknown) => {\n if (selected === '') {\n return '';\n }\n const selectedValue = optionValueToSelection(selected as string);\n return data?.find((v) => v.kind === selectedValue.type && v.spec.name === selectedValue.kind)?.spec.display.name;\n },\n [data]\n );\n\n // TODO: Does this need a loading indicator of some kind?\n return (\n <TextField\n select\n inputRef={ref}\n {...others}\n value={value}\n aria-label={value}\n onChange={handleChange}\n SelectProps={{ renderValue }}\n data-testid=\"plugin-kind-select\"\n >\n {isLoading && <MenuItem value=\"\">Loading...</MenuItem>}\n {data?.map((metadata) => (\n <MenuItem\n data-testid=\"option\"\n key={metadata.kind + metadata.spec.name}\n value={selectionToOptionValue({ type: metadata.kind, kind: metadata.spec.name })}\n >\n {metadata.spec.display.name}\n </MenuItem>\n ))}\n </TextField>\n );\n});\nPluginKindSelect.displayName = 'PluginKindSelect';\n\n// Delimiter used to stringify/parse option values\nconst OPTION_VALUE_DELIMITER = '_____';\n\n/**\n * Given a PluginEditorSelection,\n * returns a string value like `{type}_____{kind}` that can be used as a Select input value.\n * @param selector\n */\nfunction selectionToOptionValue(selector: PluginEditorSelection): string {\n return [selector.type, selector.kind].join(OPTION_VALUE_DELIMITER);\n}\n\n/**\n * Given an option value name like `{type}_____{kind}`,\n * returns a PluginEditorSelection to be used by the query data model.\n * @param optionValue\n */\nfunction optionValueToSelection(optionValue: string): PluginEditorSelection {\n const words = optionValue.split(OPTION_VALUE_DELIMITER);\n const type = words[0] as PluginType | undefined;\n const kind = words[1];\n if (type === undefined || kind === undefined) {\n throw new Error('Invalid optionValue string');\n }\n return {\n type,\n kind,\n };\n}\n"],"names":["MenuItem","TextField","forwardRef","useCallback","useListPluginMetadata","PluginKindSelect","props","ref","pluginTypes","value","propValue","onChange","others","data","isLoading","selectionToOptionValue","handleChange","event","optionValueToSelection","target","renderValue","selected","selectedValue","find","v","kind","type","spec","name","display","select","inputRef","aria-label","SelectProps","data-testid","map","metadata","displayName","OPTION_VALUE_DELIMITER","selector","join","optionValue","words","split","undefined","Error"],"mappings":"AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;;AAEjC,SAASA,QAAQ,EAAEC,SAAS,QAAwB,gBAAgB;AACpE,SAASC,UAAU,EAAgBC,WAAW,QAAQ,QAAQ;AAE9D,SAASC,qBAAqB,QAAQ,gBAAgB;AAStD;;;;;;CAMC,GACD,OAAO,MAAMC,iCAAmBH,WAAW,CAACI,OAA8BC;IACxE,MAAM,EAAEC,WAAW,EAAEC,OAAOC,SAAS,EAAEC,QAAQ,EAAE,GAAGC,QAAQ,GAAGN;IAC/D,MAAM,EAAEO,IAAI,EAAEC,SAAS,EAAE,GAAGV,sBAAsBI;IAElD,qHAAqH;IACrH,MAAMC,QAAQ,CAACC,aAAaI,YAAY,KAAKC,uBAAuBL;IAEpE,MAAMM,eAAe,CAACC;QACpBN,WAAWO,uBAAuBD,MAAME,MAAM,CAACV,KAAK;IACtD;IAEA,MAAMW,cAAcjB,YAClB,CAACkB;QACC,IAAIA,aAAa,IAAI;YACnB,OAAO;QACT;QACA,MAAMC,gBAAgBJ,uBAAuBG;QAC7C,OAAOR,MAAMU,KAAK,CAACC,IAAMA,EAAEC,IAAI,KAAKH,cAAcI,IAAI,IAAIF,EAAEG,IAAI,CAACC,IAAI,KAAKN,cAAcG,IAAI,GAAGE,KAAKE,QAAQD;IAC9G,GACA;QAACf;KAAK;IAGR,yDAAyD;IACzD,qBACE,MAACZ;QACC6B,MAAM;QACNC,UAAUxB;QACT,GAAGK,MAAM;QACVH,OAAOA;QACPuB,cAAYvB;QACZE,UAAUK;QACViB,aAAa;YAAEb;QAAY;QAC3Bc,eAAY;;YAEXpB,2BAAa,KAACd;gBAASS,OAAM;0BAAG;;YAChCI,MAAMsB,IAAI,CAACC,yBACV,KAACpC;oBACCkC,eAAY;oBAEZzB,OAAOM,uBAAuB;wBAAEW,MAAMU,SAASX,IAAI;wBAAEA,MAAMW,SAAST,IAAI,CAACC,IAAI;oBAAC;8BAE7EQ,SAAST,IAAI,CAACE,OAAO,CAACD,IAAI;mBAHtBQ,SAASX,IAAI,GAAGW,SAAST,IAAI,CAACC,IAAI;;;AAQjD,GAAG;AACHvB,iBAAiBgC,WAAW,GAAG;AAE/B,kDAAkD;AAClD,MAAMC,yBAAyB;AAE/B;;;;CAIC,GACD,SAASvB,uBAAuBwB,QAA+B;IAC7D,OAAO;QAACA,SAASb,IAAI;QAAEa,SAASd,IAAI;KAAC,CAACe,IAAI,CAACF;AAC7C;AAEA;;;;CAIC,GACD,SAASpB,uBAAuBuB,WAAmB;IACjD,MAAMC,QAAQD,YAAYE,KAAK,CAACL;IAChC,MAAMZ,OAAOgB,KAAK,CAAC,EAAE;IACrB,MAAMjB,OAAOiB,KAAK,CAAC,EAAE;IACrB,IAAIhB,SAASkB,aAAanB,SAASmB,WAAW;QAC5C,MAAM,IAAIC,MAAM;IAClB;IACA,OAAO;QACLnB;QACAD;IACF;AACF"}
1
+ {"version":3,"sources":["../../../src/components/PluginKindSelect/PluginKindSelect.tsx"],"sourcesContent":["// Copyright 2023 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { MenuItem, TextField, TextFieldProps } from '@mui/material';\nimport { forwardRef, ReactElement, useCallback } from 'react';\nimport { PluginType } from '../../model';\nimport { useListPluginMetadata } from '../../runtime';\nimport { PluginEditorSelection } from '../PluginEditor';\n\nexport interface PluginKindSelectProps extends Omit<TextFieldProps, 'value' | 'onChange' | 'children'> {\n pluginTypes: PluginType[];\n value?: PluginEditorSelection;\n onChange?: (s: PluginEditorSelection) => void;\n}\n\n/**\n * Displays a MUI Select input for selecting a plugin's kind from a list of all the available plugins of some specific\n * plugin types. (e.g. \"Show a list of all the Panel plugins\", or \"Show a list of all the Variable plugins\", or \"Show\n * a list of all the TimeSeriesQuery, TraceQuery, ProfileQuery, and LogQuery plugins\").\n * The value of the select is the kind of the plugin, but you can also listen to the `onPluginTypeChange` event to know\n * when the user changes the plugin type (it fires at start for the default value.)\n */\nexport const PluginKindSelect = forwardRef((props: PluginKindSelectProps, ref): ReactElement => {\n const { pluginTypes, value: propValue, onChange, ...others } = props;\n const { data, isLoading } = useListPluginMetadata(pluginTypes);\n\n // Pass an empty value while options are still loading so MUI doesn't complain about us using an \"out of range\" value\n const value = !propValue || isLoading ? '' : selectionToOptionValue(propValue);\n\n const handleChange = (event: { target: { value: string } }): void => {\n onChange?.(optionValueToSelection(event.target.value));\n };\n\n const renderValue = useCallback(\n (selected: unknown) => {\n if (selected === '') {\n return '';\n }\n const selectedValue = optionValueToSelection(selected as string);\n return data?.find((v) => v.kind === selectedValue.type && v.spec.name === selectedValue.kind)?.spec.display.name;\n },\n [data]\n );\n\n // TODO: Does this need a loading indicator of some kind?\n return (\n <TextField\n select\n inputRef={ref}\n {...others}\n value={value}\n aria-label={value}\n onChange={handleChange}\n SelectProps={{ renderValue }}\n data-testid=\"plugin-kind-select\"\n >\n {isLoading && <MenuItem value=\"\">Loading...</MenuItem>}\n {data?.map((metadata) => (\n <MenuItem\n data-testid=\"option\"\n key={metadata.kind + metadata.spec.name}\n value={selectionToOptionValue({ type: metadata.kind, kind: metadata.spec.name })}\n >\n {metadata.spec.display.name}\n </MenuItem>\n ))}\n </TextField>\n );\n});\nPluginKindSelect.displayName = 'PluginKindSelect';\n\n// Delimiter used to stringify/parse option values\nconst OPTION_VALUE_DELIMITER = '_____';\n\n/**\n * Given a PluginEditorSelection,\n * returns a string value like `{type}_____{kind}` that can be used as a Select input value.\n * @param selector\n */\nfunction selectionToOptionValue(selector: PluginEditorSelection): string {\n return [selector.type, selector.kind].join(OPTION_VALUE_DELIMITER);\n}\n\n/**\n * Given an option value name like `{type}_____{kind}`,\n * returns a PluginEditorSelection to be used by the query data model.\n * @param optionValue\n */\nfunction optionValueToSelection(optionValue: string): PluginEditorSelection {\n const words = optionValue.split(OPTION_VALUE_DELIMITER);\n const type = words[0] as PluginType | undefined;\n const kind = words[1];\n if (type === undefined || kind === undefined) {\n throw new Error('Invalid optionValue string');\n }\n return {\n type,\n kind,\n };\n}\n"],"names":["MenuItem","TextField","forwardRef","useCallback","useListPluginMetadata","PluginKindSelect","props","ref","pluginTypes","value","propValue","onChange","others","data","isLoading","selectionToOptionValue","handleChange","event","optionValueToSelection","target","renderValue","selected","selectedValue","find","v","kind","type","spec","name","display","select","inputRef","aria-label","SelectProps","data-testid","map","metadata","displayName","OPTION_VALUE_DELIMITER","selector","join","optionValue","words","split","undefined","Error"],"mappings":"AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;;AAEjC,SAASA,QAAQ,EAAEC,SAAS,QAAwB,gBAAgB;AACpE,SAASC,UAAU,EAAgBC,WAAW,QAAQ,QAAQ;AAE9D,SAASC,qBAAqB,QAAQ,gBAAgB;AAStD;;;;;;CAMC,GACD,OAAO,MAAMC,iCAAmBH,WAAW,CAACI,OAA8BC;IACxE,MAAM,EAAEC,WAAW,EAAEC,OAAOC,SAAS,EAAEC,QAAQ,EAAE,GAAGC,QAAQ,GAAGN;IAC/D,MAAM,EAAEO,IAAI,EAAEC,SAAS,EAAE,GAAGV,sBAAsBI;IAElD,qHAAqH;IACrH,MAAMC,QAAQ,CAACC,aAAaI,YAAY,KAAKC,uBAAuBL;IAEpE,MAAMM,eAAe,CAACC;QACpBN,WAAWO,uBAAuBD,MAAME,MAAM,CAACV,KAAK;IACtD;IAEA,MAAMW,cAAcjB,YAClB,CAACkB;QACC,IAAIA,aAAa,IAAI;YACnB,OAAO;QACT;QACA,MAAMC,gBAAgBJ,uBAAuBG;QAC7C,OAAOR,MAAMU,KAAK,CAACC,IAAMA,EAAEC,IAAI,KAAKH,cAAcI,IAAI,IAAIF,EAAEG,IAAI,CAACC,IAAI,KAAKN,cAAcG,IAAI,GAAGE,KAAKE,QAAQD;IAC9G,GACA;QAACf;KAAK;IAGR,yDAAyD;IACzD,qBACE,MAACZ;QACC6B,MAAM;QACNC,UAAUxB;QACT,GAAGK,MAAM;QACVH,OAAOA;QACPuB,cAAYvB;QACZE,UAAUK;QACViB,aAAa;YAAEb;QAAY;QAC3Bc,eAAY;;YAEXpB,2BAAa,KAACd;gBAASS,OAAM;0BAAG;;YAChCI,MAAMsB,IAAI,CAACC,yBACV,KAACpC;oBACCkC,eAAY;oBAEZzB,OAAOM,uBAAuB;wBAAEW,MAAMU,SAASX,IAAI;wBAAEA,MAAMW,SAAST,IAAI,CAACC,IAAI;oBAAC;8BAE7EQ,SAAST,IAAI,CAACE,OAAO,CAACD,IAAI;mBAHtBQ,SAASX,IAAI,GAAGW,SAAST,IAAI,CAACC,IAAI;;;AAQjD,GAAG;AACHvB,iBAAiBgC,WAAW,GAAG;AAE/B,kDAAkD;AAClD,MAAMC,yBAAyB;AAE/B;;;;CAIC,GACD,SAASvB,uBAAuBwB,QAA+B;IAC7D,OAAO;QAACA,SAASb,IAAI;QAAEa,SAASd,IAAI;KAAC,CAACe,IAAI,CAACF;AAC7C;AAEA;;;;CAIC,GACD,SAASpB,uBAAuBuB,WAAmB;IACjD,MAAMC,QAAQD,YAAYE,KAAK,CAACL;IAChC,MAAMZ,OAAOgB,KAAK,CAAC,EAAE;IACrB,MAAMjB,OAAOiB,KAAK,CAAC,EAAE;IACrB,IAAIhB,SAASkB,aAAanB,SAASmB,WAAW;QAC5C,MAAM,IAAIC,MAAM;IAClB;IACA,OAAO;QACLnB;QACAD;IACF;AACF"}
@@ -6,5 +6,6 @@ export * from './plugin-base';
6
6
  export * from './plugin-loading';
7
7
  export * from './time-series-queries';
8
8
  export * from './trace-queries';
9
+ export * from './profile-queries';
9
10
  export * from './variables';
10
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/model/index.ts"],"names":[],"mappings":"AAaA,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/model/index.ts"],"names":[],"mappings":"AAaA,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC"}
@@ -18,6 +18,7 @@ export * from './plugin-base';
18
18
  export * from './plugin-loading';
19
19
  export * from './time-series-queries';
20
20
  export * from './trace-queries';
21
+ export * from './profile-queries';
21
22
  export * from './variables';
22
23
 
23
24
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/model/index.ts"],"sourcesContent":["// Copyright 2023 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nexport * from './datasource';\nexport * from './legend';\nexport * from './panels';\nexport * from './plugins';\nexport * from './plugin-base';\nexport * from './plugin-loading';\nexport * from './time-series-queries';\nexport * from './trace-queries';\nexport * from './variables';\n"],"names":[],"mappings":"AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC,cAAc,eAAe;AAC7B,cAAc,WAAW;AACzB,cAAc,WAAW;AACzB,cAAc,YAAY;AAC1B,cAAc,gBAAgB;AAC9B,cAAc,mBAAmB;AACjC,cAAc,wBAAwB;AACtC,cAAc,kBAAkB;AAChC,cAAc,cAAc"}
1
+ {"version":3,"sources":["../../src/model/index.ts"],"sourcesContent":["// Copyright 2023 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nexport * from './datasource';\nexport * from './legend';\nexport * from './panels';\nexport * from './plugins';\nexport * from './plugin-base';\nexport * from './plugin-loading';\nexport * from './time-series-queries';\nexport * from './trace-queries';\nexport * from './profile-queries';\nexport * from './variables';\n"],"names":[],"mappings":"AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC,cAAc,eAAe;AAC7B,cAAc,WAAW;AACzB,cAAc,WAAW;AACzB,cAAc,YAAY;AAC1B,cAAc,gBAAgB;AAC9B,cAAc,mBAAmB;AACjC,cAAc,wBAAwB;AACtC,cAAc,kBAAkB;AAChC,cAAc,oBAAoB;AAClC,cAAc,cAAc"}
@@ -6,6 +6,10 @@ import { OptionsEditorProps, Plugin } from './plugin-base';
6
6
  export type PanelOptionsEditorComponent<T> = Pick<OptionsEditorTab, 'label'> & {
7
7
  content: React.ComponentType<OptionsEditorProps<T>>;
8
8
  };
9
+ export type PanelAction<TPanelProps> = {
10
+ component: React.ComponentType<TPanelProps>;
11
+ location?: string;
12
+ };
9
13
  /**
10
14
  * Plugin the provides custom visualizations inside a Panel.
11
15
  */
@@ -36,6 +40,10 @@ export interface PanelPlugin<Spec = UnknownSpec, TPanelProps = PanelProps<Spec>>
36
40
  * @default false
37
41
  */
38
42
  hideQueryEditor?: boolean;
43
+ /**
44
+ * List of panel actions that will be rendered in the panel header
45
+ */
46
+ actions?: Array<PanelAction<TPanelProps>>;
39
47
  }
40
48
  /**
41
49
  * The props provided by Perses to a panel plugin's PanelComponent.