@perses-dev/dashboards 0.53.0-beta.2 → 0.53.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/Panel/PanelActions.js +36 -0
- package/dist/cjs/components/Panel/PanelPluginLoader.js +4 -2
- package/dist/cjs/components/PanelDrawer/PanelEditorForm.js +0 -2
- package/dist/cjs/components/PanelDrawer/PanelQueriesSharedControls.js +24 -8
- package/dist/cjs/context/PanelEditorProvider/PanelEditorProvider.js +1 -2
- package/dist/components/Panel/PanelActions.d.ts.map +1 -1
- package/dist/components/Panel/PanelActions.js +36 -0
- package/dist/components/Panel/PanelActions.js.map +1 -1
- package/dist/components/Panel/PanelPluginLoader.d.ts.map +1 -1
- package/dist/components/Panel/PanelPluginLoader.js +4 -2
- package/dist/components/Panel/PanelPluginLoader.js.map +1 -1
- package/dist/components/PanelDrawer/PanelEditorForm.d.ts.map +1 -1
- package/dist/components/PanelDrawer/PanelEditorForm.js +1 -3
- package/dist/components/PanelDrawer/PanelEditorForm.js.map +1 -1
- package/dist/components/PanelDrawer/PanelQueriesSharedControls.d.ts.map +1 -1
- package/dist/components/PanelDrawer/PanelQueriesSharedControls.js +25 -9
- package/dist/components/PanelDrawer/PanelQueriesSharedControls.js.map +1 -1
- package/dist/context/PanelEditorProvider/PanelEditorProvider.d.ts +1 -1
- package/dist/context/PanelEditorProvider/PanelEditorProvider.d.ts.map +1 -1
- package/dist/context/PanelEditorProvider/PanelEditorProvider.js +1 -2
- package/dist/context/PanelEditorProvider/PanelEditorProvider.js.map +1 -1
- package/package.json +5 -5
|
@@ -33,6 +33,7 @@ const _DragVertical = /*#__PURE__*/ _interop_require_default(require("mdi-materi
|
|
|
33
33
|
const _ContentCopy = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/ContentCopy"));
|
|
34
34
|
const _Menu = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/Menu"));
|
|
35
35
|
const _Alert = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/Alert"));
|
|
36
|
+
const _AlertCircle = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/AlertCircle"));
|
|
36
37
|
const _InformationOutline = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/InformationOutline"));
|
|
37
38
|
const _constants = require("../../constants");
|
|
38
39
|
const _HeaderIconButton = require("./HeaderIconButton");
|
|
@@ -42,6 +43,19 @@ function _interop_require_default(obj) {
|
|
|
42
43
|
default: obj
|
|
43
44
|
};
|
|
44
45
|
}
|
|
46
|
+
const noticeTypeToIcon = {
|
|
47
|
+
error: /*#__PURE__*/ (0, _jsxruntime.jsx)(_AlertCircle.default, {
|
|
48
|
+
color: "error"
|
|
49
|
+
}),
|
|
50
|
+
warning: /*#__PURE__*/ (0, _jsxruntime.jsx)(_Alert.default, {
|
|
51
|
+
fontSize: "inherit",
|
|
52
|
+
color: "warning"
|
|
53
|
+
}),
|
|
54
|
+
info: /*#__PURE__*/ (0, _jsxruntime.jsx)(_InformationOutline.default, {
|
|
55
|
+
fontSize: "inherit",
|
|
56
|
+
color: "info"
|
|
57
|
+
})
|
|
58
|
+
};
|
|
45
59
|
const ConditionalBox = (0, _material.styled)(_material.Box)({
|
|
46
60
|
display: 'none',
|
|
47
61
|
alignItems: 'center',
|
|
@@ -106,6 +120,24 @@ const PanelActions = ({ editHandlers, readHandlers, viewQueriesHandler, extra, t
|
|
|
106
120
|
}, [
|
|
107
121
|
queryResults
|
|
108
122
|
]);
|
|
123
|
+
const noticesIndicator = (0, _react.useMemo)(()=>{
|
|
124
|
+
const notices = queryResults.flatMap((q)=>{
|
|
125
|
+
return q.data?.metadata?.notices ?? [];
|
|
126
|
+
});
|
|
127
|
+
if (notices.length > 0) {
|
|
128
|
+
const lastNotice = notices[notices.length - 1];
|
|
129
|
+
return /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.InfoTooltip, {
|
|
130
|
+
description: lastNotice.message,
|
|
131
|
+
children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_HeaderIconButton.HeaderIconButton, {
|
|
132
|
+
"aria-label": "panel notices",
|
|
133
|
+
size: "small",
|
|
134
|
+
children: noticeTypeToIcon[lastNotice.type]
|
|
135
|
+
})
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}, [
|
|
139
|
+
queryResults
|
|
140
|
+
]);
|
|
109
141
|
const readActions = (0, _react.useMemo)(()=>{
|
|
110
142
|
if (readHandlers !== undefined) {
|
|
111
143
|
return /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.InfoTooltip, {
|
|
@@ -253,6 +285,8 @@ const PanelActions = ({ editHandlers, readHandlers, viewQueriesHandler, extra, t
|
|
|
253
285
|
" ",
|
|
254
286
|
queryStateIndicator,
|
|
255
287
|
" ",
|
|
288
|
+
noticesIndicator,
|
|
289
|
+
" ",
|
|
256
290
|
extraActions,
|
|
257
291
|
" ",
|
|
258
292
|
viewQueryAction,
|
|
@@ -284,6 +318,7 @@ const PanelActions = ({ editHandlers, readHandlers, viewQueriesHandler, extra, t
|
|
|
284
318
|
divider,
|
|
285
319
|
" ",
|
|
286
320
|
queryStateIndicator,
|
|
321
|
+
noticesIndicator,
|
|
287
322
|
/*#__PURE__*/ (0, _jsxruntime.jsxs)(OnHover, {
|
|
288
323
|
children: [
|
|
289
324
|
extraActions,
|
|
@@ -322,6 +357,7 @@ const PanelActions = ({ editHandlers, readHandlers, viewQueriesHandler, extra, t
|
|
|
322
357
|
divider,
|
|
323
358
|
" ",
|
|
324
359
|
queryStateIndicator,
|
|
360
|
+
noticesIndicator,
|
|
325
361
|
/*#__PURE__*/ (0, _jsxruntime.jsxs)(OnHover, {
|
|
326
362
|
children: [
|
|
327
363
|
extraActions,
|
|
@@ -30,6 +30,8 @@ function PanelPluginLoader(props) {
|
|
|
30
30
|
});
|
|
31
31
|
const PanelComponent = plugin?.PanelComponent;
|
|
32
32
|
const supportedQueryTypes = plugin?.supportedQueryTypes || [];
|
|
33
|
+
// Clear out the queryResults parameter for plugins which don't support any query types
|
|
34
|
+
const supportedQueryResults = supportedQueryTypes.length > 0 ? queryResults : [];
|
|
33
35
|
// Show fullsize skeleton if the panel plugin is loading.
|
|
34
36
|
if (isPanelLoading) {
|
|
35
37
|
return /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Skeleton, {
|
|
@@ -42,7 +44,7 @@ function PanelPluginLoader(props) {
|
|
|
42
44
|
if (PanelComponent === undefined) {
|
|
43
45
|
throw new Error(`Missing PanelComponent from panel plugin for kind '${kind}'`);
|
|
44
46
|
}
|
|
45
|
-
for (const queryResult of
|
|
47
|
+
for (const queryResult of supportedQueryResults){
|
|
46
48
|
if (!supportedQueryTypes.includes(queryResult.definition.kind)) {
|
|
47
49
|
throw new Error(`This panel does not support queries of type '${queryResult.definition.kind}'. Supported query types: ${supportedQueryTypes.join(', ')}.`);
|
|
48
50
|
}
|
|
@@ -51,6 +53,6 @@ function PanelPluginLoader(props) {
|
|
|
51
53
|
spec: spec,
|
|
52
54
|
contentDimensions: contentDimensions,
|
|
53
55
|
definition: definition,
|
|
54
|
-
queryResults:
|
|
56
|
+
queryResults: supportedQueryResults
|
|
55
57
|
});
|
|
56
58
|
}
|
|
@@ -41,7 +41,6 @@ const _usePanelEditor = require("./usePanelEditor");
|
|
|
41
41
|
const _PanelQueriesSharedControls = require("./PanelQueriesSharedControls");
|
|
42
42
|
function PanelEditorForm(props) {
|
|
43
43
|
const { initialValues, initialAction, onSave, onClose } = props;
|
|
44
|
-
const pluginEditorRef = (0, _react.useRef)(null);
|
|
45
44
|
const panelGroups = (0, _context.useListPanelGroups)();
|
|
46
45
|
const { panelDefinition, setName, setDescription, setLinks, setQueries, setPlugin, setPanelDefinition } = (0, _usePanelEditor.usePanelEditor)(initialValues.panelDefinition);
|
|
47
46
|
const { plugin } = panelDefinition.spec;
|
|
@@ -128,7 +127,6 @@ function PanelEditorForm(props) {
|
|
|
128
127
|
name: 'panelDefinition.spec.plugin.kind'
|
|
129
128
|
});
|
|
130
129
|
const handleSubmit = (0, _react.useCallback)(()=>{
|
|
131
|
-
pluginEditorRef.current?.flushChanges?.();
|
|
132
130
|
form.handleSubmit(processForm)();
|
|
133
131
|
}, [
|
|
134
132
|
form,
|
|
@@ -29,16 +29,31 @@ const _react = require("react");
|
|
|
29
29
|
function PanelQueriesSharedControls({ plugin, control, panelDefinition, onQueriesChange, onPluginSpecChange, onJSONChange }) {
|
|
30
30
|
const { data: pluginPreview } = (0, _pluginsystem.usePlugin)('Panel', plugin.kind);
|
|
31
31
|
const panelEditorContext = (0, _react.useContext)(_dashboards.PanelEditorContext);
|
|
32
|
-
const pluginQueryOptions = typeof pluginPreview?.queryOptions === 'function' ? pluginPreview?.queryOptions(panelDefinition.spec.plugin.spec) : pluginPreview?.queryOptions;
|
|
33
32
|
const suggestedStepMs = (0, _pluginsystem.useSuggestedStepMs)(panelEditorContext?.preview.previewPanelWidth);
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
const pluginQueryOptions = (0, _react.useMemo)(()=>typeof pluginPreview?.queryOptions === 'function' ? pluginPreview?.queryOptions(panelDefinition.spec.plugin.spec) : pluginPreview?.queryOptions, [
|
|
34
|
+
panelDefinition.spec.plugin.spec,
|
|
35
|
+
pluginPreview
|
|
36
|
+
]);
|
|
37
|
+
const [previewDefinition, setPreviewDefinition] = (0, _react.useState)(()=>panelDefinition.spec.queries?.map((query)=>{
|
|
38
|
+
return {
|
|
39
|
+
kind: query.spec.plugin.kind,
|
|
40
|
+
spec: query.spec.plugin.spec
|
|
41
|
+
};
|
|
42
|
+
}) ?? []);
|
|
43
|
+
const handleRunQuery = (0, _react.useCallback)((index, newDef)=>{
|
|
44
|
+
setPreviewDefinition((prev)=>{
|
|
45
|
+
const newDefinitions = [
|
|
46
|
+
...prev
|
|
47
|
+
];
|
|
48
|
+
newDefinitions[index] = {
|
|
49
|
+
kind: newDef.spec.plugin.kind,
|
|
50
|
+
spec: newDef.spec.plugin.spec
|
|
51
|
+
};
|
|
52
|
+
return newDefinitions;
|
|
53
|
+
});
|
|
54
|
+
}, []);
|
|
40
55
|
return /*#__PURE__*/ (0, _jsxruntime.jsxs)(_pluginsystem.DataQueriesProvider, {
|
|
41
|
-
definitions:
|
|
56
|
+
definitions: previewDefinition,
|
|
42
57
|
options: {
|
|
43
58
|
suggestedStepMs,
|
|
44
59
|
...pluginQueryOptions
|
|
@@ -71,6 +86,7 @@ function PanelQueriesSharedControls({ plugin, control, panelDefinition, onQuerie
|
|
|
71
86
|
panelDefinition: panelDefinition,
|
|
72
87
|
onJSONChange: onJSONChange,
|
|
73
88
|
onQueriesChange: onQueriesChange,
|
|
89
|
+
onQueryRun: handleRunQuery,
|
|
74
90
|
onPluginSpecChange: onPluginSpecChange
|
|
75
91
|
})
|
|
76
92
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PanelActions.d.ts","sourceRoot":"","sources":["../../../src/components/Panel/PanelActions.tsx"],"names":[],"mappings":"AAcA,OAAO,EAAqC,SAAS,EAAqB,MAAM,OAAO,CAAC;AAExF,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"PanelActions.d.ts","sourceRoot":"","sources":["../../../src/components/Panel/PanelActions.tsx"],"names":[],"mappings":"AAcA,OAAO,EAAqC,SAAS,EAAqB,MAAM,OAAO,CAAC;AAExF,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAYtD,OAAO,EAAE,IAAI,EAAU,MAAM,kBAAkB,CAAC;AAUhD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAQvC,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;IACf,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,YAAY,CAAC,EAAE;QACb,gBAAgB,EAAE,MAAM,IAAI,CAAC;QAC7B,qBAAqB,EAAE,MAAM,IAAI,CAAC;QAClC,kBAAkB,EAAE,MAAM,IAAI,CAAC;KAChC,CAAC;IACF,YAAY,CAAC,EAAE;QACb,aAAa,CAAC,EAAE,OAAO,CAAC;QACxB,gBAAgB,EAAE,MAAM,IAAI,CAAC;KAC9B,CAAC;IACF,kBAAkB,CAAC,EAAE;QACnB,OAAO,EAAE,MAAM,IAAI,CAAC;KACrB,CAAC;IACF,YAAY,EAAE,SAAS,EAAE,CAAC;IAC1B,aAAa,CAAC,EAAE,SAAS,EAAE,CAAC;IAC5B,SAAS,EAAE,YAAY,CAAC,WAAW,CAAC,CAAC;CACtC;AASD,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAsPpD,CAAC"}
|
|
@@ -23,10 +23,24 @@ import DragIcon from 'mdi-material-ui/DragVertical';
|
|
|
23
23
|
import ContentCopyIcon from 'mdi-material-ui/ContentCopy';
|
|
24
24
|
import MenuIcon from 'mdi-material-ui/Menu';
|
|
25
25
|
import AlertIcon from 'mdi-material-ui/Alert';
|
|
26
|
+
import AlertCircleIcon from 'mdi-material-ui/AlertCircle';
|
|
26
27
|
import InformationOutlineIcon from 'mdi-material-ui/InformationOutline';
|
|
27
28
|
import { ARIA_LABEL_TEXT, HEADER_ACTIONS_CONTAINER_NAME, HEADER_MEDIUM_WIDTH, HEADER_SMALL_WIDTH, TOOLTIP_TEXT } from '../../constants';
|
|
28
29
|
import { HeaderIconButton } from './HeaderIconButton';
|
|
29
30
|
import { PanelLinks } from './PanelLinks';
|
|
31
|
+
const noticeTypeToIcon = {
|
|
32
|
+
error: /*#__PURE__*/ _jsx(AlertCircleIcon, {
|
|
33
|
+
color: "error"
|
|
34
|
+
}),
|
|
35
|
+
warning: /*#__PURE__*/ _jsx(AlertIcon, {
|
|
36
|
+
fontSize: "inherit",
|
|
37
|
+
color: "warning"
|
|
38
|
+
}),
|
|
39
|
+
info: /*#__PURE__*/ _jsx(InformationOutlineIcon, {
|
|
40
|
+
fontSize: "inherit",
|
|
41
|
+
color: "info"
|
|
42
|
+
})
|
|
43
|
+
};
|
|
30
44
|
const ConditionalBox = styled(Box)({
|
|
31
45
|
display: 'none',
|
|
32
46
|
alignItems: 'center',
|
|
@@ -91,6 +105,24 @@ export const PanelActions = ({ editHandlers, readHandlers, viewQueriesHandler, e
|
|
|
91
105
|
}, [
|
|
92
106
|
queryResults
|
|
93
107
|
]);
|
|
108
|
+
const noticesIndicator = useMemo(()=>{
|
|
109
|
+
const notices = queryResults.flatMap((q)=>{
|
|
110
|
+
return q.data?.metadata?.notices ?? [];
|
|
111
|
+
});
|
|
112
|
+
if (notices.length > 0) {
|
|
113
|
+
const lastNotice = notices[notices.length - 1];
|
|
114
|
+
return /*#__PURE__*/ _jsx(InfoTooltip, {
|
|
115
|
+
description: lastNotice.message,
|
|
116
|
+
children: /*#__PURE__*/ _jsx(HeaderIconButton, {
|
|
117
|
+
"aria-label": "panel notices",
|
|
118
|
+
size: "small",
|
|
119
|
+
children: noticeTypeToIcon[lastNotice.type]
|
|
120
|
+
})
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}, [
|
|
124
|
+
queryResults
|
|
125
|
+
]);
|
|
94
126
|
const readActions = useMemo(()=>{
|
|
95
127
|
if (readHandlers !== undefined) {
|
|
96
128
|
return /*#__PURE__*/ _jsx(InfoTooltip, {
|
|
@@ -238,6 +270,8 @@ export const PanelActions = ({ editHandlers, readHandlers, viewQueriesHandler, e
|
|
|
238
270
|
" ",
|
|
239
271
|
queryStateIndicator,
|
|
240
272
|
" ",
|
|
273
|
+
noticesIndicator,
|
|
274
|
+
" ",
|
|
241
275
|
extraActions,
|
|
242
276
|
" ",
|
|
243
277
|
viewQueryAction,
|
|
@@ -269,6 +303,7 @@ export const PanelActions = ({ editHandlers, readHandlers, viewQueriesHandler, e
|
|
|
269
303
|
divider,
|
|
270
304
|
" ",
|
|
271
305
|
queryStateIndicator,
|
|
306
|
+
noticesIndicator,
|
|
272
307
|
/*#__PURE__*/ _jsxs(OnHover, {
|
|
273
308
|
children: [
|
|
274
309
|
extraActions,
|
|
@@ -307,6 +342,7 @@ export const PanelActions = ({ editHandlers, readHandlers, viewQueriesHandler, e
|
|
|
307
342
|
divider,
|
|
308
343
|
" ",
|
|
309
344
|
queryStateIndicator,
|
|
345
|
+
noticesIndicator,
|
|
310
346
|
/*#__PURE__*/ _jsxs(OnHover, {
|
|
311
347
|
children: [
|
|
312
348
|
extraActions,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/Panel/PanelActions.tsx"],"sourcesContent":["// Copyright 2025 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 { Stack, Box, Popover, CircularProgress, styled, PopoverPosition } from '@mui/material';\nimport { isValidElement, PropsWithChildren, ReactNode, useMemo, useState } from 'react';\nimport { InfoTooltip } from '@perses-dev/components';\nimport { QueryData } from '@perses-dev/plugin-system';\nimport DatabaseSearch from 'mdi-material-ui/DatabaseSearch';\nimport ArrowCollapseIcon from 'mdi-material-ui/ArrowCollapse';\nimport ArrowExpandIcon from 'mdi-material-ui/ArrowExpand';\nimport PencilIcon from 'mdi-material-ui/PencilOutline';\nimport DeleteIcon from 'mdi-material-ui/DeleteOutline';\nimport DragIcon from 'mdi-material-ui/DragVertical';\nimport ContentCopyIcon from 'mdi-material-ui/ContentCopy';\nimport MenuIcon from 'mdi-material-ui/Menu';\nimport AlertIcon from 'mdi-material-ui/Alert';\nimport InformationOutlineIcon from 'mdi-material-ui/InformationOutline';\nimport { Link } from '@perses-dev/core';\nimport {\n ARIA_LABEL_TEXT,\n HEADER_ACTIONS_CONTAINER_NAME,\n HEADER_MEDIUM_WIDTH,\n HEADER_SMALL_WIDTH,\n TOOLTIP_TEXT,\n} from '../../constants';\nimport { HeaderIconButton } from './HeaderIconButton';\nimport { PanelLinks } from './PanelLinks';\nimport { PanelOptions } from './Panel';\n\nexport interface PanelActionsProps {\n title: string;\n description?: string;\n descriptionTooltipId: string;\n links?: Link[];\n extra?: React.ReactNode;\n editHandlers?: {\n onEditPanelClick: () => void;\n onDuplicatePanelClick: () => void;\n onDeletePanelClick: () => void;\n };\n readHandlers?: {\n isPanelViewed?: boolean;\n onViewPanelClick: () => void;\n };\n viewQueriesHandler?: {\n onClick: () => void;\n };\n queryResults: QueryData[];\n pluginActions?: ReactNode[];\n showIcons: PanelOptions['showIcons'];\n}\n\nconst ConditionalBox = styled(Box)({\n display: 'none',\n alignItems: 'center',\n flexGrow: 1,\n justifyContent: 'flex-end',\n});\n\nexport const PanelActions: React.FC<PanelActionsProps> = ({\n editHandlers,\n readHandlers,\n viewQueriesHandler,\n extra,\n title,\n description,\n descriptionTooltipId,\n links,\n queryResults,\n pluginActions = [],\n showIcons,\n}) => {\n const descriptionAction = useMemo((): ReactNode | undefined => {\n if (description && description.trim().length > 0) {\n return (\n <InfoTooltip id={descriptionTooltipId} description={description} enterDelay={100}>\n <HeaderIconButton aria-label=\"panel description\" size=\"small\">\n <InformationOutlineIcon\n aria-describedby=\"info-tooltip\"\n aria-hidden={false}\n fontSize=\"inherit\"\n sx={{ color: (theme) => theme.palette.text.secondary }}\n />\n </HeaderIconButton>\n </InfoTooltip>\n );\n }\n return undefined;\n }, [descriptionTooltipId, description]);\n\n const linksAction = links && links.length > 0 && <PanelLinks links={links} />;\n const extraActions = editHandlers === undefined && extra;\n\n const queryStateIndicator = useMemo((): ReactNode | undefined => {\n const hasData = queryResults.some((q) => q.data);\n const isFetching = queryResults.some((q) => q.isFetching);\n const queryErrors = queryResults.filter((q) => q.error);\n\n if (isFetching && hasData) {\n return <CircularProgress aria-label=\"loading\" size=\"1.125rem\" />;\n } else if (queryErrors.length > 0) {\n const errorTexts = queryErrors\n .map((q) => q.error)\n .map((e) => e.message)\n .join('\\n');\n\n return (\n <InfoTooltip description={errorTexts}>\n <HeaderIconButton aria-label=\"panel errors\" size=\"small\">\n <AlertIcon\n fontSize=\"inherit\"\n sx={{\n color: (theme) => theme.palette.error.main,\n }}\n />\n </HeaderIconButton>\n </InfoTooltip>\n );\n }\n }, [queryResults]);\n\n const readActions = useMemo((): ReactNode | undefined => {\n if (readHandlers !== undefined) {\n return (\n <InfoTooltip description={TOOLTIP_TEXT.viewPanel}>\n <HeaderIconButton\n aria-label={ARIA_LABEL_TEXT.viewPanel(title)}\n size=\"small\"\n onClick={readHandlers.onViewPanelClick}\n >\n {readHandlers.isPanelViewed ? (\n <ArrowCollapseIcon fontSize=\"inherit\" />\n ) : (\n <ArrowExpandIcon fontSize=\"inherit\" />\n )}\n </HeaderIconButton>\n </InfoTooltip>\n );\n }\n return undefined;\n }, [readHandlers, title]);\n\n const viewQueryAction = useMemo(() => {\n if (!viewQueriesHandler?.onClick) return null;\n return (\n <InfoTooltip description={TOOLTIP_TEXT.queryView}>\n <HeaderIconButton\n aria-label={ARIA_LABEL_TEXT.openQueryView(title)}\n size=\"small\"\n onClick={viewQueriesHandler.onClick}\n >\n <DatabaseSearch fontSize=\"inherit\" />\n </HeaderIconButton>\n </InfoTooltip>\n );\n }, [viewQueriesHandler, title]);\n\n const editActions = useMemo((): ReactNode | undefined => {\n if (editHandlers !== undefined) {\n // If there are edit handlers, always just show the edit buttons\n return (\n <>\n <InfoTooltip description={TOOLTIP_TEXT.editPanel}>\n <HeaderIconButton\n aria-label={ARIA_LABEL_TEXT.editPanel(title)}\n size=\"small\"\n onClick={editHandlers.onEditPanelClick}\n >\n <PencilIcon fontSize=\"inherit\" />\n </HeaderIconButton>\n </InfoTooltip>\n <InfoTooltip description={TOOLTIP_TEXT.duplicatePanel}>\n <HeaderIconButton\n aria-label={ARIA_LABEL_TEXT.duplicatePanel(title)}\n size=\"small\"\n onClick={editHandlers.onDuplicatePanelClick}\n >\n <ContentCopyIcon\n fontSize=\"inherit\"\n sx={{\n // Shrink this icon a little bit to look more consistent\n // with the other icons in the header.\n transform: 'scale(0.925)',\n }}\n />\n </HeaderIconButton>\n </InfoTooltip>\n <InfoTooltip description={TOOLTIP_TEXT.deletePanel}>\n <HeaderIconButton\n aria-label={ARIA_LABEL_TEXT.deletePanel(title)}\n size=\"small\"\n onClick={editHandlers.onDeletePanelClick}\n >\n <DeleteIcon fontSize=\"inherit\" />\n </HeaderIconButton>\n </InfoTooltip>\n </>\n );\n }\n return undefined;\n }, [editHandlers, title]);\n\n const moveAction = useMemo((): ReactNode | undefined => {\n if (editActions && !readHandlers?.isPanelViewed) {\n return (\n <InfoTooltip description={TOOLTIP_TEXT.movePanel}>\n <HeaderIconButton aria-label={ARIA_LABEL_TEXT.movePanel(title)} size=\"small\">\n <DragIcon className=\"drag-handle\" sx={{ cursor: 'grab' }} fontSize=\"inherit\" />\n </HeaderIconButton>\n </InfoTooltip>\n );\n }\n return undefined;\n }, [editActions, readHandlers, title]);\n\n const divider = <Box sx={{ flexGrow: 1 }}></Box>;\n\n // By default, the panel header shows certain icons only on hover if the panel is in non-editing, non-fullscreen mode\n const OnHover = ({ children }: PropsWithChildren): ReactNode =>\n showIcons === 'hover' ? <Box sx={{ display: 'var(--panel-hover, none)' }}>{children}</Box> : <>{children}</>;\n\n return (\n <>\n {/* small panel width: move all icons except move/grab to overflow menu */}\n <ConditionalBox\n sx={(theme) => ({\n [theme.containerQueries(HEADER_ACTIONS_CONTAINER_NAME).between(0, HEADER_SMALL_WIDTH)]: { display: 'flex' },\n })}\n >\n {divider}\n <OnHover>\n <OverflowMenu title={title}>\n {descriptionAction} {linksAction} {queryStateIndicator} {extraActions} {viewQueryAction}\n {readActions} {pluginActions}\n {editActions}\n </OverflowMenu>\n {moveAction}\n </OnHover>\n </ConditionalBox>\n\n {/* medium panel width: move edit icons to overflow menu */}\n <ConditionalBox\n sx={(theme) => ({\n [theme.containerQueries(HEADER_ACTIONS_CONTAINER_NAME).between(HEADER_SMALL_WIDTH, HEADER_MEDIUM_WIDTH)]: {\n display: 'flex',\n },\n })}\n >\n <OnHover>\n {descriptionAction} {linksAction}\n </OnHover>\n {divider} {queryStateIndicator}\n <OnHover>\n {extraActions}\n {readActions}\n <OverflowMenu title={title}>\n {editActions} {viewQueryAction} {pluginActions}\n </OverflowMenu>\n {moveAction}\n </OnHover>\n </ConditionalBox>\n\n {/* large panel width: show all icons in panel header */}\n <ConditionalBox\n sx={(theme) => ({\n // flip the logic here; if the browser (or jsdom) does not support container queries, always show all icons\n display: 'flex',\n [theme.containerQueries(HEADER_ACTIONS_CONTAINER_NAME).down(HEADER_MEDIUM_WIDTH)]: { display: 'none' },\n })}\n >\n <OnHover>\n {descriptionAction} {linksAction}\n </OnHover>\n {divider} {queryStateIndicator}\n <OnHover>\n {extraActions}\n {viewQueryAction}\n {readActions} {editActions}\n {/* Show plugin actions inside a menu if it gets crowded */}\n {pluginActions.length <= 1 ? pluginActions : <OverflowMenu title={title}>{pluginActions}</OverflowMenu>}\n {moveAction}\n </OnHover>\n </ConditionalBox>\n </>\n );\n};\n\nconst OverflowMenu: React.FC<PropsWithChildren<{ title: string }>> = ({ children, title }) => {\n const [anchorPosition, setAnchorPosition] = useState<PopoverPosition>();\n\n // do not show overflow menu if there is no content (for example, edit actions are hidden)\n const hasContent = isValidElement(children) || (Array.isArray(children) && children.some(isValidElement));\n if (!hasContent) {\n return null;\n }\n\n const handleClick = (event: React.MouseEvent<HTMLElement>): void => {\n setAnchorPosition(event.currentTarget.getBoundingClientRect());\n };\n\n const handleClose = (): void => {\n setAnchorPosition(undefined);\n };\n\n const open = Boolean(anchorPosition);\n const id = open ? 'actions-menu' : undefined;\n\n return (\n <>\n <HeaderIconButton\n className=\"show-actions\"\n aria-describedby={id}\n onClick={handleClick}\n aria-label={ARIA_LABEL_TEXT.showPanelActions(title)}\n size=\"small\"\n >\n <MenuIcon fontSize=\"inherit\" />\n </HeaderIconButton>\n <Popover\n id={id}\n open={open}\n anchorReference=\"anchorPosition\"\n anchorPosition={anchorPosition}\n onClose={handleClose}\n anchorOrigin={{\n vertical: 'bottom',\n horizontal: 'left',\n }}\n >\n <Stack direction=\"row\" alignItems=\"center\" sx={{ padding: 1 }} onClick={handleClose}>\n {children}\n </Stack>\n </Popover>\n </>\n );\n};\n"],"names":["Stack","Box","Popover","CircularProgress","styled","isValidElement","useMemo","useState","InfoTooltip","DatabaseSearch","ArrowCollapseIcon","ArrowExpandIcon","PencilIcon","DeleteIcon","DragIcon","ContentCopyIcon","MenuIcon","AlertIcon","InformationOutlineIcon","ARIA_LABEL_TEXT","HEADER_ACTIONS_CONTAINER_NAME","HEADER_MEDIUM_WIDTH","HEADER_SMALL_WIDTH","TOOLTIP_TEXT","HeaderIconButton","PanelLinks","ConditionalBox","display","alignItems","flexGrow","justifyContent","PanelActions","editHandlers","readHandlers","viewQueriesHandler","extra","title","description","descriptionTooltipId","links","queryResults","pluginActions","showIcons","descriptionAction","trim","length","id","enterDelay","aria-label","size","aria-describedby","aria-hidden","fontSize","sx","color","theme","palette","text","secondary","undefined","linksAction","extraActions","queryStateIndicator","hasData","some","q","data","isFetching","queryErrors","filter","error","errorTexts","map","e","message","join","main","readActions","viewPanel","onClick","onViewPanelClick","isPanelViewed","viewQueryAction","queryView","openQueryView","editActions","editPanel","onEditPanelClick","duplicatePanel","onDuplicatePanelClick","transform","deletePanel","onDeletePanelClick","moveAction","movePanel","className","cursor","divider","OnHover","children","containerQueries","between","OverflowMenu","down","anchorPosition","setAnchorPosition","hasContent","Array","isArray","handleClick","event","currentTarget","getBoundingClientRect","handleClose","open","Boolean","showPanelActions","anchorReference","onClose","anchorOrigin","vertical","horizontal","direction","padding"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/Panel/PanelActions.tsx"],"sourcesContent":["// Copyright 2025 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 { Stack, Box, Popover, CircularProgress, styled, PopoverPosition } from '@mui/material';\nimport { isValidElement, PropsWithChildren, ReactNode, useMemo, useState } from 'react';\nimport { InfoTooltip } from '@perses-dev/components';\nimport { QueryData } from '@perses-dev/plugin-system';\nimport DatabaseSearch from 'mdi-material-ui/DatabaseSearch';\nimport ArrowCollapseIcon from 'mdi-material-ui/ArrowCollapse';\nimport ArrowExpandIcon from 'mdi-material-ui/ArrowExpand';\nimport PencilIcon from 'mdi-material-ui/PencilOutline';\nimport DeleteIcon from 'mdi-material-ui/DeleteOutline';\nimport DragIcon from 'mdi-material-ui/DragVertical';\nimport ContentCopyIcon from 'mdi-material-ui/ContentCopy';\nimport MenuIcon from 'mdi-material-ui/Menu';\nimport AlertIcon from 'mdi-material-ui/Alert';\nimport AlertCircleIcon from 'mdi-material-ui/AlertCircle';\nimport InformationOutlineIcon from 'mdi-material-ui/InformationOutline';\nimport { Link, Notice } from '@perses-dev/core';\nimport {\n ARIA_LABEL_TEXT,\n HEADER_ACTIONS_CONTAINER_NAME,\n HEADER_MEDIUM_WIDTH,\n HEADER_SMALL_WIDTH,\n TOOLTIP_TEXT,\n} from '../../constants';\nimport { HeaderIconButton } from './HeaderIconButton';\nimport { PanelLinks } from './PanelLinks';\nimport { PanelOptions } from './Panel';\n\nconst noticeTypeToIcon: Record<Notice['type'], ReactNode> = {\n error: <AlertCircleIcon color=\"error\" />,\n warning: <AlertIcon fontSize=\"inherit\" color=\"warning\" />,\n info: <InformationOutlineIcon fontSize=\"inherit\" color=\"info\" />,\n};\n\nexport interface PanelActionsProps {\n title: string;\n description?: string;\n descriptionTooltipId: string;\n links?: Link[];\n extra?: React.ReactNode;\n editHandlers?: {\n onEditPanelClick: () => void;\n onDuplicatePanelClick: () => void;\n onDeletePanelClick: () => void;\n };\n readHandlers?: {\n isPanelViewed?: boolean;\n onViewPanelClick: () => void;\n };\n viewQueriesHandler?: {\n onClick: () => void;\n };\n queryResults: QueryData[];\n pluginActions?: ReactNode[];\n showIcons: PanelOptions['showIcons'];\n}\n\nconst ConditionalBox = styled(Box)({\n display: 'none',\n alignItems: 'center',\n flexGrow: 1,\n justifyContent: 'flex-end',\n});\n\nexport const PanelActions: React.FC<PanelActionsProps> = ({\n editHandlers,\n readHandlers,\n viewQueriesHandler,\n extra,\n title,\n description,\n descriptionTooltipId,\n links,\n queryResults,\n pluginActions = [],\n showIcons,\n}) => {\n const descriptionAction = useMemo((): ReactNode | undefined => {\n if (description && description.trim().length > 0) {\n return (\n <InfoTooltip id={descriptionTooltipId} description={description} enterDelay={100}>\n <HeaderIconButton aria-label=\"panel description\" size=\"small\">\n <InformationOutlineIcon\n aria-describedby=\"info-tooltip\"\n aria-hidden={false}\n fontSize=\"inherit\"\n sx={{ color: (theme) => theme.palette.text.secondary }}\n />\n </HeaderIconButton>\n </InfoTooltip>\n );\n }\n return undefined;\n }, [descriptionTooltipId, description]);\n\n const linksAction = links && links.length > 0 && <PanelLinks links={links} />;\n const extraActions = editHandlers === undefined && extra;\n\n const queryStateIndicator = useMemo((): ReactNode | undefined => {\n const hasData = queryResults.some((q) => q.data);\n const isFetching = queryResults.some((q) => q.isFetching);\n const queryErrors = queryResults.filter((q) => q.error);\n\n if (isFetching && hasData) {\n return <CircularProgress aria-label=\"loading\" size=\"1.125rem\" />;\n } else if (queryErrors.length > 0) {\n const errorTexts = queryErrors\n .map((q) => q.error)\n .map((e) => e.message)\n .join('\\n');\n\n return (\n <InfoTooltip description={errorTexts}>\n <HeaderIconButton aria-label=\"panel errors\" size=\"small\">\n <AlertIcon\n fontSize=\"inherit\"\n sx={{\n color: (theme) => theme.palette.error.main,\n }}\n />\n </HeaderIconButton>\n </InfoTooltip>\n );\n }\n }, [queryResults]);\n\n const noticesIndicator = useMemo(() => {\n const notices = queryResults.flatMap((q) => {\n return q.data?.metadata?.notices ?? [];\n });\n\n if (notices.length > 0) {\n const lastNotice = notices[notices.length - 1]!;\n\n return (\n <InfoTooltip description={lastNotice.message}>\n <HeaderIconButton aria-label=\"panel notices\" size=\"small\">\n {noticeTypeToIcon[lastNotice.type]}\n </HeaderIconButton>\n </InfoTooltip>\n );\n }\n }, [queryResults]);\n\n const readActions = useMemo((): ReactNode | undefined => {\n if (readHandlers !== undefined) {\n return (\n <InfoTooltip description={TOOLTIP_TEXT.viewPanel}>\n <HeaderIconButton\n aria-label={ARIA_LABEL_TEXT.viewPanel(title)}\n size=\"small\"\n onClick={readHandlers.onViewPanelClick}\n >\n {readHandlers.isPanelViewed ? (\n <ArrowCollapseIcon fontSize=\"inherit\" />\n ) : (\n <ArrowExpandIcon fontSize=\"inherit\" />\n )}\n </HeaderIconButton>\n </InfoTooltip>\n );\n }\n return undefined;\n }, [readHandlers, title]);\n\n const viewQueryAction = useMemo(() => {\n if (!viewQueriesHandler?.onClick) return null;\n return (\n <InfoTooltip description={TOOLTIP_TEXT.queryView}>\n <HeaderIconButton\n aria-label={ARIA_LABEL_TEXT.openQueryView(title)}\n size=\"small\"\n onClick={viewQueriesHandler.onClick}\n >\n <DatabaseSearch fontSize=\"inherit\" />\n </HeaderIconButton>\n </InfoTooltip>\n );\n }, [viewQueriesHandler, title]);\n\n const editActions = useMemo((): ReactNode | undefined => {\n if (editHandlers !== undefined) {\n // If there are edit handlers, always just show the edit buttons\n return (\n <>\n <InfoTooltip description={TOOLTIP_TEXT.editPanel}>\n <HeaderIconButton\n aria-label={ARIA_LABEL_TEXT.editPanel(title)}\n size=\"small\"\n onClick={editHandlers.onEditPanelClick}\n >\n <PencilIcon fontSize=\"inherit\" />\n </HeaderIconButton>\n </InfoTooltip>\n <InfoTooltip description={TOOLTIP_TEXT.duplicatePanel}>\n <HeaderIconButton\n aria-label={ARIA_LABEL_TEXT.duplicatePanel(title)}\n size=\"small\"\n onClick={editHandlers.onDuplicatePanelClick}\n >\n <ContentCopyIcon\n fontSize=\"inherit\"\n sx={{\n // Shrink this icon a little bit to look more consistent\n // with the other icons in the header.\n transform: 'scale(0.925)',\n }}\n />\n </HeaderIconButton>\n </InfoTooltip>\n <InfoTooltip description={TOOLTIP_TEXT.deletePanel}>\n <HeaderIconButton\n aria-label={ARIA_LABEL_TEXT.deletePanel(title)}\n size=\"small\"\n onClick={editHandlers.onDeletePanelClick}\n >\n <DeleteIcon fontSize=\"inherit\" />\n </HeaderIconButton>\n </InfoTooltip>\n </>\n );\n }\n return undefined;\n }, [editHandlers, title]);\n\n const moveAction = useMemo((): ReactNode | undefined => {\n if (editActions && !readHandlers?.isPanelViewed) {\n return (\n <InfoTooltip description={TOOLTIP_TEXT.movePanel}>\n <HeaderIconButton aria-label={ARIA_LABEL_TEXT.movePanel(title)} size=\"small\">\n <DragIcon className=\"drag-handle\" sx={{ cursor: 'grab' }} fontSize=\"inherit\" />\n </HeaderIconButton>\n </InfoTooltip>\n );\n }\n return undefined;\n }, [editActions, readHandlers, title]);\n\n const divider = <Box sx={{ flexGrow: 1 }}></Box>;\n\n // By default, the panel header shows certain icons only on hover if the panel is in non-editing, non-fullscreen mode\n const OnHover = ({ children }: PropsWithChildren): ReactNode =>\n showIcons === 'hover' ? <Box sx={{ display: 'var(--panel-hover, none)' }}>{children}</Box> : <>{children}</>;\n\n return (\n <>\n {/* small panel width: move all icons except move/grab to overflow menu */}\n <ConditionalBox\n sx={(theme) => ({\n [theme.containerQueries(HEADER_ACTIONS_CONTAINER_NAME).between(0, HEADER_SMALL_WIDTH)]: { display: 'flex' },\n })}\n >\n {divider}\n <OnHover>\n <OverflowMenu title={title}>\n {descriptionAction} {linksAction} {queryStateIndicator} {noticesIndicator} {extraActions} {viewQueryAction}\n {readActions} {pluginActions}\n {editActions}\n </OverflowMenu>\n {moveAction}\n </OnHover>\n </ConditionalBox>\n\n {/* medium panel width: move edit icons to overflow menu */}\n <ConditionalBox\n sx={(theme) => ({\n [theme.containerQueries(HEADER_ACTIONS_CONTAINER_NAME).between(HEADER_SMALL_WIDTH, HEADER_MEDIUM_WIDTH)]: {\n display: 'flex',\n },\n })}\n >\n <OnHover>\n {descriptionAction} {linksAction}\n </OnHover>\n {divider} {queryStateIndicator}\n {noticesIndicator}\n <OnHover>\n {extraActions}\n {readActions}\n <OverflowMenu title={title}>\n {editActions} {viewQueryAction} {pluginActions}\n </OverflowMenu>\n {moveAction}\n </OnHover>\n </ConditionalBox>\n\n {/* large panel width: show all icons in panel header */}\n <ConditionalBox\n sx={(theme) => ({\n // flip the logic here; if the browser (or jsdom) does not support container queries, always show all icons\n display: 'flex',\n [theme.containerQueries(HEADER_ACTIONS_CONTAINER_NAME).down(HEADER_MEDIUM_WIDTH)]: { display: 'none' },\n })}\n >\n <OnHover>\n {descriptionAction} {linksAction}\n </OnHover>\n {divider} {queryStateIndicator}\n {noticesIndicator}\n <OnHover>\n {extraActions}\n {viewQueryAction}\n {readActions} {editActions}\n {/* Show plugin actions inside a menu if it gets crowded */}\n {pluginActions.length <= 1 ? pluginActions : <OverflowMenu title={title}>{pluginActions}</OverflowMenu>}\n {moveAction}\n </OnHover>\n </ConditionalBox>\n </>\n );\n};\n\nconst OverflowMenu: React.FC<PropsWithChildren<{ title: string }>> = ({ children, title }) => {\n const [anchorPosition, setAnchorPosition] = useState<PopoverPosition>();\n\n // do not show overflow menu if there is no content (for example, edit actions are hidden)\n const hasContent = isValidElement(children) || (Array.isArray(children) && children.some(isValidElement));\n if (!hasContent) {\n return null;\n }\n\n const handleClick = (event: React.MouseEvent<HTMLElement>): void => {\n setAnchorPosition(event.currentTarget.getBoundingClientRect());\n };\n\n const handleClose = (): void => {\n setAnchorPosition(undefined);\n };\n\n const open = Boolean(anchorPosition);\n const id = open ? 'actions-menu' : undefined;\n\n return (\n <>\n <HeaderIconButton\n className=\"show-actions\"\n aria-describedby={id}\n onClick={handleClick}\n aria-label={ARIA_LABEL_TEXT.showPanelActions(title)}\n size=\"small\"\n >\n <MenuIcon fontSize=\"inherit\" />\n </HeaderIconButton>\n <Popover\n id={id}\n open={open}\n anchorReference=\"anchorPosition\"\n anchorPosition={anchorPosition}\n onClose={handleClose}\n anchorOrigin={{\n vertical: 'bottom',\n horizontal: 'left',\n }}\n >\n <Stack direction=\"row\" alignItems=\"center\" sx={{ padding: 1 }} onClick={handleClose}>\n {children}\n </Stack>\n </Popover>\n </>\n );\n};\n"],"names":["Stack","Box","Popover","CircularProgress","styled","isValidElement","useMemo","useState","InfoTooltip","DatabaseSearch","ArrowCollapseIcon","ArrowExpandIcon","PencilIcon","DeleteIcon","DragIcon","ContentCopyIcon","MenuIcon","AlertIcon","AlertCircleIcon","InformationOutlineIcon","ARIA_LABEL_TEXT","HEADER_ACTIONS_CONTAINER_NAME","HEADER_MEDIUM_WIDTH","HEADER_SMALL_WIDTH","TOOLTIP_TEXT","HeaderIconButton","PanelLinks","noticeTypeToIcon","error","color","warning","fontSize","info","ConditionalBox","display","alignItems","flexGrow","justifyContent","PanelActions","editHandlers","readHandlers","viewQueriesHandler","extra","title","description","descriptionTooltipId","links","queryResults","pluginActions","showIcons","descriptionAction","trim","length","id","enterDelay","aria-label","size","aria-describedby","aria-hidden","sx","theme","palette","text","secondary","undefined","linksAction","extraActions","queryStateIndicator","hasData","some","q","data","isFetching","queryErrors","filter","errorTexts","map","e","message","join","main","noticesIndicator","notices","flatMap","metadata","lastNotice","type","readActions","viewPanel","onClick","onViewPanelClick","isPanelViewed","viewQueryAction","queryView","openQueryView","editActions","editPanel","onEditPanelClick","duplicatePanel","onDuplicatePanelClick","transform","deletePanel","onDeletePanelClick","moveAction","movePanel","className","cursor","divider","OnHover","children","containerQueries","between","OverflowMenu","down","anchorPosition","setAnchorPosition","hasContent","Array","isArray","handleClick","event","currentTarget","getBoundingClientRect","handleClose","open","Boolean","showPanelActions","anchorReference","onClose","anchorOrigin","vertical","horizontal","direction","padding"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PanelPluginLoader.d.ts","sourceRoot":"","sources":["../../../src/components/Panel/PanelPluginLoader.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAa,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAGrC,UAAU,gBAAiB,SAAQ,UAAU,CAAC,WAAW,EAAE,aAAa,CAAC;IACvE,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,gBAAgB,GAAG,YAAY,
|
|
1
|
+
{"version":3,"file":"PanelPluginLoader.d.ts","sourceRoot":"","sources":["../../../src/components/Panel/PanelPluginLoader.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAa,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAGrC,UAAU,gBAAiB,SAAQ,UAAU,CAAC,WAAW,EAAE,aAAa,CAAC;IACvE,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,gBAAgB,GAAG,YAAY,CAwCvE"}
|
|
@@ -23,6 +23,8 @@ import { Skeleton } from '@mui/material';
|
|
|
23
23
|
});
|
|
24
24
|
const PanelComponent = plugin?.PanelComponent;
|
|
25
25
|
const supportedQueryTypes = plugin?.supportedQueryTypes || [];
|
|
26
|
+
// Clear out the queryResults parameter for plugins which don't support any query types
|
|
27
|
+
const supportedQueryResults = supportedQueryTypes.length > 0 ? queryResults : [];
|
|
26
28
|
// Show fullsize skeleton if the panel plugin is loading.
|
|
27
29
|
if (isPanelLoading) {
|
|
28
30
|
return /*#__PURE__*/ _jsx(Skeleton, {
|
|
@@ -35,7 +37,7 @@ import { Skeleton } from '@mui/material';
|
|
|
35
37
|
if (PanelComponent === undefined) {
|
|
36
38
|
throw new Error(`Missing PanelComponent from panel plugin for kind '${kind}'`);
|
|
37
39
|
}
|
|
38
|
-
for (const queryResult of
|
|
40
|
+
for (const queryResult of supportedQueryResults){
|
|
39
41
|
if (!supportedQueryTypes.includes(queryResult.definition.kind)) {
|
|
40
42
|
throw new Error(`This panel does not support queries of type '${queryResult.definition.kind}'. Supported query types: ${supportedQueryTypes.join(', ')}.`);
|
|
41
43
|
}
|
|
@@ -44,7 +46,7 @@ import { Skeleton } from '@mui/material';
|
|
|
44
46
|
spec: spec,
|
|
45
47
|
contentDimensions: contentDimensions,
|
|
46
48
|
definition: definition,
|
|
47
|
-
queryResults:
|
|
49
|
+
queryResults: supportedQueryResults
|
|
48
50
|
});
|
|
49
51
|
}
|
|
50
52
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/Panel/PanelPluginLoader.tsx"],"sourcesContent":["// Copyright 2025 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 { usePlugin, PanelProps } from '@perses-dev/plugin-system';\nimport { UnknownSpec, QueryDataType } from '@perses-dev/core';\nimport { ReactElement } from 'react';\nimport { Skeleton } from '@mui/material';\n\ninterface PanelPluginProps extends PanelProps<UnknownSpec, QueryDataType> {\n kind: string;\n}\n\n/**\n * PanelPluginLoader loads the panel plugin specified by the 'kind' prop from the plugin registry and\n * renders its PanelComponent.\n */\nexport function PanelPluginLoader(props: PanelPluginProps): ReactElement {\n const { kind, spec, contentDimensions, definition, queryResults } = props;\n const { data: plugin, isLoading: isPanelLoading } = usePlugin('Panel', kind, { useErrorBoundary: true });\n const PanelComponent = plugin?.PanelComponent;\n const supportedQueryTypes = plugin?.supportedQueryTypes || [];\n\n // Show fullsize skeleton if the panel plugin is loading.\n if (isPanelLoading) {\n return (\n <Skeleton\n variant=\"rectangular\"\n width={contentDimensions?.width}\n height={contentDimensions?.height}\n aria-label=\"Loading...\"\n />\n );\n }\n\n if (PanelComponent === undefined) {\n throw new Error(`Missing PanelComponent from panel plugin for kind '${kind}'`);\n }\n\n for (const queryResult of
|
|
1
|
+
{"version":3,"sources":["../../../src/components/Panel/PanelPluginLoader.tsx"],"sourcesContent":["// Copyright 2025 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 { usePlugin, PanelProps } from '@perses-dev/plugin-system';\nimport { UnknownSpec, QueryDataType } from '@perses-dev/core';\nimport { ReactElement } from 'react';\nimport { Skeleton } from '@mui/material';\n\ninterface PanelPluginProps extends PanelProps<UnknownSpec, QueryDataType> {\n kind: string;\n}\n\n/**\n * PanelPluginLoader loads the panel plugin specified by the 'kind' prop from the plugin registry and\n * renders its PanelComponent.\n */\nexport function PanelPluginLoader(props: PanelPluginProps): ReactElement {\n const { kind, spec, contentDimensions, definition, queryResults } = props;\n const { data: plugin, isLoading: isPanelLoading } = usePlugin('Panel', kind, { useErrorBoundary: true });\n const PanelComponent = plugin?.PanelComponent;\n const supportedQueryTypes = plugin?.supportedQueryTypes || [];\n // Clear out the queryResults parameter for plugins which don't support any query types\n const supportedQueryResults = supportedQueryTypes.length > 0 ? queryResults : [];\n\n // Show fullsize skeleton if the panel plugin is loading.\n if (isPanelLoading) {\n return (\n <Skeleton\n variant=\"rectangular\"\n width={contentDimensions?.width}\n height={contentDimensions?.height}\n aria-label=\"Loading...\"\n />\n );\n }\n\n if (PanelComponent === undefined) {\n throw new Error(`Missing PanelComponent from panel plugin for kind '${kind}'`);\n }\n\n for (const queryResult of supportedQueryResults) {\n if (!supportedQueryTypes.includes(queryResult.definition.kind)) {\n throw new Error(\n `This panel does not support queries of type '${queryResult.definition.kind}'. Supported query types: ${supportedQueryTypes.join(', ')}.`\n );\n }\n }\n\n return (\n <PanelComponent\n spec={spec}\n contentDimensions={contentDimensions}\n definition={definition}\n queryResults={supportedQueryResults}\n />\n );\n}\n"],"names":["usePlugin","Skeleton","PanelPluginLoader","props","kind","spec","contentDimensions","definition","queryResults","data","plugin","isLoading","isPanelLoading","useErrorBoundary","PanelComponent","supportedQueryTypes","supportedQueryResults","length","variant","width","height","aria-label","undefined","Error","queryResult","includes","join"],"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,SAAS,QAAoB,4BAA4B;AAGlE,SAASC,QAAQ,QAAQ,gBAAgB;AAMzC;;;CAGC,GACD,OAAO,SAASC,kBAAkBC,KAAuB;IACvD,MAAM,EAAEC,IAAI,EAAEC,IAAI,EAAEC,iBAAiB,EAAEC,UAAU,EAAEC,YAAY,EAAE,GAAGL;IACpE,MAAM,EAAEM,MAAMC,MAAM,EAAEC,WAAWC,cAAc,EAAE,GAAGZ,UAAU,SAASI,MAAM;QAAES,kBAAkB;IAAK;IACtG,MAAMC,iBAAiBJ,QAAQI;IAC/B,MAAMC,sBAAsBL,QAAQK,uBAAuB,EAAE;IAC7D,uFAAuF;IACvF,MAAMC,wBAAwBD,oBAAoBE,MAAM,GAAG,IAAIT,eAAe,EAAE;IAEhF,yDAAyD;IACzD,IAAII,gBAAgB;QAClB,qBACE,KAACX;YACCiB,SAAQ;YACRC,OAAOb,mBAAmBa;YAC1BC,QAAQd,mBAAmBc;YAC3BC,cAAW;;IAGjB;IAEA,IAAIP,mBAAmBQ,WAAW;QAChC,MAAM,IAAIC,MAAM,CAAC,mDAAmD,EAAEnB,KAAK,CAAC,CAAC;IAC/E;IAEA,KAAK,MAAMoB,eAAeR,sBAAuB;QAC/C,IAAI,CAACD,oBAAoBU,QAAQ,CAACD,YAAYjB,UAAU,CAACH,IAAI,GAAG;YAC9D,MAAM,IAAImB,MACR,CAAC,6CAA6C,EAAEC,YAAYjB,UAAU,CAACH,IAAI,CAAC,0BAA0B,EAAEW,oBAAoBW,IAAI,CAAC,MAAM,CAAC,CAAC;QAE7I;IACF;IAEA,qBACE,KAACZ;QACCT,MAAMA;QACNC,mBAAmBA;QACnBC,YAAYA;QACZC,cAAcQ;;AAGpB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PanelEditorForm.d.ts","sourceRoot":"","sources":["../../../src/components/PanelDrawer/PanelEditorForm.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"PanelEditorForm.d.ts","sourceRoot":"","sources":["../../../src/components/PanelDrawer/PanelEditorForm.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAE,YAAY,EAAoC,MAAM,OAAO,CAAC;AAEvE,OAAO,EAAE,MAAM,EAAmB,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAgB9E,MAAM,WAAW,oBAAoB;IACnC,aAAa,EAAE,iBAAiB,CAAC;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAC5C,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,GAAG,YAAY,CA6NzE;AAED;;GAEG;AACH,eAAO,MAAM,iBAAiB,sBAAsB,CAAC"}
|
|
@@ -11,7 +11,7 @@
|
|
|
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 { useCallback, useEffect,
|
|
14
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
15
15
|
import { Box, Button, Grid, MenuItem, Stack, TextField, Typography } from '@mui/material';
|
|
16
16
|
import { DiscardChangesConfirmationDialog, ErrorAlert, ErrorBoundary } from '@perses-dev/components';
|
|
17
17
|
import { PluginKindSelect, usePluginEditor, getTitleAction, getSubmitText, useValidationSchemas } from '@perses-dev/plugin-system';
|
|
@@ -23,7 +23,6 @@ import { usePanelEditor } from './usePanelEditor';
|
|
|
23
23
|
import { PanelQueriesSharedControls } from './PanelQueriesSharedControls';
|
|
24
24
|
export function PanelEditorForm(props) {
|
|
25
25
|
const { initialValues, initialAction, onSave, onClose } = props;
|
|
26
|
-
const pluginEditorRef = useRef(null);
|
|
27
26
|
const panelGroups = useListPanelGroups();
|
|
28
27
|
const { panelDefinition, setName, setDescription, setLinks, setQueries, setPlugin, setPanelDefinition } = usePanelEditor(initialValues.panelDefinition);
|
|
29
28
|
const { plugin } = panelDefinition.spec;
|
|
@@ -110,7 +109,6 @@ export function PanelEditorForm(props) {
|
|
|
110
109
|
name: 'panelDefinition.spec.plugin.kind'
|
|
111
110
|
});
|
|
112
111
|
const handleSubmit = useCallback(()=>{
|
|
113
|
-
pluginEditorRef.current?.flushChanges?.();
|
|
114
112
|
form.handleSubmit(processForm)();
|
|
115
113
|
}, [
|
|
116
114
|
form,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/PanelDrawer/PanelEditorForm.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 { ReactElement, useCallback, useEffect, useRef, useState } from 'react';\nimport { Box, Button, Grid, MenuItem, Stack, TextField, Typography } from '@mui/material';\nimport { Action, PanelDefinition, PanelEditorValues } from '@perses-dev/core';\nimport { DiscardChangesConfirmationDialog, ErrorAlert, ErrorBoundary } from '@perses-dev/components';\nimport {\n PluginKindSelect,\n usePluginEditor,\n getTitleAction,\n getSubmitText,\n useValidationSchemas,\n PluginEditorRef,\n} from '@perses-dev/plugin-system';\nimport { Controller, FormProvider, SubmitHandler, useForm, useWatch } from 'react-hook-form';\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport { useListPanelGroups } from '../../context';\nimport { PanelEditorProvider } from '../../context/PanelEditorProvider/PanelEditorProvider';\nimport { usePanelEditor } from './usePanelEditor';\nimport { PanelQueriesSharedControls } from './PanelQueriesSharedControls';\n\nexport interface PanelEditorFormProps {\n initialValues: PanelEditorValues;\n initialAction: Action;\n onSave: (values: PanelEditorValues) => void;\n onClose: () => void;\n}\n\nexport function PanelEditorForm(props: PanelEditorFormProps): ReactElement {\n const { initialValues, initialAction, onSave, onClose } = props;\n const pluginEditorRef = useRef<PluginEditorRef>(null);\n const panelGroups = useListPanelGroups();\n const { panelDefinition, setName, setDescription, setLinks, setQueries, setPlugin, setPanelDefinition } =\n usePanelEditor(initialValues.panelDefinition);\n const { plugin } = panelDefinition.spec;\n const [isDiscardDialogOpened, setDiscardDialogOpened] = useState<boolean>(false);\n\n const { panelEditorSchema } = useValidationSchemas();\n const form = useForm<PanelEditorValues>({\n resolver: zodResolver(panelEditorSchema),\n mode: 'onBlur',\n defaultValues: initialValues,\n });\n\n // Use common plugin editor logic even though we've split the inputs up in this form\n const pluginEditor = usePluginEditor({\n pluginTypes: ['Panel'],\n value: { selection: { kind: plugin.kind, type: 'Panel' }, spec: plugin.spec },\n onChange: (plugin) => {\n form.setValue('panelDefinition.spec.plugin', { kind: plugin.selection.kind, spec: plugin.spec });\n setPlugin({\n kind: plugin.selection.kind,\n spec: plugin.spec,\n });\n },\n onHideQueryEditorChange: (isHidden) => {\n setQueries(undefined, isHidden);\n },\n });\n\n const titleAction = getTitleAction(initialAction, true);\n const submitText = getSubmitText(initialAction, true);\n\n const links = useWatch({ control: form.control, name: 'panelDefinition.spec.links' });\n useEffect(() => {\n setLinks(links);\n }, [setLinks, links]);\n\n const processForm: SubmitHandler<PanelEditorValues> = useCallback(\n (data) => {\n onSave(data);\n },\n [onSave]\n );\n\n // When user click on cancel, several possibilities:\n // - create action: ask for discard approval\n // - update action: ask for discard approval if changed\n // - read action: don´t ask for discard approval\n function handleCancel(): void {\n if (JSON.stringify(initialValues) !== JSON.stringify(form.getValues())) {\n setDiscardDialogOpened(true);\n } else {\n onClose();\n }\n }\n\n const handlePanelDefinitionChange = (nextPanelDefStr: string): void => {\n const nextPanelDef: PanelDefinition = JSON.parse(nextPanelDefStr);\n const { kind: pluginKind, spec: pluginSpec } = nextPanelDef.spec.plugin;\n // if panel plugin kind and spec are modified, then need to save current spec\n if (\n panelDefinition.spec.plugin.kind !== pluginKind &&\n JSON.stringify(panelDefinition.spec.plugin.spec) !== JSON.stringify(pluginSpec)\n ) {\n pluginEditor.rememberCurrentSpecState();\n }\n setPanelDefinition(nextPanelDef);\n };\n\n const watchedName = useWatch({ control: form.control, name: 'panelDefinition.spec.display.name' });\n const watchedDescription = useWatch({ control: form.control, name: 'panelDefinition.spec.display.description' });\n const watchedPluginKind = useWatch({ control: form.control, name: 'panelDefinition.spec.plugin.kind' });\n\n const handleSubmit = useCallback(() => {\n pluginEditorRef.current?.flushChanges?.();\n form.handleSubmit(processForm)();\n }, [form, processForm]);\n\n return (\n <FormProvider {...form}>\n <PanelEditorProvider>\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n padding: (theme) => theme.spacing(1, 2),\n borderBottom: (theme) => `1px solid ${theme.palette.divider}`,\n }}\n >\n <Typography variant=\"h2\">{titleAction} Panel</Typography>\n <Stack direction=\"row\" spacing={1} marginLeft=\"auto\">\n <Button variant=\"contained\" disabled={!form.formState.isValid} onClick={handleSubmit}>\n {submitText}\n </Button>\n <Button color=\"secondary\" variant=\"outlined\" onClick={handleCancel}>\n Cancel\n </Button>\n </Stack>\n </Box>\n <Box id={panelEditorFormId} sx={{ flex: 1, overflowY: 'scroll', padding: (theme) => theme.spacing(2) }}>\n <Grid container spacing={2}>\n <Grid item xs={8}>\n <Controller\n control={form.control}\n name=\"panelDefinition.spec.display.name\"\n render={({ field, fieldState }) => (\n <TextField\n {...field}\n required\n fullWidth\n label=\"Name\"\n error={!!fieldState.error}\n helperText={fieldState.error?.message}\n value={watchedName ?? ''}\n onChange={(event) => {\n field.onChange(event);\n setName(event.target.value);\n }}\n />\n )}\n />\n </Grid>\n <Grid item xs={4}>\n <Controller\n control={form.control}\n name=\"groupId\"\n render={({ field, fieldState }) => (\n <TextField\n select\n {...field}\n required\n fullWidth\n label=\"Group\"\n error={!!fieldState.error}\n helperText={fieldState.error?.message}\n onChange={(event) => {\n field.onChange(event);\n }}\n >\n {panelGroups.map((panelGroup, index) => (\n <MenuItem key={panelGroup.id} value={panelGroup.id}>\n {panelGroup.title ?? `Group ${index + 1}`}\n </MenuItem>\n ))}\n </TextField>\n )}\n />\n </Grid>\n <Grid item xs={8}>\n <Controller\n control={form.control}\n name=\"panelDefinition.spec.display.description\"\n render={({ field, fieldState }) => (\n <TextField\n {...field}\n fullWidth\n label=\"Description\"\n error={!!fieldState.error}\n helperText={fieldState.error?.message}\n value={watchedDescription ?? ''}\n onChange={(event) => {\n field.onChange(event);\n setDescription(event.target.value);\n }}\n />\n )}\n />\n </Grid>\n <Grid item xs={4}>\n <Controller\n control={form.control}\n name=\"panelDefinition.spec.plugin.kind\"\n render={({ field, fieldState }) => (\n <PluginKindSelect\n {...field}\n pluginTypes={['Panel']}\n required\n fullWidth\n label=\"Type\"\n disabled={pluginEditor.isLoading}\n error={!!pluginEditor.error || !!fieldState.error}\n helperText={pluginEditor.error?.message ?? fieldState.error?.message}\n value={{ type: 'Panel', kind: watchedPluginKind }}\n onChange={(event) => {\n field.onChange(event.kind);\n pluginEditor.onSelectionChange(event);\n }}\n />\n )}\n />\n </Grid>\n\n <ErrorBoundary FallbackComponent={ErrorAlert}>\n <PanelQueriesSharedControls\n control={form.control}\n plugin={plugin}\n panelDefinition={panelDefinition}\n onQueriesChange={(q) => setQueries(q)}\n onPluginSpecChange={(spec) => {\n pluginEditor.onSpecChange(spec);\n }}\n onJSONChange={handlePanelDefinitionChange}\n />\n </ErrorBoundary>\n </Grid>\n </Box>\n <DiscardChangesConfirmationDialog\n description=\"You have unapplied changes in this panel. Are you sure you want to discard these changes? Changes cannot be recovered.\"\n isOpen={isDiscardDialogOpened}\n onCancel={() => {\n setDiscardDialogOpened(false);\n }}\n onDiscardChanges={() => {\n setDiscardDialogOpened(false);\n onClose();\n }}\n />\n </PanelEditorProvider>\n </FormProvider>\n );\n}\n\n/**\n * The `id` attribute added to the `PanelEditorForm` component, allowing submit buttons to live outside the form.\n */\nexport const panelEditorFormId = 'panel-editor-form';\n"],"names":["useCallback","useEffect","useRef","useState","Box","Button","Grid","MenuItem","Stack","TextField","Typography","DiscardChangesConfirmationDialog","ErrorAlert","ErrorBoundary","PluginKindSelect","usePluginEditor","getTitleAction","getSubmitText","useValidationSchemas","Controller","FormProvider","useForm","useWatch","zodResolver","useListPanelGroups","PanelEditorProvider","usePanelEditor","PanelQueriesSharedControls","PanelEditorForm","props","initialValues","initialAction","onSave","onClose","pluginEditorRef","panelGroups","panelDefinition","setName","setDescription","setLinks","setQueries","setPlugin","setPanelDefinition","plugin","spec","isDiscardDialogOpened","setDiscardDialogOpened","panelEditorSchema","form","resolver","mode","defaultValues","pluginEditor","pluginTypes","value","selection","kind","type","onChange","setValue","onHideQueryEditorChange","isHidden","undefined","titleAction","submitText","links","control","name","processForm","data","handleCancel","JSON","stringify","getValues","handlePanelDefinitionChange","nextPanelDefStr","nextPanelDef","parse","pluginKind","pluginSpec","rememberCurrentSpecState","watchedName","watchedDescription","watchedPluginKind","handleSubmit","current","flushChanges","sx","display","alignItems","padding","theme","spacing","borderBottom","palette","divider","variant","direction","marginLeft","disabled","formState","isValid","onClick","color","id","panelEditorFormId","flex","overflowY","container","item","xs","render","field","fieldState","required","fullWidth","label","error","helperText","message","event","target","select","map","panelGroup","index","title","isLoading","onSelectionChange","FallbackComponent","onQueriesChange","q","onPluginSpecChange","onSpecChange","onJSONChange","description","isOpen","onCancel","onDiscardChanges"],"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,SAAuBA,WAAW,EAAEC,SAAS,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,QAAQ;AAC/E,SAASC,GAAG,EAAEC,MAAM,EAAEC,IAAI,EAAEC,QAAQ,EAAEC,KAAK,EAAEC,SAAS,EAAEC,UAAU,QAAQ,gBAAgB;AAE1F,SAASC,gCAAgC,EAAEC,UAAU,EAAEC,aAAa,QAAQ,yBAAyB;AACrG,SACEC,gBAAgB,EAChBC,eAAe,EACfC,cAAc,EACdC,aAAa,EACbC,oBAAoB,QAEf,4BAA4B;AACnC,SAASC,UAAU,EAAEC,YAAY,EAAiBC,OAAO,EAAEC,QAAQ,QAAQ,kBAAkB;AAC7F,SAASC,WAAW,QAAQ,0BAA0B;AACtD,SAASC,kBAAkB,QAAQ,gBAAgB;AACnD,SAASC,mBAAmB,QAAQ,wDAAwD;AAC5F,SAASC,cAAc,QAAQ,mBAAmB;AAClD,SAASC,0BAA0B,QAAQ,+BAA+B;AAS1E,OAAO,SAASC,gBAAgBC,KAA2B;IACzD,MAAM,EAAEC,aAAa,EAAEC,aAAa,EAAEC,MAAM,EAAEC,OAAO,EAAE,GAAGJ;IAC1D,MAAMK,kBAAkBhC,OAAwB;IAChD,MAAMiC,cAAcX;IACpB,MAAM,EAAEY,eAAe,EAAEC,OAAO,EAAEC,cAAc,EAAEC,QAAQ,EAAEC,UAAU,EAAEC,SAAS,EAAEC,kBAAkB,EAAE,GACrGhB,eAAeI,cAAcM,eAAe;IAC9C,MAAM,EAAEO,MAAM,EAAE,GAAGP,gBAAgBQ,IAAI;IACvC,MAAM,CAACC,uBAAuBC,uBAAuB,GAAG3C,SAAkB;IAE1E,MAAM,EAAE4C,iBAAiB,EAAE,GAAG7B;IAC9B,MAAM8B,OAAO3B,QAA2B;QACtC4B,UAAU1B,YAAYwB;QACtBG,MAAM;QACNC,eAAerB;IACjB;IAEA,oFAAoF;IACpF,MAAMsB,eAAerC,gBAAgB;QACnCsC,aAAa;YAAC;SAAQ;QACtBC,OAAO;YAAEC,WAAW;gBAAEC,MAAMb,OAAOa,IAAI;gBAAEC,MAAM;YAAQ;YAAGb,MAAMD,OAAOC,IAAI;QAAC;QAC5Ec,UAAU,CAACf;YACTK,KAAKW,QAAQ,CAAC,+BAA+B;gBAAEH,MAAMb,OAAOY,SAAS,CAACC,IAAI;gBAAEZ,MAAMD,OAAOC,IAAI;YAAC;YAC9FH,UAAU;gBACRe,MAAMb,OAAOY,SAAS,CAACC,IAAI;gBAC3BZ,MAAMD,OAAOC,IAAI;YACnB;QACF;QACAgB,yBAAyB,CAACC;YACxBrB,WAAWsB,WAAWD;QACxB;IACF;IAEA,MAAME,cAAc/C,eAAee,eAAe;IAClD,MAAMiC,aAAa/C,cAAcc,eAAe;IAEhD,MAAMkC,QAAQ3C,SAAS;QAAE4C,SAASlB,KAAKkB,OAAO;QAAEC,MAAM;IAA6B;IACnFlE,UAAU;QACRsC,SAAS0B;IACX,GAAG;QAAC1B;QAAU0B;KAAM;IAEpB,MAAMG,cAAgDpE,YACpD,CAACqE;QACCrC,OAAOqC;IACT,GACA;QAACrC;KAAO;IAGV,oDAAoD;IACpD,4CAA4C;IAC5C,uDAAuD;IACvD,gDAAgD;IAChD,SAASsC;QACP,IAAIC,KAAKC,SAAS,CAAC1C,mBAAmByC,KAAKC,SAAS,CAACxB,KAAKyB,SAAS,KAAK;YACtE3B,uBAAuB;QACzB,OAAO;YACLb;QACF;IACF;IAEA,MAAMyC,8BAA8B,CAACC;QACnC,MAAMC,eAAgCL,KAAKM,KAAK,CAACF;QACjD,MAAM,EAAEnB,MAAMsB,UAAU,EAAElC,MAAMmC,UAAU,EAAE,GAAGH,aAAahC,IAAI,CAACD,MAAM;QACvE,6EAA6E;QAC7E,IACEP,gBAAgBQ,IAAI,CAACD,MAAM,CAACa,IAAI,KAAKsB,cACrCP,KAAKC,SAAS,CAACpC,gBAAgBQ,IAAI,CAACD,MAAM,CAACC,IAAI,MAAM2B,KAAKC,SAAS,CAACO,aACpE;YACA3B,aAAa4B,wBAAwB;QACvC;QACAtC,mBAAmBkC;IACrB;IAEA,MAAMK,cAAc3D,SAAS;QAAE4C,SAASlB,KAAKkB,OAAO;QAAEC,MAAM;IAAoC;IAChG,MAAMe,qBAAqB5D,SAAS;QAAE4C,SAASlB,KAAKkB,OAAO;QAAEC,MAAM;IAA2C;IAC9G,MAAMgB,oBAAoB7D,SAAS;QAAE4C,SAASlB,KAAKkB,OAAO;QAAEC,MAAM;IAAmC;IAErG,MAAMiB,eAAepF,YAAY;QAC/BkC,gBAAgBmD,OAAO,EAAEC;QACzBtC,KAAKoC,YAAY,CAAChB;IACpB,GAAG;QAACpB;QAAMoB;KAAY;IAEtB,qBACE,KAAChD;QAAc,GAAG4B,IAAI;kBACpB,cAAA,MAACvB;;8BACC,MAACrB;oBACCmF,IAAI;wBACFC,SAAS;wBACTC,YAAY;wBACZC,SAAS,CAACC,QAAUA,MAAMC,OAAO,CAAC,GAAG;wBACrCC,cAAc,CAACF,QAAU,CAAC,UAAU,EAAEA,MAAMG,OAAO,CAACC,OAAO,EAAE;oBAC/D;;sCAEA,MAACrF;4BAAWsF,SAAQ;;gCAAMjC;gCAAY;;;sCACtC,MAACvD;4BAAMyF,WAAU;4BAAML,SAAS;4BAAGM,YAAW;;8CAC5C,KAAC7F;oCAAO2F,SAAQ;oCAAYG,UAAU,CAACnD,KAAKoD,SAAS,CAACC,OAAO;oCAAEC,SAASlB;8CACrEpB;;8CAEH,KAAC3D;oCAAOkG,OAAM;oCAAYP,SAAQ;oCAAWM,SAAShC;8CAAc;;;;;;8BAKxE,KAAClE;oBAAIoG,IAAIC;oBAAmBlB,IAAI;wBAAEmB,MAAM;wBAAGC,WAAW;wBAAUjB,SAAS,CAACC,QAAUA,MAAMC,OAAO,CAAC;oBAAG;8BACnG,cAAA,MAACtF;wBAAKsG,SAAS;wBAAChB,SAAS;;0CACvB,KAACtF;gCAAKuG,IAAI;gCAACC,IAAI;0CACb,cAAA,KAAC3F;oCACC+C,SAASlB,KAAKkB,OAAO;oCACrBC,MAAK;oCACL4C,QAAQ,CAAC,EAAEC,KAAK,EAAEC,UAAU,EAAE,iBAC5B,KAACxG;4CACE,GAAGuG,KAAK;4CACTE,QAAQ;4CACRC,SAAS;4CACTC,OAAM;4CACNC,OAAO,CAAC,CAACJ,WAAWI,KAAK;4CACzBC,YAAYL,WAAWI,KAAK,EAAEE;4CAC9BjE,OAAO2B,eAAe;4CACtBvB,UAAU,CAAC8D;gDACTR,MAAMtD,QAAQ,CAAC8D;gDACfnF,QAAQmF,MAAMC,MAAM,CAACnE,KAAK;4CAC5B;;;;0CAKR,KAAChD;gCAAKuG,IAAI;gCAACC,IAAI;0CACb,cAAA,KAAC3F;oCACC+C,SAASlB,KAAKkB,OAAO;oCACrBC,MAAK;oCACL4C,QAAQ,CAAC,EAAEC,KAAK,EAAEC,UAAU,EAAE,iBAC5B,KAACxG;4CACCiH,MAAM;4CACL,GAAGV,KAAK;4CACTE,QAAQ;4CACRC,SAAS;4CACTC,OAAM;4CACNC,OAAO,CAAC,CAACJ,WAAWI,KAAK;4CACzBC,YAAYL,WAAWI,KAAK,EAAEE;4CAC9B7D,UAAU,CAAC8D;gDACTR,MAAMtD,QAAQ,CAAC8D;4CACjB;sDAECrF,YAAYwF,GAAG,CAAC,CAACC,YAAYC,sBAC5B,KAACtH;oDAA6B+C,OAAOsE,WAAWpB,EAAE;8DAC/CoB,WAAWE,KAAK,IAAI,CAAC,MAAM,EAAED,QAAQ,GAAG;mDAD5BD,WAAWpB,EAAE;;;;0CAQtC,KAAClG;gCAAKuG,IAAI;gCAACC,IAAI;0CACb,cAAA,KAAC3F;oCACC+C,SAASlB,KAAKkB,OAAO;oCACrBC,MAAK;oCACL4C,QAAQ,CAAC,EAAEC,KAAK,EAAEC,UAAU,EAAE,iBAC5B,KAACxG;4CACE,GAAGuG,KAAK;4CACTG,SAAS;4CACTC,OAAM;4CACNC,OAAO,CAAC,CAACJ,WAAWI,KAAK;4CACzBC,YAAYL,WAAWI,KAAK,EAAEE;4CAC9BjE,OAAO4B,sBAAsB;4CAC7BxB,UAAU,CAAC8D;gDACTR,MAAMtD,QAAQ,CAAC8D;gDACflF,eAAekF,MAAMC,MAAM,CAACnE,KAAK;4CACnC;;;;0CAKR,KAAChD;gCAAKuG,IAAI;gCAACC,IAAI;0CACb,cAAA,KAAC3F;oCACC+C,SAASlB,KAAKkB,OAAO;oCACrBC,MAAK;oCACL4C,QAAQ,CAAC,EAAEC,KAAK,EAAEC,UAAU,EAAE,iBAC5B,KAACnG;4CACE,GAAGkG,KAAK;4CACT3D,aAAa;gDAAC;6CAAQ;4CACtB6D,QAAQ;4CACRC,SAAS;4CACTC,OAAM;4CACNjB,UAAU/C,aAAa2E,SAAS;4CAChCV,OAAO,CAAC,CAACjE,aAAaiE,KAAK,IAAI,CAAC,CAACJ,WAAWI,KAAK;4CACjDC,YAAYlE,aAAaiE,KAAK,EAAEE,WAAWN,WAAWI,KAAK,EAAEE;4CAC7DjE,OAAO;gDAAEG,MAAM;gDAASD,MAAM2B;4CAAkB;4CAChDzB,UAAU,CAAC8D;gDACTR,MAAMtD,QAAQ,CAAC8D,MAAMhE,IAAI;gDACzBJ,aAAa4E,iBAAiB,CAACR;4CACjC;;;;0CAMR,KAAC3G;gCAAcoH,mBAAmBrH;0CAChC,cAAA,KAACe;oCACCuC,SAASlB,KAAKkB,OAAO;oCACrBvB,QAAQA;oCACRP,iBAAiBA;oCACjB8F,iBAAiB,CAACC,IAAM3F,WAAW2F;oCACnCC,oBAAoB,CAACxF;wCACnBQ,aAAaiF,YAAY,CAACzF;oCAC5B;oCACA0F,cAAc5D;;;;;;8BAKtB,KAAC/D;oBACC4H,aAAY;oBACZC,QAAQ3F;oBACR4F,UAAU;wBACR3F,uBAAuB;oBACzB;oBACA4F,kBAAkB;wBAChB5F,uBAAuB;wBACvBb;oBACF;;;;;AAKV;AAEA;;CAEC,GACD,OAAO,MAAMwE,oBAAoB,oBAAoB"}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/PanelDrawer/PanelEditorForm.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 { ReactElement, useCallback, useEffect, useState } from 'react';\nimport { Box, Button, Grid, MenuItem, Stack, TextField, Typography } from '@mui/material';\nimport { Action, PanelDefinition, PanelEditorValues } from '@perses-dev/core';\nimport { DiscardChangesConfirmationDialog, ErrorAlert, ErrorBoundary } from '@perses-dev/components';\nimport {\n PluginKindSelect,\n usePluginEditor,\n getTitleAction,\n getSubmitText,\n useValidationSchemas,\n} from '@perses-dev/plugin-system';\nimport { Controller, FormProvider, SubmitHandler, useForm, useWatch } from 'react-hook-form';\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport { useListPanelGroups } from '../../context';\nimport { PanelEditorProvider } from '../../context/PanelEditorProvider/PanelEditorProvider';\nimport { usePanelEditor } from './usePanelEditor';\nimport { PanelQueriesSharedControls } from './PanelQueriesSharedControls';\n\nexport interface PanelEditorFormProps {\n initialValues: PanelEditorValues;\n initialAction: Action;\n onSave: (values: PanelEditorValues) => void;\n onClose: () => void;\n}\n\nexport function PanelEditorForm(props: PanelEditorFormProps): ReactElement {\n const { initialValues, initialAction, onSave, onClose } = props;\n const panelGroups = useListPanelGroups();\n const { panelDefinition, setName, setDescription, setLinks, setQueries, setPlugin, setPanelDefinition } =\n usePanelEditor(initialValues.panelDefinition);\n const { plugin } = panelDefinition.spec;\n const [isDiscardDialogOpened, setDiscardDialogOpened] = useState<boolean>(false);\n\n const { panelEditorSchema } = useValidationSchemas();\n const form = useForm<PanelEditorValues>({\n resolver: zodResolver(panelEditorSchema),\n mode: 'onBlur',\n defaultValues: initialValues,\n });\n\n // Use common plugin editor logic even though we've split the inputs up in this form\n const pluginEditor = usePluginEditor({\n pluginTypes: ['Panel'],\n value: { selection: { kind: plugin.kind, type: 'Panel' }, spec: plugin.spec },\n onChange: (plugin) => {\n form.setValue('panelDefinition.spec.plugin', { kind: plugin.selection.kind, spec: plugin.spec });\n setPlugin({\n kind: plugin.selection.kind,\n spec: plugin.spec,\n });\n },\n onHideQueryEditorChange: (isHidden) => {\n setQueries(undefined, isHidden);\n },\n });\n\n const titleAction = getTitleAction(initialAction, true);\n const submitText = getSubmitText(initialAction, true);\n\n const links = useWatch({ control: form.control, name: 'panelDefinition.spec.links' });\n useEffect(() => {\n setLinks(links);\n }, [setLinks, links]);\n\n const processForm: SubmitHandler<PanelEditorValues> = useCallback(\n (data) => {\n onSave(data);\n },\n [onSave]\n );\n\n // When user click on cancel, several possibilities:\n // - create action: ask for discard approval\n // - update action: ask for discard approval if changed\n // - read action: don´t ask for discard approval\n function handleCancel(): void {\n if (JSON.stringify(initialValues) !== JSON.stringify(form.getValues())) {\n setDiscardDialogOpened(true);\n } else {\n onClose();\n }\n }\n\n const handlePanelDefinitionChange = (nextPanelDefStr: string): void => {\n const nextPanelDef: PanelDefinition = JSON.parse(nextPanelDefStr);\n const { kind: pluginKind, spec: pluginSpec } = nextPanelDef.spec.plugin;\n // if panel plugin kind and spec are modified, then need to save current spec\n if (\n panelDefinition.spec.plugin.kind !== pluginKind &&\n JSON.stringify(panelDefinition.spec.plugin.spec) !== JSON.stringify(pluginSpec)\n ) {\n pluginEditor.rememberCurrentSpecState();\n }\n setPanelDefinition(nextPanelDef);\n };\n\n const watchedName = useWatch({ control: form.control, name: 'panelDefinition.spec.display.name' });\n const watchedDescription = useWatch({ control: form.control, name: 'panelDefinition.spec.display.description' });\n const watchedPluginKind = useWatch({ control: form.control, name: 'panelDefinition.spec.plugin.kind' });\n\n const handleSubmit = useCallback(() => {\n form.handleSubmit(processForm)();\n }, [form, processForm]);\n\n return (\n <FormProvider {...form}>\n <PanelEditorProvider>\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n padding: (theme) => theme.spacing(1, 2),\n borderBottom: (theme) => `1px solid ${theme.palette.divider}`,\n }}\n >\n <Typography variant=\"h2\">{titleAction} Panel</Typography>\n <Stack direction=\"row\" spacing={1} marginLeft=\"auto\">\n <Button variant=\"contained\" disabled={!form.formState.isValid} onClick={handleSubmit}>\n {submitText}\n </Button>\n <Button color=\"secondary\" variant=\"outlined\" onClick={handleCancel}>\n Cancel\n </Button>\n </Stack>\n </Box>\n <Box id={panelEditorFormId} sx={{ flex: 1, overflowY: 'scroll', padding: (theme) => theme.spacing(2) }}>\n <Grid container spacing={2}>\n <Grid item xs={8}>\n <Controller\n control={form.control}\n name=\"panelDefinition.spec.display.name\"\n render={({ field, fieldState }) => (\n <TextField\n {...field}\n required\n fullWidth\n label=\"Name\"\n error={!!fieldState.error}\n helperText={fieldState.error?.message}\n value={watchedName ?? ''}\n onChange={(event) => {\n field.onChange(event);\n setName(event.target.value);\n }}\n />\n )}\n />\n </Grid>\n <Grid item xs={4}>\n <Controller\n control={form.control}\n name=\"groupId\"\n render={({ field, fieldState }) => (\n <TextField\n select\n {...field}\n required\n fullWidth\n label=\"Group\"\n error={!!fieldState.error}\n helperText={fieldState.error?.message}\n onChange={(event) => {\n field.onChange(event);\n }}\n >\n {panelGroups.map((panelGroup, index) => (\n <MenuItem key={panelGroup.id} value={panelGroup.id}>\n {panelGroup.title ?? `Group ${index + 1}`}\n </MenuItem>\n ))}\n </TextField>\n )}\n />\n </Grid>\n <Grid item xs={8}>\n <Controller\n control={form.control}\n name=\"panelDefinition.spec.display.description\"\n render={({ field, fieldState }) => (\n <TextField\n {...field}\n fullWidth\n label=\"Description\"\n error={!!fieldState.error}\n helperText={fieldState.error?.message}\n value={watchedDescription ?? ''}\n onChange={(event) => {\n field.onChange(event);\n setDescription(event.target.value);\n }}\n />\n )}\n />\n </Grid>\n <Grid item xs={4}>\n <Controller\n control={form.control}\n name=\"panelDefinition.spec.plugin.kind\"\n render={({ field, fieldState }) => (\n <PluginKindSelect\n {...field}\n pluginTypes={['Panel']}\n required\n fullWidth\n label=\"Type\"\n disabled={pluginEditor.isLoading}\n error={!!pluginEditor.error || !!fieldState.error}\n helperText={pluginEditor.error?.message ?? fieldState.error?.message}\n value={{ type: 'Panel', kind: watchedPluginKind }}\n onChange={(event) => {\n field.onChange(event.kind);\n pluginEditor.onSelectionChange(event);\n }}\n />\n )}\n />\n </Grid>\n\n <ErrorBoundary FallbackComponent={ErrorAlert}>\n <PanelQueriesSharedControls\n control={form.control}\n plugin={plugin}\n panelDefinition={panelDefinition}\n onQueriesChange={(q) => setQueries(q)}\n onPluginSpecChange={(spec) => {\n pluginEditor.onSpecChange(spec);\n }}\n onJSONChange={handlePanelDefinitionChange}\n />\n </ErrorBoundary>\n </Grid>\n </Box>\n <DiscardChangesConfirmationDialog\n description=\"You have unapplied changes in this panel. Are you sure you want to discard these changes? Changes cannot be recovered.\"\n isOpen={isDiscardDialogOpened}\n onCancel={() => {\n setDiscardDialogOpened(false);\n }}\n onDiscardChanges={() => {\n setDiscardDialogOpened(false);\n onClose();\n }}\n />\n </PanelEditorProvider>\n </FormProvider>\n );\n}\n\n/**\n * The `id` attribute added to the `PanelEditorForm` component, allowing submit buttons to live outside the form.\n */\nexport const panelEditorFormId = 'panel-editor-form';\n"],"names":["useCallback","useEffect","useState","Box","Button","Grid","MenuItem","Stack","TextField","Typography","DiscardChangesConfirmationDialog","ErrorAlert","ErrorBoundary","PluginKindSelect","usePluginEditor","getTitleAction","getSubmitText","useValidationSchemas","Controller","FormProvider","useForm","useWatch","zodResolver","useListPanelGroups","PanelEditorProvider","usePanelEditor","PanelQueriesSharedControls","PanelEditorForm","props","initialValues","initialAction","onSave","onClose","panelGroups","panelDefinition","setName","setDescription","setLinks","setQueries","setPlugin","setPanelDefinition","plugin","spec","isDiscardDialogOpened","setDiscardDialogOpened","panelEditorSchema","form","resolver","mode","defaultValues","pluginEditor","pluginTypes","value","selection","kind","type","onChange","setValue","onHideQueryEditorChange","isHidden","undefined","titleAction","submitText","links","control","name","processForm","data","handleCancel","JSON","stringify","getValues","handlePanelDefinitionChange","nextPanelDefStr","nextPanelDef","parse","pluginKind","pluginSpec","rememberCurrentSpecState","watchedName","watchedDescription","watchedPluginKind","handleSubmit","sx","display","alignItems","padding","theme","spacing","borderBottom","palette","divider","variant","direction","marginLeft","disabled","formState","isValid","onClick","color","id","panelEditorFormId","flex","overflowY","container","item","xs","render","field","fieldState","required","fullWidth","label","error","helperText","message","event","target","select","map","panelGroup","index","title","isLoading","onSelectionChange","FallbackComponent","onQueriesChange","q","onPluginSpecChange","onSpecChange","onJSONChange","description","isOpen","onCancel","onDiscardChanges"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PanelQueriesSharedControls.d.ts","sourceRoot":"","sources":["../../../src/components/PanelDrawer/PanelQueriesSharedControls.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,iBAAiB,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAChH,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"PanelQueriesSharedControls.d.ts","sourceRoot":"","sources":["../../../src/components/PanelDrawer/PanelQueriesSharedControls.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,iBAAiB,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAChH,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,YAAY,EAA8C,MAAM,OAAO,CAAC;AAEjF,MAAM,WAAW,+BAA+B;IAC9C,OAAO,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACpC,MAAM,EAAE,UAAU,CAAC,WAAW,CAAC,CAAC;IAChC,eAAe,EAAE,eAAe,CAAC;IACjC,eAAe,EAAE,CAAC,OAAO,EAAE,eAAe,EAAE,KAAK,IAAI,CAAC;IACtD,kBAAkB,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,CAAC;IAChD,YAAY,EAAE,CAAC,kBAAkB,EAAE,MAAM,KAAK,IAAI,CAAC;CACpD;AAID,wBAAgB,0BAA0B,CAAC,EACzC,MAAM,EACN,OAAO,EACP,eAAe,EACf,eAAe,EACf,kBAAkB,EAClB,YAAY,GACb,EAAE,+BAA+B,GAAG,YAAY,CA2DhD"}
|
|
@@ -15,22 +15,37 @@ import { Grid, Typography } from '@mui/material';
|
|
|
15
15
|
import { ErrorAlert, ErrorBoundary } from '@perses-dev/components';
|
|
16
16
|
import { PanelEditorContext, PanelPreview } from '@perses-dev/dashboards';
|
|
17
17
|
import { DataQueriesProvider, PanelSpecEditor, usePlugin, useSuggestedStepMs } from '@perses-dev/plugin-system';
|
|
18
|
-
import { useContext } from 'react';
|
|
18
|
+
import { useCallback, useContext, useMemo, useState } from 'react';
|
|
19
19
|
// Component of PanelEditor, it will share queries results to its children with DataQueriesProvider.
|
|
20
20
|
// TODO: consider merging PanelEditorProvider, QueryCountProvider and DataQueriesProvider into a single provider to avoid multiple nested providers.
|
|
21
21
|
export function PanelQueriesSharedControls({ plugin, control, panelDefinition, onQueriesChange, onPluginSpecChange, onJSONChange }) {
|
|
22
22
|
const { data: pluginPreview } = usePlugin('Panel', plugin.kind);
|
|
23
23
|
const panelEditorContext = useContext(PanelEditorContext);
|
|
24
|
-
const pluginQueryOptions = typeof pluginPreview?.queryOptions === 'function' ? pluginPreview?.queryOptions(panelDefinition.spec.plugin.spec) : pluginPreview?.queryOptions;
|
|
25
24
|
const suggestedStepMs = useSuggestedStepMs(panelEditorContext?.preview.previewPanelWidth);
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
25
|
+
const pluginQueryOptions = useMemo(()=>typeof pluginPreview?.queryOptions === 'function' ? pluginPreview?.queryOptions(panelDefinition.spec.plugin.spec) : pluginPreview?.queryOptions, [
|
|
26
|
+
panelDefinition.spec.plugin.spec,
|
|
27
|
+
pluginPreview
|
|
28
|
+
]);
|
|
29
|
+
const [previewDefinition, setPreviewDefinition] = useState(()=>panelDefinition.spec.queries?.map((query)=>{
|
|
30
|
+
return {
|
|
31
|
+
kind: query.spec.plugin.kind,
|
|
32
|
+
spec: query.spec.plugin.spec
|
|
33
|
+
};
|
|
34
|
+
}) ?? []);
|
|
35
|
+
const handleRunQuery = useCallback((index, newDef)=>{
|
|
36
|
+
setPreviewDefinition((prev)=>{
|
|
37
|
+
const newDefinitions = [
|
|
38
|
+
...prev
|
|
39
|
+
];
|
|
40
|
+
newDefinitions[index] = {
|
|
41
|
+
kind: newDef.spec.plugin.kind,
|
|
42
|
+
spec: newDef.spec.plugin.spec
|
|
43
|
+
};
|
|
44
|
+
return newDefinitions;
|
|
45
|
+
});
|
|
46
|
+
}, []);
|
|
32
47
|
return /*#__PURE__*/ _jsxs(DataQueriesProvider, {
|
|
33
|
-
definitions:
|
|
48
|
+
definitions: previewDefinition,
|
|
34
49
|
options: {
|
|
35
50
|
suggestedStepMs,
|
|
36
51
|
...pluginQueryOptions
|
|
@@ -63,6 +78,7 @@ export function PanelQueriesSharedControls({ plugin, control, panelDefinition, o
|
|
|
63
78
|
panelDefinition: panelDefinition,
|
|
64
79
|
onJSONChange: onJSONChange,
|
|
65
80
|
onQueriesChange: onQueriesChange,
|
|
81
|
+
onQueryRun: handleRunQuery,
|
|
66
82
|
onPluginSpecChange: onPluginSpecChange
|
|
67
83
|
})
|
|
68
84
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/PanelDrawer/PanelQueriesSharedControls.tsx"],"sourcesContent":["// Copyright 2025 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 { Grid, Typography } from '@mui/material';\nimport { ErrorAlert, ErrorBoundary } from '@perses-dev/components';\nimport { PanelEditorContext, PanelPreview } from '@perses-dev/dashboards';\nimport { DataQueriesProvider, PanelSpecEditor, usePlugin, useSuggestedStepMs } from '@perses-dev/plugin-system';\nimport { Definition, PanelDefinition, PanelEditorValues, QueryDefinition, UnknownSpec } from '@perses-dev/core';\nimport { Control } from 'react-hook-form';\nimport { ReactElement, useContext } from 'react';\n\nexport interface PanelQueriesSharedControlsProps {\n control: Control<PanelEditorValues>;\n plugin: Definition<UnknownSpec>;\n panelDefinition: PanelDefinition;\n onQueriesChange: (queries: QueryDefinition[]) => void;\n onPluginSpecChange: (spec: UnknownSpec) => void;\n onJSONChange: (panelDefinitionStr: string) => void;\n}\n\n// Component of PanelEditor, it will share queries results to its children with DataQueriesProvider.\n// TODO: consider merging PanelEditorProvider, QueryCountProvider and DataQueriesProvider into a single provider to avoid multiple nested providers.\nexport function PanelQueriesSharedControls({\n plugin,\n control,\n panelDefinition,\n onQueriesChange,\n onPluginSpecChange,\n onJSONChange,\n}: PanelQueriesSharedControlsProps): ReactElement {\n const { data: pluginPreview } = usePlugin('Panel', plugin.kind);\n const panelEditorContext = useContext(PanelEditorContext);\n\n const pluginQueryOptions
|
|
1
|
+
{"version":3,"sources":["../../../src/components/PanelDrawer/PanelQueriesSharedControls.tsx"],"sourcesContent":["// Copyright 2025 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 { Grid, Typography } from '@mui/material';\nimport { ErrorAlert, ErrorBoundary } from '@perses-dev/components';\nimport { PanelEditorContext, PanelPreview } from '@perses-dev/dashboards';\nimport { DataQueriesProvider, PanelSpecEditor, usePlugin, useSuggestedStepMs } from '@perses-dev/plugin-system';\nimport { Definition, PanelDefinition, PanelEditorValues, QueryDefinition, UnknownSpec } from '@perses-dev/core';\nimport { Control } from 'react-hook-form';\nimport { ReactElement, useCallback, useContext, useMemo, useState } from 'react';\n\nexport interface PanelQueriesSharedControlsProps {\n control: Control<PanelEditorValues>;\n plugin: Definition<UnknownSpec>;\n panelDefinition: PanelDefinition;\n onQueriesChange: (queries: QueryDefinition[]) => void;\n onPluginSpecChange: (spec: UnknownSpec) => void;\n onJSONChange: (panelDefinitionStr: string) => void;\n}\n\n// Component of PanelEditor, it will share queries results to its children with DataQueriesProvider.\n// TODO: consider merging PanelEditorProvider, QueryCountProvider and DataQueriesProvider into a single provider to avoid multiple nested providers.\nexport function PanelQueriesSharedControls({\n plugin,\n control,\n panelDefinition,\n onQueriesChange,\n onPluginSpecChange,\n onJSONChange,\n}: PanelQueriesSharedControlsProps): ReactElement {\n const { data: pluginPreview } = usePlugin('Panel', plugin.kind);\n const panelEditorContext = useContext(PanelEditorContext);\n\n const suggestedStepMs = useSuggestedStepMs(panelEditorContext?.preview.previewPanelWidth);\n\n const pluginQueryOptions = useMemo(\n () =>\n typeof pluginPreview?.queryOptions === 'function'\n ? pluginPreview?.queryOptions(panelDefinition.spec.plugin.spec)\n : pluginPreview?.queryOptions,\n [panelDefinition.spec.plugin.spec, pluginPreview]\n );\n\n const [previewDefinition, setPreviewDefinition] = useState(\n () =>\n panelDefinition.spec.queries?.map((query) => {\n return {\n kind: query.spec.plugin.kind,\n spec: query.spec.plugin.spec,\n };\n }) ?? []\n );\n\n const handleRunQuery = useCallback((index: number, newDef: QueryDefinition) => {\n setPreviewDefinition((prev) => {\n const newDefinitions = [...prev];\n newDefinitions[index] = {\n kind: newDef.spec.plugin.kind,\n spec: newDef.spec.plugin.spec,\n };\n return newDefinitions;\n });\n }, []);\n\n return (\n <DataQueriesProvider definitions={previewDefinition} options={{ suggestedStepMs, ...pluginQueryOptions }}>\n <Grid item xs={12}>\n <Typography variant=\"h4\" marginBottom={1}>\n Preview\n </Typography>\n <ErrorBoundary FallbackComponent={ErrorAlert}>\n <PanelPreview panelDefinition={panelDefinition} />\n </ErrorBoundary>\n </Grid>\n <Grid item xs={12}>\n <ErrorBoundary FallbackComponent={ErrorAlert}>\n <PanelSpecEditor\n control={control}\n panelDefinition={panelDefinition}\n onJSONChange={onJSONChange}\n onQueriesChange={onQueriesChange}\n onQueryRun={handleRunQuery}\n onPluginSpecChange={onPluginSpecChange}\n />\n </ErrorBoundary>\n </Grid>\n </DataQueriesProvider>\n );\n}\n"],"names":["Grid","Typography","ErrorAlert","ErrorBoundary","PanelEditorContext","PanelPreview","DataQueriesProvider","PanelSpecEditor","usePlugin","useSuggestedStepMs","useCallback","useContext","useMemo","useState","PanelQueriesSharedControls","plugin","control","panelDefinition","onQueriesChange","onPluginSpecChange","onJSONChange","data","pluginPreview","kind","panelEditorContext","suggestedStepMs","preview","previewPanelWidth","pluginQueryOptions","queryOptions","spec","previewDefinition","setPreviewDefinition","queries","map","query","handleRunQuery","index","newDef","prev","newDefinitions","definitions","options","item","xs","variant","marginBottom","FallbackComponent","onQueryRun"],"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,IAAI,EAAEC,UAAU,QAAQ,gBAAgB;AACjD,SAASC,UAAU,EAAEC,aAAa,QAAQ,yBAAyB;AACnE,SAASC,kBAAkB,EAAEC,YAAY,QAAQ,yBAAyB;AAC1E,SAASC,mBAAmB,EAAEC,eAAe,EAAEC,SAAS,EAAEC,kBAAkB,QAAQ,4BAA4B;AAGhH,SAAuBC,WAAW,EAAEC,UAAU,EAAEC,OAAO,EAAEC,QAAQ,QAAQ,QAAQ;AAWjF,oGAAoG;AACpG,oJAAoJ;AACpJ,OAAO,SAASC,2BAA2B,EACzCC,MAAM,EACNC,OAAO,EACPC,eAAe,EACfC,eAAe,EACfC,kBAAkB,EAClBC,YAAY,EACoB;IAChC,MAAM,EAAEC,MAAMC,aAAa,EAAE,GAAGd,UAAU,SAASO,OAAOQ,IAAI;IAC9D,MAAMC,qBAAqBb,WAAWP;IAEtC,MAAMqB,kBAAkBhB,mBAAmBe,oBAAoBE,QAAQC;IAEvE,MAAMC,qBAAqBhB,QACzB,IACE,OAAOU,eAAeO,iBAAiB,aACnCP,eAAeO,aAAaZ,gBAAgBa,IAAI,CAACf,MAAM,CAACe,IAAI,IAC5DR,eAAeO,cACrB;QAACZ,gBAAgBa,IAAI,CAACf,MAAM,CAACe,IAAI;QAAER;KAAc;IAGnD,MAAM,CAACS,mBAAmBC,qBAAqB,GAAGnB,SAChD,IACEI,gBAAgBa,IAAI,CAACG,OAAO,EAAEC,IAAI,CAACC;YACjC,OAAO;gBACLZ,MAAMY,MAAML,IAAI,CAACf,MAAM,CAACQ,IAAI;gBAC5BO,MAAMK,MAAML,IAAI,CAACf,MAAM,CAACe,IAAI;YAC9B;QACF,MAAM,EAAE;IAGZ,MAAMM,iBAAiB1B,YAAY,CAAC2B,OAAeC;QACjDN,qBAAqB,CAACO;YACpB,MAAMC,iBAAiB;mBAAID;aAAK;YAChCC,cAAc,CAACH,MAAM,GAAG;gBACtBd,MAAMe,OAAOR,IAAI,CAACf,MAAM,CAACQ,IAAI;gBAC7BO,MAAMQ,OAAOR,IAAI,CAACf,MAAM,CAACe,IAAI;YAC/B;YACA,OAAOU;QACT;IACF,GAAG,EAAE;IAEL,qBACE,MAAClC;QAAoBmC,aAAaV;QAAmBW,SAAS;YAAEjB;YAAiB,GAAGG,kBAAkB;QAAC;;0BACrG,MAAC5B;gBAAK2C,IAAI;gBAACC,IAAI;;kCACb,KAAC3C;wBAAW4C,SAAQ;wBAAKC,cAAc;kCAAG;;kCAG1C,KAAC3C;wBAAc4C,mBAAmB7C;kCAChC,cAAA,KAACG;4BAAaY,iBAAiBA;;;;;0BAGnC,KAACjB;gBAAK2C,IAAI;gBAACC,IAAI;0BACb,cAAA,KAACzC;oBAAc4C,mBAAmB7C;8BAChC,cAAA,KAACK;wBACCS,SAASA;wBACTC,iBAAiBA;wBACjBG,cAAcA;wBACdF,iBAAiBA;wBACjB8B,YAAYZ;wBACZjB,oBAAoBA;;;;;;AAMhC"}
|
|
@@ -2,7 +2,7 @@ import { ReactElement, ReactNode } from 'react';
|
|
|
2
2
|
export interface PanelEditor {
|
|
3
3
|
preview: {
|
|
4
4
|
previewPanelWidth?: number;
|
|
5
|
-
setPreviewPanelWidth
|
|
5
|
+
setPreviewPanelWidth: (width: number) => void;
|
|
6
6
|
};
|
|
7
7
|
}
|
|
8
8
|
export interface PanelEditorProviderProps {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PanelEditorProvider.d.ts","sourceRoot":"","sources":["../../../src/context/PanelEditorProvider/PanelEditorProvider.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAiB,YAAY,EAAE,SAAS,EAAqB,MAAM,OAAO,CAAC;AAElF,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE;QACP,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,oBAAoB,
|
|
1
|
+
{"version":3,"file":"PanelEditorProvider.d.ts","sourceRoot":"","sources":["../../../src/context/PanelEditorProvider/PanelEditorProvider.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAiB,YAAY,EAAE,SAAS,EAAqB,MAAM,OAAO,CAAC;AAElF,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE;QACP,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,oBAAoB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;KAC/C,CAAC;CACH;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,eAAO,MAAM,kBAAkB,kDAAoD,CAAC;AAEpF,eAAO,MAAM,mBAAmB,iBAAkB,wBAAwB,KAAG,YAc5E,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/context/PanelEditorProvider/PanelEditorProvider.tsx"],"sourcesContent":["// Copyright 2025 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 { createContext, ReactElement, ReactNode, useMemo, useState } from 'react';\n\nexport interface PanelEditor {\n preview: {\n previewPanelWidth?: number;\n setPreviewPanelWidth
|
|
1
|
+
{"version":3,"sources":["../../../src/context/PanelEditorProvider/PanelEditorProvider.tsx"],"sourcesContent":["// Copyright 2025 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 { createContext, ReactElement, ReactNode, useMemo, useState } from 'react';\n\nexport interface PanelEditor {\n preview: {\n previewPanelWidth?: number;\n setPreviewPanelWidth: (width: number) => void;\n };\n}\n\nexport interface PanelEditorProviderProps {\n children: ReactNode;\n}\n\nexport const PanelEditorContext = createContext<PanelEditor | undefined>(undefined);\n\nexport const PanelEditorProvider = ({ children }: PanelEditorProviderProps): ReactElement => {\n const [previewPanelWidth, setPreviewPanelWidth] = useState<number | undefined>(undefined);\n\n const ctx = useMemo(\n (): PanelEditor => ({\n preview: {\n previewPanelWidth,\n setPreviewPanelWidth,\n },\n }),\n [previewPanelWidth]\n );\n\n return <PanelEditorContext.Provider value={ctx}>{children}</PanelEditorContext.Provider>;\n};\n"],"names":["createContext","useMemo","useState","PanelEditorContext","undefined","PanelEditorProvider","children","previewPanelWidth","setPreviewPanelWidth","ctx","preview","Provider","value"],"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,aAAa,EAA2BC,OAAO,EAAEC,QAAQ,QAAQ,QAAQ;AAalF,OAAO,MAAMC,mCAAqBH,cAAuCI,WAAW;AAEpF,OAAO,MAAMC,sBAAsB,CAAC,EAAEC,QAAQ,EAA4B;IACxE,MAAM,CAACC,mBAAmBC,qBAAqB,GAAGN,SAA6BE;IAE/E,MAAMK,MAAMR,QACV,IAAoB,CAAA;YAClBS,SAAS;gBACPH;gBACAC;YACF;QACF,CAAA,GACA;QAACD;KAAkB;IAGrB,qBAAO,KAACJ,mBAAmBQ,QAAQ;QAACC,OAAOH;kBAAMH;;AACnD,EAAE"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@perses-dev/dashboards",
|
|
3
|
-
"version": "0.53.0-beta.
|
|
3
|
+
"version": "0.53.0-beta.3",
|
|
4
4
|
"description": "The dashboards feature in Perses",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://github.com/perses/perses/blob/main/README.md",
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
"lint:fix": "eslint --fix src --ext .ts,.tsx"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@perses-dev/components": "0.53.0-beta.
|
|
33
|
-
"@perses-dev/core": "0.53.0-beta.
|
|
34
|
-
"@perses-dev/plugin-system": "0.53.0-beta.
|
|
32
|
+
"@perses-dev/components": "0.53.0-beta.3",
|
|
33
|
+
"@perses-dev/core": "0.53.0-beta.3",
|
|
34
|
+
"@perses-dev/plugin-system": "0.53.0-beta.3",
|
|
35
35
|
"@types/react-grid-layout": "^1.3.2",
|
|
36
36
|
"date-fns": "^4.1.0",
|
|
37
37
|
"immer": "^10.1.1",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"zustand": "^4.3.3"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@perses-dev/internal-utils": "0.53.0-beta.
|
|
49
|
+
"@perses-dev/internal-utils": "0.53.0-beta.3",
|
|
50
50
|
"history": "^5.3.0",
|
|
51
51
|
"intersection-observer": "^0.12.2"
|
|
52
52
|
},
|