@perses-dev/dashboards 0.0.0-snapshot-profile-89b306f → 0.0.0-snapshot-panel-actions-520389b
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/Panel.js +60 -1
- package/dist/cjs/components/Panel/PanelActions.js +86 -16
- package/dist/cjs/components/Panel/PanelContent.js +1 -1
- package/dist/cjs/components/Panel/PanelHeader.js +47 -3
- package/dist/cjs/components/Panel/PanelPluginLoader.js +1 -1
- package/dist/cjs/components/PanelDrawer/PanelPreview.js +2 -2
- package/dist/cjs/components/QuerySummaryTable/QuerySummaryTable.js +1 -1
- package/dist/components/Panel/Panel.d.ts +5 -0
- package/dist/components/Panel/Panel.d.ts.map +1 -1
- package/dist/components/Panel/Panel.js +60 -1
- package/dist/components/Panel/Panel.js.map +1 -1
- package/dist/components/Panel/PanelActions.d.ts +5 -3
- package/dist/components/Panel/PanelActions.d.ts.map +1 -1
- package/dist/components/Panel/PanelActions.js +87 -17
- package/dist/components/Panel/PanelActions.js.map +1 -1
- package/dist/components/Panel/PanelContent.js +1 -1
- package/dist/components/Panel/PanelContent.js.map +1 -1
- package/dist/components/Panel/PanelHeader.d.ts +5 -1
- package/dist/components/Panel/PanelHeader.d.ts.map +1 -1
- package/dist/components/Panel/PanelHeader.js +47 -3
- package/dist/components/Panel/PanelHeader.js.map +1 -1
- package/dist/components/Panel/PanelPluginLoader.js +1 -1
- package/dist/components/Panel/PanelPluginLoader.js.map +1 -1
- package/dist/components/PanelDrawer/PanelPreview.js +2 -2
- package/dist/components/PanelDrawer/PanelPreview.js.map +1 -1
- package/dist/components/QuerySummaryTable/QuerySummaryTable.js +1 -1
- package/dist/components/QuerySummaryTable/QuerySummaryTable.js.map +1 -1
- package/package.json +6 -6
|
@@ -12,8 +12,9 @@
|
|
|
12
12
|
// limitations under the License.
|
|
13
13
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
14
14
|
import { Stack, Box, Popover, CircularProgress, styled } from '@mui/material';
|
|
15
|
-
import { isValidElement, useMemo, useState } from 'react';
|
|
15
|
+
import { isValidElement, useMemo, useState, useEffect } from 'react';
|
|
16
16
|
import { InfoTooltip } from '@perses-dev/components';
|
|
17
|
+
import { usePluginRegistry, useDataQueriesContext } from '@perses-dev/plugin-system';
|
|
17
18
|
import ArrowCollapseIcon from 'mdi-material-ui/ArrowCollapse';
|
|
18
19
|
import ArrowExpandIcon from 'mdi-material-ui/ArrowExpand';
|
|
19
20
|
import PencilIcon from 'mdi-material-ui/PencilOutline';
|
|
@@ -32,7 +33,72 @@ const ConditionalBox = styled(Box)({
|
|
|
32
33
|
flexGrow: 1,
|
|
33
34
|
justifyContent: 'flex-end'
|
|
34
35
|
});
|
|
35
|
-
export const PanelActions = ({ editHandlers, readHandlers, extra, title, description, descriptionTooltipId, links, queryResults })=>{
|
|
36
|
+
export const PanelActions = ({ editHandlers, readHandlers, extra, title, description, descriptionTooltipId, links, queryResults, panelPluginKind, projectName: _propsProjectName, panelProps })=>{
|
|
37
|
+
const { isFetching, errors } = useDataQueriesContext();
|
|
38
|
+
const { getPlugin } = usePluginRegistry();
|
|
39
|
+
const [pluginActions, setPluginActions] = useState([]);
|
|
40
|
+
useEffect(()=>{
|
|
41
|
+
let cancelled = false;
|
|
42
|
+
const loadPluginActions = async ()=>{
|
|
43
|
+
if (!panelPluginKind || !panelProps) {
|
|
44
|
+
if (!cancelled) {
|
|
45
|
+
setPluginActions([]);
|
|
46
|
+
}
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
// Add defensive check for getPlugin availability
|
|
51
|
+
if (!getPlugin || typeof getPlugin !== 'function') {
|
|
52
|
+
if (!cancelled) {
|
|
53
|
+
setPluginActions([]);
|
|
54
|
+
}
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const plugin = await getPlugin('Panel', panelPluginKind);
|
|
58
|
+
if (cancelled) return;
|
|
59
|
+
// More defensive checking for plugin and actions
|
|
60
|
+
if (!plugin || typeof plugin !== 'object' || !plugin.actions || !Array.isArray(plugin.actions) || plugin.actions.length === 0) {
|
|
61
|
+
if (!cancelled) {
|
|
62
|
+
setPluginActions([]);
|
|
63
|
+
}
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
// Render plugin actions in header location
|
|
67
|
+
const headerActions = plugin.actions.filter((action)=>!action.location || action.location === 'header').map((action, index)=>{
|
|
68
|
+
const ActionComponent = action.component;
|
|
69
|
+
try {
|
|
70
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
71
|
+
return /*#__PURE__*/ _jsx(ActionComponent, {
|
|
72
|
+
...panelProps
|
|
73
|
+
}, `plugin-action-${index}`);
|
|
74
|
+
} catch (error) {
|
|
75
|
+
console.warn(`Failed to render plugin action ${index}:`, error);
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
}).filter((item)=>Boolean(item));
|
|
79
|
+
if (!cancelled) {
|
|
80
|
+
setPluginActions(headerActions);
|
|
81
|
+
}
|
|
82
|
+
} catch (error) {
|
|
83
|
+
if (!cancelled) {
|
|
84
|
+
console.warn('Failed to load plugin actions:', error);
|
|
85
|
+
setPluginActions([]);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
// Use setTimeout to defer the async operation to the next tick
|
|
90
|
+
const timeoutId = setTimeout(()=>{
|
|
91
|
+
loadPluginActions();
|
|
92
|
+
}, 0);
|
|
93
|
+
return ()=>{
|
|
94
|
+
cancelled = true;
|
|
95
|
+
clearTimeout(timeoutId);
|
|
96
|
+
};
|
|
97
|
+
}, [
|
|
98
|
+
panelPluginKind,
|
|
99
|
+
panelProps,
|
|
100
|
+
getPlugin
|
|
101
|
+
]);
|
|
36
102
|
const descriptionAction = useMemo(()=>{
|
|
37
103
|
if (description && description.trim().length > 0) {
|
|
38
104
|
return /*#__PURE__*/ _jsx(InfoTooltip, {
|
|
@@ -63,19 +129,23 @@ export const PanelActions = ({ editHandlers, readHandlers, extra, title, descrip
|
|
|
63
129
|
});
|
|
64
130
|
const extraActions = editHandlers === undefined && extra;
|
|
65
131
|
const queryStateIndicator = useMemo(()=>{
|
|
66
|
-
const hasData = queryResults.
|
|
67
|
-
const isFetching = queryResults.some((q)=>q.isFetching);
|
|
68
|
-
const queryErrors = queryResults.filter((q)=>q.error);
|
|
132
|
+
const hasData = queryResults && queryResults.series && queryResults.series.length > 0;
|
|
69
133
|
if (isFetching && hasData) {
|
|
70
|
-
// If the panel has no data, the panel content will show the loading overlay.
|
|
71
|
-
// Therefore, show the circular loading indicator only in case the panel doesn't display the loading overlay already.
|
|
72
134
|
return /*#__PURE__*/ _jsx(CircularProgress, {
|
|
73
135
|
"aria-label": "loading",
|
|
74
136
|
size: "1.125rem"
|
|
75
137
|
});
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
138
|
+
}
|
|
139
|
+
const validErrors = (errors || []).filter((error)=>error !== null);
|
|
140
|
+
if (validErrors.length > 0) {
|
|
141
|
+
const errorTexts = validErrors.map((e)=>{
|
|
142
|
+
if (typeof e === 'string') return e;
|
|
143
|
+
if (e && typeof e === 'object') {
|
|
144
|
+
const errorObj = e;
|
|
145
|
+
return errorObj.message ?? errorObj.toString?.() ?? 'Unknown error';
|
|
146
|
+
}
|
|
147
|
+
return 'Unknown error';
|
|
148
|
+
}).join('\n');
|
|
79
149
|
return /*#__PURE__*/ _jsx(InfoTooltip, {
|
|
80
150
|
description: errorTexts,
|
|
81
151
|
children: /*#__PURE__*/ _jsx(HeaderIconButton, {
|
|
@@ -88,7 +158,9 @@ export const PanelActions = ({ editHandlers, readHandlers, extra, title, descrip
|
|
|
88
158
|
});
|
|
89
159
|
}
|
|
90
160
|
}, [
|
|
91
|
-
queryResults
|
|
161
|
+
queryResults,
|
|
162
|
+
isFetching,
|
|
163
|
+
errors
|
|
92
164
|
]);
|
|
93
165
|
const readActions = useMemo(()=>{
|
|
94
166
|
if (readHandlers !== undefined) {
|
|
@@ -113,7 +185,6 @@ export const PanelActions = ({ editHandlers, readHandlers, extra, title, descrip
|
|
|
113
185
|
]);
|
|
114
186
|
const editActions = useMemo(()=>{
|
|
115
187
|
if (editHandlers !== undefined) {
|
|
116
|
-
// If there are edit handlers, always just show the edit buttons
|
|
117
188
|
return /*#__PURE__*/ _jsxs(_Fragment, {
|
|
118
189
|
children: [
|
|
119
190
|
/*#__PURE__*/ _jsx(InfoTooltip, {
|
|
@@ -136,8 +207,6 @@ export const PanelActions = ({ editHandlers, readHandlers, extra, title, descrip
|
|
|
136
207
|
children: /*#__PURE__*/ _jsx(ContentCopyIcon, {
|
|
137
208
|
fontSize: "inherit",
|
|
138
209
|
sx: {
|
|
139
|
-
// Shrink this icon a little bit to look more consistent
|
|
140
|
-
// with the other icons in the header.
|
|
141
210
|
transform: 'scale(0.925)'
|
|
142
211
|
}
|
|
143
212
|
})
|
|
@@ -227,6 +296,7 @@ export const PanelActions = ({ editHandlers, readHandlers, extra, title, descrip
|
|
|
227
296
|
editActions
|
|
228
297
|
]
|
|
229
298
|
}),
|
|
299
|
+
pluginActions,
|
|
230
300
|
moveAction
|
|
231
301
|
]
|
|
232
302
|
})
|
|
@@ -254,6 +324,7 @@ export const PanelActions = ({ editHandlers, readHandlers, extra, title, descrip
|
|
|
254
324
|
extraActions,
|
|
255
325
|
" ",
|
|
256
326
|
readActions,
|
|
327
|
+
pluginActions,
|
|
257
328
|
/*#__PURE__*/ _jsx(OverflowMenu, {
|
|
258
329
|
title: title,
|
|
259
330
|
children: editActions
|
|
@@ -265,7 +336,6 @@ export const PanelActions = ({ editHandlers, readHandlers, extra, title, descrip
|
|
|
265
336
|
}),
|
|
266
337
|
/*#__PURE__*/ _jsxs(ConditionalBox, {
|
|
267
338
|
sx: (theme)=>({
|
|
268
|
-
// flip the logic here; if the browser (or jsdom) does not support container queries, always show all icons
|
|
269
339
|
display: 'flex',
|
|
270
340
|
[theme.containerQueries(HEADER_ACTIONS_CONTAINER_NAME).down(HEADER_MEDIUM_WIDTH)]: {
|
|
271
341
|
display: 'none'
|
|
@@ -287,7 +357,7 @@ export const PanelActions = ({ editHandlers, readHandlers, extra, title, descrip
|
|
|
287
357
|
extraActions,
|
|
288
358
|
" ",
|
|
289
359
|
readActions,
|
|
290
|
-
|
|
360
|
+
pluginActions,
|
|
291
361
|
editActions,
|
|
292
362
|
" ",
|
|
293
363
|
moveAction
|
|
@@ -300,7 +370,7 @@ export const PanelActions = ({ editHandlers, readHandlers, extra, title, descrip
|
|
|
300
370
|
};
|
|
301
371
|
const OverflowMenu = ({ children, title })=>{
|
|
302
372
|
const [anchorPosition, setAnchorPosition] = useState();
|
|
303
|
-
// do not show overflow menu if there is no content
|
|
373
|
+
// do not show overflow menu if there is no content
|
|
304
374
|
const hasContent = /*#__PURE__*/ isValidElement(children) || Array.isArray(children) && children.some(isValidElement);
|
|
305
375
|
if (!hasContent) {
|
|
306
376
|
return undefined;
|
|
@@ -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 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 { QueryData } from '@perses-dev/plugin-system';\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';\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 queryResults: QueryData[];\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 extra,\n title,\n description,\n descriptionTooltipId,\n links,\n queryResults,\n}) => {\n const descriptionAction = useMemo(() => {\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 const linksAction = links && links.length > 0 && <PanelLinks links={links} />;\n const extraActions = editHandlers === undefined && extra;\n\n const queryStateIndicator = useMemo(() => {\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 if (isFetching && hasData) {\n // If the panel has no data, the panel content will show the loading overlay.\n // Therefore, show the circular loading indicator only in case the panel doesn't display the loading overlay already.\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: any) => e?.message ?? e?.toString() ?? 'Unknown error') // eslint-disable-line @typescript-eslint/no-explicit-any\n .join('\\n');\n\n return (\n <InfoTooltip description={errorTexts}>\n <HeaderIconButton aria-label=\"panel errors\" size=\"small\">\n <AlertIcon fontSize=\"inherit\" />\n </HeaderIconButton>\n </InfoTooltip>\n );\n }\n }, [queryResults]);\n\n const readActions = useMemo(() => {\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 editActions = useMemo(() => {\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(() => {\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 // if the panel is in non-editing, non-fullscreen mode, show certain icons only on hover\n const OnHover = ({ children }: PropsWithChildren): ReactNode =>\n editHandlers === undefined && !readHandlers?.isPanelViewed ? (\n <Box sx={{ display: 'var(--panel-hover, none)' }}>{children}</Box>\n ) : (\n <>{children}</>\n );\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} {readActions} {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} {readActions}\n <OverflowMenu title={title}>{editActions}</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} {readActions} {editActions} {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 undefined;\n }\n\n const handleClick = (event: React.MouseEvent<HTMLElement>): undefined => {\n setAnchorPosition(event.currentTarget.getBoundingClientRect());\n };\n\n const handleClose = (): undefined => {\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","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","extra","title","description","descriptionTooltipId","links","queryResults","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","toString","join","readActions","viewPanel","onClick","onViewPanelClick","isPanelViewed","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, useEffect, ReactElement } from 'react';\nimport { InfoTooltip } from '@perses-dev/components';\nimport { usePluginRegistry, useDataQueriesContext } from '@perses-dev/plugin-system';\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, TimeSeriesData } 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';\n\nexport interface PanelActionsProps {\n title: string;\n description?: string;\n descriptionTooltipId: string;\n links?: Link[];\n extra?: React.ReactNode;\n panelPluginKind: string;\n editHandlers?: {\n onEditPanelClick: () => void;\n onDuplicatePanelClick: () => void;\n onDeletePanelClick: () => void;\n };\n readHandlers?: {\n isPanelViewed?: boolean;\n onViewPanelClick: () => void;\n };\n queryResults: TimeSeriesData | undefined;\n projectName?: string;\n panelProps?: Record<string, unknown>;\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 extra,\n title,\n description,\n descriptionTooltipId,\n links,\n queryResults,\n panelPluginKind,\n projectName: _propsProjectName,\n panelProps,\n}) => {\n const { isFetching, errors } = useDataQueriesContext();\n const { getPlugin } = usePluginRegistry();\n\n const [pluginActions, setPluginActions] = useState<ReactNode[]>([]);\n\n useEffect(() => {\n let cancelled = false;\n\n const loadPluginActions = async (): Promise<void> => {\n if (!panelPluginKind || !panelProps) {\n if (!cancelled) {\n setPluginActions([]);\n }\n return;\n }\n\n try {\n // Add defensive check for getPlugin availability\n if (!getPlugin || typeof getPlugin !== 'function') {\n if (!cancelled) {\n setPluginActions([]);\n }\n return;\n }\n\n const plugin = await getPlugin('Panel', panelPluginKind);\n\n if (cancelled) return;\n\n // More defensive checking for plugin and actions\n if (\n !plugin ||\n typeof plugin !== 'object' ||\n !plugin.actions ||\n !Array.isArray(plugin.actions) ||\n plugin.actions.length === 0\n ) {\n if (!cancelled) {\n setPluginActions([]);\n }\n return;\n }\n\n // Render plugin actions in header location\n const headerActions = plugin.actions\n .filter((action) => !action.location || action.location === 'header')\n .map((action, index): ReactNode | null => {\n const ActionComponent = action.component;\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return <ActionComponent key={`plugin-action-${index}`} {...(panelProps as any)} />;\n } catch (error) {\n console.warn(`Failed to render plugin action ${index}:`, error);\n return null;\n }\n })\n .filter((item): item is ReactNode => Boolean(item));\n\n if (!cancelled) {\n setPluginActions(headerActions);\n }\n } catch (error) {\n if (!cancelled) {\n console.warn('Failed to load plugin actions:', error);\n setPluginActions([]);\n }\n }\n };\n\n // Use setTimeout to defer the async operation to the next tick\n const timeoutId = setTimeout(() => {\n loadPluginActions();\n }, 0);\n\n return (): void => {\n cancelled = true;\n clearTimeout(timeoutId);\n };\n }, [panelPluginKind, panelProps, getPlugin]);\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 && queryResults.series && queryResults.series.length > 0;\n if (isFetching && hasData) {\n return <CircularProgress aria-label=\"loading\" size=\"1.125rem\" />;\n }\n const validErrors = (errors || []).filter((error) => error !== null);\n if (validErrors.length > 0) {\n const errorTexts = validErrors\n .map((e: unknown) => {\n if (typeof e === 'string') return e;\n if (e && typeof e === 'object') {\n const errorObj = e as { message?: string; toString?: () => string };\n return errorObj.message ?? errorObj.toString?.() ?? 'Unknown error';\n }\n return 'Unknown error';\n })\n .join('\\n');\n\n return (\n <InfoTooltip description={errorTexts}>\n <HeaderIconButton aria-label=\"panel errors\" size=\"small\">\n <AlertIcon fontSize=\"inherit\" />\n </HeaderIconButton>\n </InfoTooltip>\n );\n }\n }, [queryResults, isFetching, errors]);\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 editActions = useMemo((): ReactNode | undefined => {\n if (editHandlers !== undefined) {\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 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 // if the panel is in non-editing, non-fullscreen mode, show certain icons only on hover\n const OnHover = ({ children }: PropsWithChildren): ReactNode =>\n editHandlers === undefined && !readHandlers?.isPanelViewed ? (\n <Box sx={{ display: 'var(--panel-hover, none)' }}>{children}</Box>\n ) : (\n <>{children}</>\n );\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} {readActions} {editActions}\n </OverflowMenu>\n {pluginActions}\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} {readActions}\n {pluginActions}\n <OverflowMenu title={title}>{editActions}</OverflowMenu>\n {moveAction}\n </OnHover>\n </ConditionalBox>\n\n {/* large panel width: show all icons in panel header */}\n <ConditionalBox\n sx={(theme) => ({\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} {readActions}\n {pluginActions}\n {editActions} {moveAction}\n </OnHover>\n </ConditionalBox>\n </>\n );\n};\n\nconst OverflowMenu: React.FC<PropsWithChildren<{ title: string }>> = ({\n children,\n title,\n}): ReactElement | undefined => {\n const [anchorPosition, setAnchorPosition] = useState<PopoverPosition>();\n\n // do not show overflow menu if there is no content\n const hasContent = isValidElement(children) || (Array.isArray(children) && children.some(isValidElement));\n if (!hasContent) {\n return undefined;\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","useEffect","InfoTooltip","usePluginRegistry","useDataQueriesContext","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","extra","title","description","descriptionTooltipId","links","queryResults","panelPluginKind","projectName","_propsProjectName","panelProps","isFetching","errors","getPlugin","pluginActions","setPluginActions","cancelled","loadPluginActions","plugin","actions","Array","isArray","length","headerActions","filter","action","location","map","index","ActionComponent","component","error","console","warn","item","Boolean","timeoutId","setTimeout","clearTimeout","descriptionAction","trim","id","enterDelay","aria-label","size","aria-describedby","aria-hidden","fontSize","sx","color","theme","palette","text","secondary","undefined","linksAction","extraActions","queryStateIndicator","hasData","series","validErrors","errorTexts","e","errorObj","message","toString","join","readActions","viewPanel","onClick","onViewPanelClick","isPanelViewed","editActions","editPanel","onEditPanelClick","duplicatePanel","onDuplicatePanelClick","transform","deletePanel","onDeletePanelClick","moveAction","movePanel","className","cursor","divider","OnHover","children","containerQueries","between","OverflowMenu","down","anchorPosition","setAnchorPosition","hasContent","some","handleClick","event","currentTarget","getBoundingClientRect","handleClose","open","showPanelActions","anchorReference","onClose","anchorOrigin","vertical","horizontal","direction","padding"],"mappings":"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"}
|
|
@@ -21,7 +21,7 @@ import { PanelPluginLoader } from './PanelPluginLoader';
|
|
|
21
21
|
*/ export function PanelContent(props) {
|
|
22
22
|
const { panelPluginKind, definition, queryResults, spec, contentDimensions } = props;
|
|
23
23
|
const { data: plugin, isLoading: isPanelLoading } = usePlugin('Panel', panelPluginKind, {
|
|
24
|
-
|
|
24
|
+
useErrorBoundary: true
|
|
25
25
|
});
|
|
26
26
|
// Show fullsize skeleton if the panel plugin is loading.
|
|
27
27
|
if (isPanelLoading) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/Panel/PanelContent.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 { usePlugin, PanelProps, QueryData, PanelPlugin } from '@perses-dev/plugin-system';\nimport { UnknownSpec, PanelDefinition, QueryDataType } from '@perses-dev/core';\nimport { ReactElement } from 'react';\nimport { LoadingOverlay } from '@perses-dev/components';\nimport { Skeleton } from '@mui/material';\nimport { PanelPluginLoader } from './PanelPluginLoader';\n\nexport interface PanelContentProps extends Omit<PanelProps<UnknownSpec>, 'queryResults'> {\n panelPluginKind: string;\n definition?: PanelDefinition<UnknownSpec>;\n queryResults: QueryData[];\n}\n\n/**\n * Based on the status of the queries (loading, error or data available), this component renders a\n * loading overlay, throws an error, or renders the panel content.\n */\nexport function PanelContent(props: PanelContentProps): ReactElement {\n const { panelPluginKind, definition, queryResults, spec, contentDimensions } = props;\n const { data: plugin, isLoading: isPanelLoading } = usePlugin('Panel', panelPluginKind, {
|
|
1
|
+
{"version":3,"sources":["../../../src/components/Panel/PanelContent.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 { usePlugin, PanelProps, QueryData, PanelPlugin } from '@perses-dev/plugin-system';\nimport { UnknownSpec, PanelDefinition, QueryDataType } from '@perses-dev/core';\nimport { ReactElement } from 'react';\nimport { LoadingOverlay } from '@perses-dev/components';\nimport { Skeleton } from '@mui/material';\nimport { PanelPluginLoader } from './PanelPluginLoader';\n\nexport interface PanelContentProps extends Omit<PanelProps<UnknownSpec>, 'queryResults'> {\n panelPluginKind: string;\n definition?: PanelDefinition<UnknownSpec>;\n queryResults: QueryData[];\n}\n\n/**\n * Based on the status of the queries (loading, error or data available), this component renders a\n * loading overlay, throws an error, or renders the panel content.\n */\nexport function PanelContent(props: PanelContentProps): ReactElement {\n const { panelPluginKind, definition, queryResults, spec, contentDimensions } = props;\n const { data: plugin, isLoading: isPanelLoading } = usePlugin('Panel', panelPluginKind, { useErrorBoundary: true });\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 // Render the panel if any query has data, or the panel doesn't have a query attached (for example MarkdownPanel).\n // Loading indicator or errors of other queries are shown in the panel header.\n const queryResultsWithData = queryResults.flatMap((q) =>\n q.data ? [{ data: q.data, definition: q.definition }] : []\n );\n if (queryResultsWithData.length > 0 || queryResults.length === 0) {\n return (\n <PanelPluginLoader\n kind={panelPluginKind}\n spec={spec}\n contentDimensions={contentDimensions}\n definition={definition}\n queryResults={queryResultsWithData}\n />\n );\n }\n\n // No query has data, show loading overlay if any query is fetching data.\n if (queryResults.some((q) => q.isFetching)) {\n return <PanelLoading plugin={plugin} spec={spec} definition={definition} contentDimensions={contentDimensions} />;\n }\n\n // No query has data or is loading, show the error if any query has an error.\n // The error will be catched in <ErrorBoundary> of <Panel>.\n const queryError = queryResults.find((q) => q.error);\n if (queryError) {\n throw queryError.error;\n }\n\n // At this point, one or more queries are defined, but no query has data, is loading, or has an error.\n // This can happen if all queries are disabled (e.g. dependent dashboard variables are loading, or they are not in the viewport of the browser).\n // Most likely, some query will be enabled later. Render the panel loading skeleton.\n return <PanelLoading plugin={plugin} spec={spec} definition={definition} contentDimensions={contentDimensions} />;\n}\n\ninterface PanelLoadingProps extends Pick<PanelContentProps, 'spec' | 'definition' | 'contentDimensions'> {\n plugin?: PanelPlugin<UnknownSpec, PanelProps<UnknownSpec, QueryDataType>>;\n}\n\nfunction PanelLoading({ plugin, spec, definition, contentDimensions }: PanelLoadingProps): ReactElement {\n if (plugin?.LoadingComponent) {\n return (\n <plugin.LoadingComponent\n spec={spec}\n contentDimensions={contentDimensions}\n definition={definition}\n queryResults={[]}\n />\n );\n }\n return <LoadingOverlay />;\n}\n"],"names":["usePlugin","LoadingOverlay","Skeleton","PanelPluginLoader","PanelContent","props","panelPluginKind","definition","queryResults","spec","contentDimensions","data","plugin","isLoading","isPanelLoading","useErrorBoundary","variant","width","height","aria-label","queryResultsWithData","flatMap","q","length","kind","some","isFetching","PanelLoading","queryError","find","error","LoadingComponent"],"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,QAA4C,4BAA4B;AAG1F,SAASC,cAAc,QAAQ,yBAAyB;AACxD,SAASC,QAAQ,QAAQ,gBAAgB;AACzC,SAASC,iBAAiB,QAAQ,sBAAsB;AAQxD;;;CAGC,GACD,OAAO,SAASC,aAAaC,KAAwB;IACnD,MAAM,EAAEC,eAAe,EAAEC,UAAU,EAAEC,YAAY,EAAEC,IAAI,EAAEC,iBAAiB,EAAE,GAAGL;IAC/E,MAAM,EAAEM,MAAMC,MAAM,EAAEC,WAAWC,cAAc,EAAE,GAAGd,UAAU,SAASM,iBAAiB;QAAES,kBAAkB;IAAK;IAEjH,yDAAyD;IACzD,IAAID,gBAAgB;QAClB,qBACE,KAACZ;YACCc,SAAQ;YACRC,OAAOP,mBAAmBO;YAC1BC,QAAQR,mBAAmBQ;YAC3BC,cAAW;;IAGjB;IAEA,kHAAkH;IAClH,8EAA8E;IAC9E,MAAMC,uBAAuBZ,aAAaa,OAAO,CAAC,CAACC,IACjDA,EAAEX,IAAI,GAAG;YAAC;gBAAEA,MAAMW,EAAEX,IAAI;gBAAEJ,YAAYe,EAAEf,UAAU;YAAC;SAAE,GAAG,EAAE;IAE5D,IAAIa,qBAAqBG,MAAM,GAAG,KAAKf,aAAae,MAAM,KAAK,GAAG;QAChE,qBACE,KAACpB;YACCqB,MAAMlB;YACNG,MAAMA;YACNC,mBAAmBA;YACnBH,YAAYA;YACZC,cAAcY;;IAGpB;IAEA,yEAAyE;IACzE,IAAIZ,aAAaiB,IAAI,CAAC,CAACH,IAAMA,EAAEI,UAAU,GAAG;QAC1C,qBAAO,KAACC;YAAaf,QAAQA;YAAQH,MAAMA;YAAMF,YAAYA;YAAYG,mBAAmBA;;IAC9F;IAEA,6EAA6E;IAC7E,2DAA2D;IAC3D,MAAMkB,aAAapB,aAAaqB,IAAI,CAAC,CAACP,IAAMA,EAAEQ,KAAK;IACnD,IAAIF,YAAY;QACd,MAAMA,WAAWE,KAAK;IACxB;IAEA,sGAAsG;IACtG,gJAAgJ;IAChJ,oFAAoF;IACpF,qBAAO,KAACH;QAAaf,QAAQA;QAAQH,MAAMA;QAAMF,YAAYA;QAAYG,mBAAmBA;;AAC9F;AAMA,SAASiB,aAAa,EAAEf,MAAM,EAAEH,IAAI,EAAEF,UAAU,EAAEG,iBAAiB,EAAqB;IACtF,IAAIE,QAAQmB,kBAAkB;QAC5B,qBACE,KAACnB,OAAOmB,gBAAgB;YACtBtB,MAAMA;YACNC,mBAAmBA;YACnBH,YAAYA;YACZC,cAAc,EAAE;;IAGtB;IACA,qBAAO,KAACP;AACV"}
|
|
@@ -11,9 +11,13 @@ export interface PanelHeaderProps extends Omit<CardHeaderProps, OmittedProps> {
|
|
|
11
11
|
links?: Link[];
|
|
12
12
|
extra?: ReactNode;
|
|
13
13
|
queryResults: QueryData[];
|
|
14
|
+
panelPluginKind: string;
|
|
14
15
|
readHandlers?: PanelActionsProps['readHandlers'];
|
|
15
16
|
editHandlers?: PanelActionsProps['editHandlers'];
|
|
17
|
+
projectName?: string;
|
|
18
|
+
panelProps?: Record<string, unknown>;
|
|
16
19
|
}
|
|
17
|
-
export declare function PanelHeader({ id, title: rawTitle, description: rawDescription, links, queryResults, readHandlers, editHandlers, sx, extra,
|
|
20
|
+
export declare function PanelHeader({ id, title: rawTitle, description: rawDescription, links, queryResults, readHandlers, editHandlers, sx, extra, panelPluginKind, projectName, panelProps, // ========== ADDED ==========
|
|
21
|
+
...rest }: PanelHeaderProps): ReactElement;
|
|
18
22
|
export {};
|
|
19
23
|
//# sourceMappingURL=PanelHeader.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PanelHeader.d.ts","sourceRoot":"","sources":["../../../src/components/Panel/PanelHeader.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAc,eAAe,EAAqB,MAAM,eAAe,CAAC;AAE/E,OAAO,EAAE,IAAI,
|
|
1
|
+
{"version":3,"file":"PanelHeader.d.ts","sourceRoot":"","sources":["../../../src/components/Panel/PanelHeader.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAc,eAAe,EAAqB,MAAM,eAAe,CAAC;AAE/E,OAAO,EAAE,IAAI,EAAkD,MAAM,kBAAkB,CAAC;AACxF,OAAO,EAAE,SAAS,EAA+B,MAAM,2BAA2B,CAAC;AACnF,OAAO,EAAE,YAAY,EAAE,SAAS,EAAW,MAAM,OAAO,CAAC;AAEzD,OAAO,EAAgB,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEjE,KAAK,YAAY,GAAG,UAAU,GAAG,QAAQ,GAAG,OAAO,GAAG,mBAAmB,CAAC;AAO1E,MAAM,WAAW,gBAAiB,SAAQ,IAAI,CAAC,eAAe,EAAE,YAAY,CAAC;IAC3E,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;IACf,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,YAAY,EAAE,SAAS,EAAE,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,iBAAiB,CAAC,cAAc,CAAC,CAAC;IACjD,YAAY,CAAC,EAAE,iBAAiB,CAAC,cAAc,CAAC,CAAC;IACjD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,wBAAgB,WAAW,CAAC,EAC1B,EAAE,EACF,KAAK,EAAE,QAAQ,EACf,WAAW,EAAE,cAAc,EAC3B,KAAK,EACL,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,EAAE,EACF,KAAK,EACL,eAAe,EACf,WAAW,EACX,UAAU,EAAE,8BAA8B;AAC1C,GAAG,IAAI,EACR,EAAE,gBAAgB,GAAG,YAAY,CA2GjC"}
|
|
@@ -14,13 +14,53 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
14
14
|
import { CardHeader, Stack, Typography } from '@mui/material';
|
|
15
15
|
import { combineSx } from '@perses-dev/components';
|
|
16
16
|
import { useReplaceVariablesInString } from '@perses-dev/plugin-system';
|
|
17
|
+
import { useMemo } from 'react';
|
|
17
18
|
import { HEADER_ACTIONS_CONTAINER_NAME } from '../../constants';
|
|
18
19
|
import { PanelActions } from './PanelActions';
|
|
19
|
-
export function PanelHeader({ id, title: rawTitle, description: rawDescription, links, queryResults, readHandlers, editHandlers, sx, extra, ...rest }) {
|
|
20
|
+
export function PanelHeader({ id, title: rawTitle, description: rawDescription, links, queryResults, readHandlers, editHandlers, sx, extra, panelPluginKind, projectName, panelProps, ...rest }) {
|
|
20
21
|
const titleElementId = `${id}-title`;
|
|
21
22
|
const descriptionTooltipId = `${id}-description`;
|
|
22
23
|
const title = useReplaceVariablesInString(rawTitle);
|
|
23
24
|
const description = useReplaceVariablesInString(rawDescription);
|
|
25
|
+
const timeSeriesDataForExport = useMemo(()=>{
|
|
26
|
+
// Collect all series from all queries
|
|
27
|
+
const allSeries = [];
|
|
28
|
+
let timeRange = undefined;
|
|
29
|
+
let stepMs = undefined;
|
|
30
|
+
let metadata = undefined;
|
|
31
|
+
queryResults.forEach((query)=>{
|
|
32
|
+
if (query.data && 'series' in query.data) {
|
|
33
|
+
const timeSeriesData = query.data;
|
|
34
|
+
// Collect series from this query
|
|
35
|
+
if (timeSeriesData.series && timeSeriesData.series.length > 0) {
|
|
36
|
+
allSeries.push(...timeSeriesData.series);
|
|
37
|
+
// Use the first query's metadata/timeRange/stepMs as the base
|
|
38
|
+
if (!timeRange && timeSeriesData.timeRange) {
|
|
39
|
+
timeRange = timeSeriesData.timeRange;
|
|
40
|
+
}
|
|
41
|
+
if (!stepMs && timeSeriesData.stepMs) {
|
|
42
|
+
stepMs = timeSeriesData.stepMs;
|
|
43
|
+
}
|
|
44
|
+
if (!metadata && timeSeriesData.metadata) {
|
|
45
|
+
metadata = timeSeriesData.metadata;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
// If we found series, create a combined TimeSeriesData object
|
|
51
|
+
if (allSeries.length > 0) {
|
|
52
|
+
const combinedData = {
|
|
53
|
+
series: allSeries,
|
|
54
|
+
timeRange,
|
|
55
|
+
stepMs,
|
|
56
|
+
metadata
|
|
57
|
+
};
|
|
58
|
+
return combinedData;
|
|
59
|
+
}
|
|
60
|
+
return undefined;
|
|
61
|
+
}, [
|
|
62
|
+
queryResults
|
|
63
|
+
]);
|
|
24
64
|
return /*#__PURE__*/ _jsx(CardHeader, {
|
|
25
65
|
id: id,
|
|
26
66
|
component: "header",
|
|
@@ -49,10 +89,14 @@ export function PanelHeader({ id, title: rawTitle, description: rawDescription,
|
|
|
49
89
|
description: description,
|
|
50
90
|
descriptionTooltipId: descriptionTooltipId,
|
|
51
91
|
links: links,
|
|
52
|
-
queryResults:
|
|
92
|
+
queryResults: timeSeriesDataForExport,
|
|
93
|
+
panelPluginKind: panelPluginKind,
|
|
53
94
|
readHandlers: readHandlers,
|
|
54
95
|
editHandlers: editHandlers,
|
|
55
|
-
extra: extra
|
|
96
|
+
extra: extra,
|
|
97
|
+
projectName: projectName,
|
|
98
|
+
// ========== ADDED: Pass panel props for actions ==========
|
|
99
|
+
panelProps: panelProps
|
|
56
100
|
})
|
|
57
101
|
]
|
|
58
102
|
}),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/Panel/PanelHeader.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 { CardHeader, CardHeaderProps, Stack, Typography } from '@mui/material';\nimport { combineSx } from '@perses-dev/components';\nimport { Link } from '@perses-dev/core';\nimport { QueryData, useReplaceVariablesInString } from '@perses-dev/plugin-system';\nimport { ReactElement, ReactNode } from 'react';\nimport { HEADER_ACTIONS_CONTAINER_NAME } from '../../constants';\nimport { PanelActions, PanelActionsProps } from './PanelActions';\n\ntype OmittedProps = 'children' | 'action' | 'title' | 'disableTypography';\n\nexport interface PanelHeaderProps extends Omit<CardHeaderProps, OmittedProps> {\n id: string;\n title: string;\n description?: string;\n links?: Link[];\n extra?: ReactNode;\n queryResults: QueryData[];\n readHandlers?: PanelActionsProps['readHandlers'];\n editHandlers?: PanelActionsProps['editHandlers'];\n}\n\nexport function PanelHeader({\n id,\n title: rawTitle,\n description: rawDescription,\n links,\n queryResults,\n readHandlers,\n editHandlers,\n sx,\n extra,\n ...rest\n}: PanelHeaderProps): ReactElement {\n const titleElementId = `${id}-title`;\n const descriptionTooltipId = `${id}-description`;\n\n const title = useReplaceVariablesInString(rawTitle) as string;\n const description = useReplaceVariablesInString(rawDescription);\n\n return (\n <CardHeader\n id={id}\n component=\"header\"\n aria-labelledby={titleElementId}\n aria-describedby={descriptionTooltipId}\n disableTypography\n title={\n <Stack direction=\"row\">\n <Typography\n id={titleElementId}\n variant=\"subtitle1\"\n sx={{\n // `minHeight` guarantees that the header has the correct height\n // when there is no title (i.e. in the preview)\n lineHeight: '24px',\n minHeight: '26px',\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n }}\n >\n {title}\n </Typography>\n <PanelActions\n title={title}\n description={description}\n descriptionTooltipId={descriptionTooltipId}\n links={links}\n queryResults={
|
|
1
|
+
{"version":3,"sources":["../../../src/components/Panel/PanelHeader.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 { CardHeader, CardHeaderProps, Stack, Typography } from '@mui/material';\nimport { combineSx } from '@perses-dev/components';\nimport { Link, TimeSeriesData, TimeSeries, TimeSeriesMetadata } from '@perses-dev/core';\nimport { QueryData, useReplaceVariablesInString } from '@perses-dev/plugin-system';\nimport { ReactElement, ReactNode, useMemo } from 'react';\nimport { HEADER_ACTIONS_CONTAINER_NAME } from '../../constants';\nimport { PanelActions, PanelActionsProps } from './PanelActions';\n\ntype OmittedProps = 'children' | 'action' | 'title' | 'disableTypography';\n\ninterface AbsoluteTimeRange {\n start: Date;\n end: Date;\n}\n\nexport interface PanelHeaderProps extends Omit<CardHeaderProps, OmittedProps> {\n id: string;\n title: string;\n description?: string;\n links?: Link[];\n extra?: ReactNode;\n queryResults: QueryData[];\n panelPluginKind: string;\n readHandlers?: PanelActionsProps['readHandlers'];\n editHandlers?: PanelActionsProps['editHandlers'];\n projectName?: string;\n panelProps?: Record<string, unknown>;\n}\n\nexport function PanelHeader({\n id,\n title: rawTitle,\n description: rawDescription,\n links,\n queryResults,\n readHandlers,\n editHandlers,\n sx,\n extra,\n panelPluginKind,\n projectName,\n panelProps, // ========== ADDED ==========\n ...rest\n}: PanelHeaderProps): ReactElement {\n const titleElementId = `${id}-title`;\n const descriptionTooltipId = `${id}-description`;\n\n const title = useReplaceVariablesInString(rawTitle) as string;\n const description = useReplaceVariablesInString(rawDescription);\n\n const timeSeriesDataForExport = useMemo(() => {\n // Collect all series from all queries\n const allSeries: TimeSeries[] = [];\n let timeRange: AbsoluteTimeRange | undefined = undefined;\n let stepMs: number | undefined = undefined;\n let metadata: TimeSeriesMetadata | undefined = undefined;\n\n queryResults.forEach((query) => {\n if (query.data && 'series' in query.data) {\n const timeSeriesData = query.data as TimeSeriesData;\n\n // Collect series from this query\n if (timeSeriesData.series && timeSeriesData.series.length > 0) {\n allSeries.push(...timeSeriesData.series);\n\n // Use the first query's metadata/timeRange/stepMs as the base\n if (!timeRange && timeSeriesData.timeRange) {\n timeRange = timeSeriesData.timeRange;\n }\n if (!stepMs && timeSeriesData.stepMs) {\n stepMs = timeSeriesData.stepMs;\n }\n if (!metadata && timeSeriesData.metadata) {\n metadata = timeSeriesData.metadata;\n }\n }\n }\n });\n\n // If we found series, create a combined TimeSeriesData object\n if (allSeries.length > 0) {\n const combinedData: TimeSeriesData = {\n series: allSeries,\n timeRange,\n stepMs,\n metadata,\n };\n\n return combinedData;\n }\n\n return undefined;\n }, [queryResults]);\n\n return (\n <CardHeader\n id={id}\n component=\"header\"\n aria-labelledby={titleElementId}\n aria-describedby={descriptionTooltipId}\n disableTypography\n title={\n <Stack direction=\"row\">\n <Typography\n id={titleElementId}\n variant=\"subtitle1\"\n sx={{\n // `minHeight` guarantees that the header has the correct height\n // when there is no title (i.e. in the preview)\n lineHeight: '24px',\n minHeight: '26px',\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n }}\n >\n {title}\n </Typography>\n <PanelActions\n title={title}\n description={description}\n descriptionTooltipId={descriptionTooltipId}\n links={links}\n queryResults={timeSeriesDataForExport}\n panelPluginKind={panelPluginKind}\n readHandlers={readHandlers}\n editHandlers={editHandlers}\n extra={extra}\n projectName={projectName}\n // ========== ADDED: Pass panel props for actions ==========\n panelProps={panelProps}\n // ========================================================\n />\n </Stack>\n }\n sx={combineSx(\n (theme) => ({\n containerType: 'inline-size',\n containerName: HEADER_ACTIONS_CONTAINER_NAME,\n padding: theme.spacing(1),\n borderBottom: `solid 1px ${theme.palette.divider}`,\n '.MuiCardHeader-content': {\n overflow: 'hidden',\n },\n }),\n sx\n )}\n {...rest}\n />\n );\n}\n"],"names":["CardHeader","Stack","Typography","combineSx","useReplaceVariablesInString","useMemo","HEADER_ACTIONS_CONTAINER_NAME","PanelActions","PanelHeader","id","title","rawTitle","description","rawDescription","links","queryResults","readHandlers","editHandlers","sx","extra","panelPluginKind","projectName","panelProps","rest","titleElementId","descriptionTooltipId","timeSeriesDataForExport","allSeries","timeRange","undefined","stepMs","metadata","forEach","query","data","timeSeriesData","series","length","push","combinedData","component","aria-labelledby","aria-describedby","disableTypography","direction","variant","lineHeight","minHeight","whiteSpace","overflow","textOverflow","theme","containerType","containerName","padding","spacing","borderBottom","palette","divider"],"mappings":"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"}
|
|
@@ -19,7 +19,7 @@ import { Skeleton } from '@mui/material';
|
|
|
19
19
|
*/ export function PanelPluginLoader(props) {
|
|
20
20
|
const { kind, spec, contentDimensions, definition, queryResults } = props;
|
|
21
21
|
const { data: plugin, isLoading: isPanelLoading } = usePlugin('Panel', kind, {
|
|
22
|
-
|
|
22
|
+
useErrorBoundary: true
|
|
23
23
|
});
|
|
24
24
|
const PanelComponent = plugin?.PanelComponent;
|
|
25
25
|
const supportedQueryTypes = plugin?.supportedQueryTypes || [];
|
|
@@ -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, {
|
|
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 queryResults) {\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={queryResults}\n />\n );\n}\n"],"names":["usePlugin","Skeleton","PanelPluginLoader","props","kind","spec","contentDimensions","definition","queryResults","data","plugin","isLoading","isPanelLoading","useErrorBoundary","PanelComponent","supportedQueryTypes","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;IAE7D,yDAAyD;IACzD,IAAIH,gBAAgB;QAClB,qBACE,KAACX;YACCe,SAAQ;YACRC,OAAOX,mBAAmBW;YAC1BC,QAAQZ,mBAAmBY;YAC3BC,cAAW;;IAGjB;IAEA,IAAIL,mBAAmBM,WAAW;QAChC,MAAM,IAAIC,MAAM,CAAC,mDAAmD,EAAEjB,KAAK,CAAC,CAAC;IAC/E;IAEA,KAAK,MAAMkB,eAAed,aAAc;QACtC,IAAI,CAACO,oBAAoBQ,QAAQ,CAACD,YAAYf,UAAU,CAACH,IAAI,GAAG;YAC9D,MAAM,IAAIiB,MACR,CAAC,6CAA6C,EAAEC,YAAYf,UAAU,CAACH,IAAI,CAAC,0BAA0B,EAAEW,oBAAoBS,IAAI,CAAC,MAAM,CAAC,CAAC;QAE7I;IACF;IAEA,qBACE,KAACV;QACCT,MAAMA;QACNC,mBAAmBA;QACnBC,YAAYA;QACZC,cAAcA;;AAGpB"}
|
|
@@ -24,8 +24,8 @@ export function PanelPreview({ panelDefinition }) {
|
|
|
24
24
|
width = boxRef.current.getBoundingClientRect().width;
|
|
25
25
|
}
|
|
26
26
|
const suggestedStepMs = useSuggestedStepMs(width);
|
|
27
|
-
const { data: plugin,
|
|
28
|
-
if (
|
|
27
|
+
const { data: plugin, isLoading } = usePlugin('Panel', panelDefinition.spec.plugin.kind);
|
|
28
|
+
if (isLoading) {
|
|
29
29
|
return null;
|
|
30
30
|
}
|
|
31
31
|
if (panelDefinition.spec.plugin.kind === '') {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/PanelDrawer/PanelPreview.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, useRef } from 'react';\nimport { Box } from '@mui/material';\nimport { DataQueriesProvider, usePlugin, useSuggestedStepMs } from '@perses-dev/plugin-system';\nimport { PanelEditorValues } from '@perses-dev/core';\nimport { Panel } from '../Panel';\n\nconst PANEL_PREVIEW_HEIGHT = 300;\nconst PANEL_PREVIEW_DEFAULT_WIDTH = 840;\n\nexport function PanelPreview({ panelDefinition }: Pick<PanelEditorValues, 'panelDefinition'>): ReactElement | null {\n const boxRef = useRef<HTMLDivElement>(null);\n let width = PANEL_PREVIEW_DEFAULT_WIDTH;\n if (boxRef.current !== null) {\n width = boxRef.current.getBoundingClientRect().width;\n }\n const suggestedStepMs = useSuggestedStepMs(width);\n\n const { data: plugin,
|
|
1
|
+
{"version":3,"sources":["../../../src/components/PanelDrawer/PanelPreview.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, useRef } from 'react';\nimport { Box } from '@mui/material';\nimport { DataQueriesProvider, usePlugin, useSuggestedStepMs } from '@perses-dev/plugin-system';\nimport { PanelEditorValues } from '@perses-dev/core';\nimport { Panel } from '../Panel';\n\nconst PANEL_PREVIEW_HEIGHT = 300;\nconst PANEL_PREVIEW_DEFAULT_WIDTH = 840;\n\nexport function PanelPreview({ panelDefinition }: Pick<PanelEditorValues, 'panelDefinition'>): ReactElement | null {\n const boxRef = useRef<HTMLDivElement>(null);\n let width = PANEL_PREVIEW_DEFAULT_WIDTH;\n if (boxRef.current !== null) {\n width = boxRef.current.getBoundingClientRect().width;\n }\n const suggestedStepMs = useSuggestedStepMs(width);\n\n const { data: plugin, isLoading } = usePlugin('Panel', panelDefinition.spec.plugin.kind);\n if (isLoading) {\n return null;\n }\n\n if (panelDefinition.spec.plugin.kind === '') {\n return null;\n }\n\n const queries = panelDefinition.spec.queries ?? [];\n\n // map TimeSeriesQueryDefinition to Definition<UnknownSpec>\n const definitions = queries.length\n ? queries.map((query) => {\n return {\n kind: query.spec.plugin.kind,\n spec: query.spec.plugin.spec,\n };\n })\n : [];\n\n return (\n <Box ref={boxRef} height={PANEL_PREVIEW_HEIGHT}>\n <DataQueriesProvider definitions={definitions} options={{ suggestedStepMs, ...plugin?.queryOptions }}>\n <Panel definition={panelDefinition} />\n </DataQueriesProvider>\n </Box>\n );\n}\n"],"names":["useRef","Box","DataQueriesProvider","usePlugin","useSuggestedStepMs","Panel","PANEL_PREVIEW_HEIGHT","PANEL_PREVIEW_DEFAULT_WIDTH","PanelPreview","panelDefinition","boxRef","width","current","getBoundingClientRect","suggestedStepMs","data","plugin","isLoading","spec","kind","queries","definitions","length","map","query","ref","height","options","queryOptions","definition"],"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,MAAM,QAAQ,QAAQ;AAC7C,SAASC,GAAG,QAAQ,gBAAgB;AACpC,SAASC,mBAAmB,EAAEC,SAAS,EAAEC,kBAAkB,QAAQ,4BAA4B;AAE/F,SAASC,KAAK,QAAQ,WAAW;AAEjC,MAAMC,uBAAuB;AAC7B,MAAMC,8BAA8B;AAEpC,OAAO,SAASC,aAAa,EAAEC,eAAe,EAA8C;IAC1F,MAAMC,SAASV,OAAuB;IACtC,IAAIW,QAAQJ;IACZ,IAAIG,OAAOE,OAAO,KAAK,MAAM;QAC3BD,QAAQD,OAAOE,OAAO,CAACC,qBAAqB,GAAGF,KAAK;IACtD;IACA,MAAMG,kBAAkBV,mBAAmBO;IAE3C,MAAM,EAAEI,MAAMC,MAAM,EAAEC,SAAS,EAAE,GAAGd,UAAU,SAASM,gBAAgBS,IAAI,CAACF,MAAM,CAACG,IAAI;IACvF,IAAIF,WAAW;QACb,OAAO;IACT;IAEA,IAAIR,gBAAgBS,IAAI,CAACF,MAAM,CAACG,IAAI,KAAK,IAAI;QAC3C,OAAO;IACT;IAEA,MAAMC,UAAUX,gBAAgBS,IAAI,CAACE,OAAO,IAAI,EAAE;IAElD,2DAA2D;IAC3D,MAAMC,cAAcD,QAAQE,MAAM,GAC9BF,QAAQG,GAAG,CAAC,CAACC;QACX,OAAO;YACLL,MAAMK,MAAMN,IAAI,CAACF,MAAM,CAACG,IAAI;YAC5BD,MAAMM,MAAMN,IAAI,CAACF,MAAM,CAACE,IAAI;QAC9B;IACF,KACA,EAAE;IAEN,qBACE,KAACjB;QAAIwB,KAAKf;QAAQgB,QAAQpB;kBACxB,cAAA,KAACJ;YAAoBmB,aAAaA;YAAaM,SAAS;gBAAEb;gBAAiB,GAAGE,QAAQY,YAAY;YAAC;sBACjG,cAAA,KAACvB;gBAAMwB,YAAYpB;;;;AAI3B"}
|
|
@@ -24,7 +24,7 @@ export function QuerySummaryTable(props) {
|
|
|
24
24
|
// for displaying a summary of recent query results
|
|
25
25
|
const queryClient = useQueryClient();
|
|
26
26
|
const queries = queryClient.getQueryCache().findAll();
|
|
27
|
-
const activeQueries = queries.filter((query)=>query.state.status === '
|
|
27
|
+
const activeQueries = queries.filter((query)=>query.state.status === 'loading');
|
|
28
28
|
const completedQueries = queries.filter((query)=>query.state.status === 'success');
|
|
29
29
|
const querySummary = useActiveTimeSeriesQueries();
|
|
30
30
|
if (datasourceClient.isLoading === true) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/QuerySummaryTable/QuerySummaryTable.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 {\n Box,\n Button,\n Paper,\n Table,\n TableBody,\n TableCell,\n TableContainer,\n TableHead,\n TableRow,\n Typography,\n Stack,\n} from '@mui/material';\nimport { useQueryClient } from '@tanstack/react-query';\nimport { TimeSeriesQueryDefinition, UnknownSpec } from '@perses-dev/core';\nimport { useActiveTimeSeriesQueries, useDatasourceClient, useTimeRange } from '@perses-dev/plugin-system';\nimport { ReactElement } from 'react';\n\nexport interface WarningDisplay {\n query: string;\n summary: string;\n}\n\nconst TABLE_MAX_WIDTH = 1000;\n\ninterface QuerySummaryTableProps {\n showTotalQueries?: boolean;\n}\n\nexport function QuerySummaryTable(props: QuerySummaryTableProps): ReactElement | null {\n const { showTotalQueries = true } = props;\n const datasourceClient = useDatasourceClient({ kind: 'PrometheusDatasource' });\n const { absoluteTimeRange } = useTimeRange();\n\n // for displaying a summary of recent query results\n const queryClient = useQueryClient();\n const queries = queryClient.getQueryCache().findAll();\n const activeQueries = queries.filter((query) => query.state.status === '
|
|
1
|
+
{"version":3,"sources":["../../../src/components/QuerySummaryTable/QuerySummaryTable.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 {\n Box,\n Button,\n Paper,\n Table,\n TableBody,\n TableCell,\n TableContainer,\n TableHead,\n TableRow,\n Typography,\n Stack,\n} from '@mui/material';\nimport { useQueryClient } from '@tanstack/react-query';\nimport { TimeSeriesQueryDefinition, UnknownSpec } from '@perses-dev/core';\nimport { useActiveTimeSeriesQueries, useDatasourceClient, useTimeRange } from '@perses-dev/plugin-system';\nimport { ReactElement } from 'react';\n\nexport interface WarningDisplay {\n query: string;\n summary: string;\n}\n\nconst TABLE_MAX_WIDTH = 1000;\n\ninterface QuerySummaryTableProps {\n showTotalQueries?: boolean;\n}\n\nexport function QuerySummaryTable(props: QuerySummaryTableProps): ReactElement | null {\n const { showTotalQueries = true } = props;\n const datasourceClient = useDatasourceClient({ kind: 'PrometheusDatasource' });\n const { absoluteTimeRange } = useTimeRange();\n\n // for displaying a summary of recent query results\n const queryClient = useQueryClient();\n const queries = queryClient.getQueryCache().findAll();\n const activeQueries = queries.filter((query) => query.state.status === 'loading');\n const completedQueries = queries.filter((query) => query.state.status === 'success');\n const querySummary = useActiveTimeSeriesQueries();\n\n if (datasourceClient.isLoading === true) {\n return null;\n }\n\n const warnings: WarningDisplay[] = [];\n querySummary.forEach((query) => {\n const queryData = query.state.data;\n if (queryData && queryData.metadata?.notices) {\n const queryKey = query.queryKey as [TimeSeriesQueryDefinition<UnknownSpec>];\n const warningMessage = queryData.metadata.notices[0]?.message;\n if (warningMessage) {\n warnings.push({\n query: String(queryKey[0].spec.plugin.spec.query),\n summary: warningMessage,\n });\n }\n }\n });\n\n return (\n <Stack\n spacing={1}\n mb={2}\n sx={{\n maxWidth: TABLE_MAX_WIDTH,\n }}\n >\n <Box sx={{ p: 1 }}>\n <Typography variant=\"h2\" mb={1}>\n Query Summary\n </Typography>\n <TableContainer component={Paper}>\n <Table size=\"small\" aria-label=\"query summary table\">\n <TableHead>\n <TableRow>\n <TableCell>Queries Loading</TableCell>\n <TableCell>Recent Time Series Queries</TableCell>\n {showTotalQueries && <TableCell>Total Queries</TableCell>}\n <TableCell>Start Time</TableCell>\n <TableCell>End Time</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n <TableRow>\n <TableCell>{activeQueries.length}</TableCell>\n <TableCell>{querySummary.length}</TableCell>\n {showTotalQueries && <TableCell>{completedQueries.length}</TableCell>}\n <TableCell>{absoluteTimeRange.start.toString()}</TableCell>\n <TableCell>{absoluteTimeRange.end.toString()}</TableCell>\n </TableRow>\n </TableBody>\n </Table>\n </TableContainer>\n </Box>\n\n {warnings.length > 0 && (\n <Box sx={{ p: 1, m: 0 }}>\n <Typography variant=\"h3\" mb={1}>\n Warnings\n </Typography>\n <TableContainer component={Paper} sx={{ mb: 2 }}>\n <Table size=\"small\" aria-label=\"query warnings table\">\n <TableHead>\n <TableRow>\n <TableCell>Query</TableCell>\n <TableCell>Summary</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {warnings.map((details, idx) => {\n return (\n <TableRow key={idx}>\n <TableCell>{details.query}</TableCell>\n <TableCell>{details.summary}</TableCell>\n </TableRow>\n );\n })}\n </TableBody>\n </Table>\n </TableContainer>\n <Button disabled variant=\"outlined\">\n TODO: Action Button\n </Button>\n </Box>\n )}\n </Stack>\n );\n}\n"],"names":["Box","Button","Paper","Table","TableBody","TableCell","TableContainer","TableHead","TableRow","Typography","Stack","useQueryClient","useActiveTimeSeriesQueries","useDatasourceClient","useTimeRange","TABLE_MAX_WIDTH","QuerySummaryTable","props","showTotalQueries","datasourceClient","kind","absoluteTimeRange","queryClient","queries","getQueryCache","findAll","activeQueries","filter","query","state","status","completedQueries","querySummary","isLoading","warnings","forEach","queryData","data","metadata","notices","queryKey","warningMessage","message","push","String","spec","plugin","summary","spacing","mb","sx","maxWidth","p","variant","component","size","aria-label","length","start","toString","end","m","map","details","idx","disabled"],"mappings":"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"}
|