@perses-dev/dashboards 0.52.0-beta.4 → 0.52.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/GridLayout/GridItemContent.js +137 -17
- package/dist/cjs/components/GridLayout/GridLayout.js +78 -126
- package/dist/cjs/components/GridLayout/Row.js +150 -0
- package/dist/cjs/components/GridLayout/index.js +1 -0
- package/dist/cjs/components/LeaveDialog/LeaveDialog.js +44 -0
- package/dist/cjs/components/LeaveDialog/index.js +30 -0
- package/dist/cjs/components/Panel/Panel.js +7 -2
- package/dist/cjs/components/Panel/PanelActions.js +25 -5
- package/dist/cjs/components/Panel/PanelHeader.js +33 -15
- package/dist/cjs/components/PanelDrawer/PanelDrawer.js +58 -21
- package/dist/cjs/components/PanelGroupDialog/PanelGroupDialog.js +3 -0
- package/dist/cjs/components/PanelGroupDialog/PanelGroupEditorForm.js +35 -15
- package/dist/cjs/components/index.js +1 -0
- package/dist/cjs/constants/user-interface-text.js +4 -2
- package/dist/cjs/context/DashboardProvider/DashboardProvider.js +7 -8
- package/dist/cjs/context/DashboardProvider/DashboardProviderWithQueryParams.js +3 -3
- package/dist/cjs/context/DashboardProvider/panel-editor-slice.js +1 -0
- package/dist/cjs/context/DashboardProvider/panel-group-editor-slice.js +6 -2
- package/dist/cjs/context/DashboardProvider/panel-group-slice.js +1 -0
- package/dist/cjs/context/DashboardProvider/view-panel-slice.js +10 -3
- package/dist/cjs/context/VariableProvider/VariableProvider.js +1 -1
- package/dist/cjs/context/useDashboard.js +5 -4
- package/dist/cjs/views/ViewDashboard/DashboardApp.js +7 -3
- package/dist/cjs/views/ViewDashboard/ViewDashboard.js +9 -8
- package/dist/components/DashboardToolbar/DashboardToolbar.d.ts +2 -2
- package/dist/components/DashboardToolbar/DashboardToolbar.d.ts.map +1 -1
- package/dist/components/DashboardToolbar/DashboardToolbar.js.map +1 -1
- package/dist/components/GridLayout/GridItemContent.d.ts.map +1 -1
- package/dist/components/GridLayout/GridItemContent.js +99 -20
- package/dist/components/GridLayout/GridItemContent.js.map +1 -1
- package/dist/components/GridLayout/GridLayout.d.ts +8 -0
- package/dist/components/GridLayout/GridLayout.d.ts.map +1 -1
- package/dist/components/GridLayout/GridLayout.js +72 -126
- package/dist/components/GridLayout/GridLayout.js.map +1 -1
- package/dist/components/GridLayout/Row.d.ts +17 -0
- package/dist/components/GridLayout/Row.d.ts.map +1 -0
- package/dist/components/GridLayout/Row.js +142 -0
- package/dist/components/GridLayout/Row.js.map +1 -0
- package/dist/components/GridLayout/index.d.ts +1 -0
- package/dist/components/GridLayout/index.d.ts.map +1 -1
- package/dist/components/GridLayout/index.js +1 -0
- package/dist/components/GridLayout/index.js.map +1 -1
- package/dist/components/LeaveDialog/LeaveDialog.d.ts +7 -0
- package/dist/components/LeaveDialog/LeaveDialog.d.ts.map +1 -0
- package/dist/components/LeaveDialog/LeaveDialog.js +36 -0
- package/dist/components/LeaveDialog/LeaveDialog.js.map +1 -0
- package/dist/components/LeaveDialog/index.d.ts +2 -0
- package/dist/components/LeaveDialog/index.d.ts.map +1 -0
- package/dist/components/LeaveDialog/index.js +15 -0
- package/dist/components/LeaveDialog/index.js.map +1 -0
- package/dist/components/Panel/Panel.d.ts +6 -0
- package/dist/components/Panel/Panel.d.ts.map +1 -1
- package/dist/components/Panel/Panel.js +7 -2
- package/dist/components/Panel/Panel.js.map +1 -1
- package/dist/components/Panel/PanelActions.d.ts +5 -0
- package/dist/components/Panel/PanelActions.d.ts.map +1 -1
- package/dist/components/Panel/PanelActions.js +25 -5
- package/dist/components/Panel/PanelActions.js.map +1 -1
- package/dist/components/Panel/PanelHeader.d.ts +7 -1
- package/dist/components/Panel/PanelHeader.d.ts.map +1 -1
- package/dist/components/Panel/PanelHeader.js +34 -16
- package/dist/components/Panel/PanelHeader.js.map +1 -1
- package/dist/components/PanelDrawer/PanelDrawer.d.ts.map +1 -1
- package/dist/components/PanelDrawer/PanelDrawer.js +59 -22
- package/dist/components/PanelDrawer/PanelDrawer.js.map +1 -1
- package/dist/components/PanelGroupDialog/PanelGroupDialog.d.ts.map +1 -1
- package/dist/components/PanelGroupDialog/PanelGroupDialog.js +3 -0
- package/dist/components/PanelGroupDialog/PanelGroupDialog.js.map +1 -1
- package/dist/components/PanelGroupDialog/PanelGroupEditorForm.d.ts +1 -0
- package/dist/components/PanelGroupDialog/PanelGroupEditorForm.d.ts.map +1 -1
- package/dist/components/PanelGroupDialog/PanelGroupEditorForm.js +36 -16
- package/dist/components/PanelGroupDialog/PanelGroupEditorForm.js.map +1 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +1 -0
- package/dist/components/index.js.map +1 -1
- package/dist/constants/user-interface-text.d.ts +2 -0
- package/dist/constants/user-interface-text.d.ts.map +1 -1
- package/dist/constants/user-interface-text.js +4 -2
- package/dist/constants/user-interface-text.js.map +1 -1
- package/dist/context/DashboardProvider/DashboardProvider.d.ts +5 -5
- package/dist/context/DashboardProvider/DashboardProvider.d.ts.map +1 -1
- package/dist/context/DashboardProvider/DashboardProvider.js +7 -8
- package/dist/context/DashboardProvider/DashboardProvider.js.map +1 -1
- package/dist/context/DashboardProvider/DashboardProviderWithQueryParams.js +4 -4
- package/dist/context/DashboardProvider/DashboardProviderWithQueryParams.js.map +1 -1
- package/dist/context/DashboardProvider/common.d.ts +1 -1
- package/dist/context/DashboardProvider/common.d.ts.map +1 -1
- package/dist/context/DashboardProvider/common.js.map +1 -1
- package/dist/context/DashboardProvider/panel-editor-slice.d.ts +1 -0
- package/dist/context/DashboardProvider/panel-editor-slice.d.ts.map +1 -1
- package/dist/context/DashboardProvider/panel-editor-slice.js +1 -0
- package/dist/context/DashboardProvider/panel-editor-slice.js.map +1 -1
- package/dist/context/DashboardProvider/panel-group-editor-slice.d.ts +1 -0
- package/dist/context/DashboardProvider/panel-group-editor-slice.d.ts.map +1 -1
- package/dist/context/DashboardProvider/panel-group-editor-slice.js +6 -2
- package/dist/context/DashboardProvider/panel-group-editor-slice.js.map +1 -1
- package/dist/context/DashboardProvider/panel-group-slice.d.ts +3 -0
- package/dist/context/DashboardProvider/panel-group-slice.d.ts.map +1 -1
- package/dist/context/DashboardProvider/panel-group-slice.js +1 -0
- package/dist/context/DashboardProvider/panel-group-slice.js.map +1 -1
- package/dist/context/DashboardProvider/view-panel-slice.d.ts +6 -2
- package/dist/context/DashboardProvider/view-panel-slice.d.ts.map +1 -1
- package/dist/context/DashboardProvider/view-panel-slice.js +10 -3
- package/dist/context/DashboardProvider/view-panel-slice.js.map +1 -1
- package/dist/context/VariableProvider/VariableProvider.js +1 -1
- package/dist/context/VariableProvider/VariableProvider.js.map +1 -1
- package/dist/context/useDashboard.js +5 -4
- package/dist/context/useDashboard.js.map +1 -1
- package/dist/views/ViewDashboard/DashboardApp.d.ts +7 -6
- package/dist/views/ViewDashboard/DashboardApp.d.ts.map +1 -1
- package/dist/views/ViewDashboard/DashboardApp.js +8 -4
- package/dist/views/ViewDashboard/DashboardApp.js.map +1 -1
- package/dist/views/ViewDashboard/ViewDashboard.d.ts.map +1 -1
- package/dist/views/ViewDashboard/ViewDashboard.js +9 -8
- package/dist/views/ViewDashboard/ViewDashboard.js.map +1 -1
- package/package.json +5 -5
|
@@ -14,6 +14,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
14
14
|
import { Stack, Box, Popover, CircularProgress, styled } from '@mui/material';
|
|
15
15
|
import { isValidElement, useMemo, useState } from 'react';
|
|
16
16
|
import { InfoTooltip } from '@perses-dev/components';
|
|
17
|
+
import DatabaseSearch from 'mdi-material-ui/DatabaseSearch';
|
|
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,7 @@ 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, pluginActions = [] })=>{
|
|
36
|
+
export const PanelActions = ({ editHandlers, readHandlers, viewQueriesHandler, extra, title, description, descriptionTooltipId, links, queryResults, pluginActions = [], showIcons })=>{
|
|
36
37
|
const descriptionAction = useMemo(()=>{
|
|
37
38
|
if (description && description.trim().length > 0) {
|
|
38
39
|
return /*#__PURE__*/ _jsx(InfoTooltip, {
|
|
@@ -109,6 +110,23 @@ export const PanelActions = ({ editHandlers, readHandlers, extra, title, descrip
|
|
|
109
110
|
readHandlers,
|
|
110
111
|
title
|
|
111
112
|
]);
|
|
113
|
+
const viewQueryAction = useMemo(()=>{
|
|
114
|
+
if (!viewQueriesHandler?.onClick) return null;
|
|
115
|
+
return /*#__PURE__*/ _jsx(InfoTooltip, {
|
|
116
|
+
description: TOOLTIP_TEXT.queryView,
|
|
117
|
+
children: /*#__PURE__*/ _jsx(HeaderIconButton, {
|
|
118
|
+
"aria-label": ARIA_LABEL_TEXT.openQueryView(title),
|
|
119
|
+
size: "small",
|
|
120
|
+
onClick: viewQueriesHandler.onClick,
|
|
121
|
+
children: /*#__PURE__*/ _jsx(DatabaseSearch, {
|
|
122
|
+
fontSize: "inherit"
|
|
123
|
+
})
|
|
124
|
+
})
|
|
125
|
+
});
|
|
126
|
+
}, [
|
|
127
|
+
viewQueriesHandler,
|
|
128
|
+
title
|
|
129
|
+
]);
|
|
112
130
|
const editActions = useMemo(()=>{
|
|
113
131
|
if (editHandlers !== undefined) {
|
|
114
132
|
// If there are edit handlers, always just show the edit buttons
|
|
@@ -188,8 +206,8 @@ export const PanelActions = ({ editHandlers, readHandlers, extra, title, descrip
|
|
|
188
206
|
flexGrow: 1
|
|
189
207
|
}
|
|
190
208
|
});
|
|
191
|
-
// if the panel is in non-editing, non-fullscreen mode
|
|
192
|
-
const OnHover = ({ children })=>
|
|
209
|
+
// By default, the panel header shows certain icons only on hover if the panel is in non-editing, non-fullscreen mode
|
|
210
|
+
const OnHover = ({ children })=>showIcons === 'hover' ? /*#__PURE__*/ _jsx(Box, {
|
|
193
211
|
sx: {
|
|
194
212
|
display: 'var(--panel-hover, none)'
|
|
195
213
|
},
|
|
@@ -220,6 +238,7 @@ export const PanelActions = ({ editHandlers, readHandlers, extra, title, descrip
|
|
|
220
238
|
" ",
|
|
221
239
|
extraActions,
|
|
222
240
|
" ",
|
|
241
|
+
viewQueryAction,
|
|
223
242
|
readActions,
|
|
224
243
|
" ",
|
|
225
244
|
pluginActions,
|
|
@@ -251,13 +270,14 @@ export const PanelActions = ({ editHandlers, readHandlers, extra, title, descrip
|
|
|
251
270
|
/*#__PURE__*/ _jsxs(OnHover, {
|
|
252
271
|
children: [
|
|
253
272
|
extraActions,
|
|
254
|
-
" ",
|
|
255
273
|
readActions,
|
|
256
274
|
/*#__PURE__*/ _jsxs(OverflowMenu, {
|
|
257
275
|
title: title,
|
|
258
276
|
children: [
|
|
259
277
|
editActions,
|
|
260
278
|
" ",
|
|
279
|
+
viewQueryAction,
|
|
280
|
+
" ",
|
|
261
281
|
pluginActions
|
|
262
282
|
]
|
|
263
283
|
}),
|
|
@@ -288,7 +308,7 @@ export const PanelActions = ({ editHandlers, readHandlers, extra, title, descrip
|
|
|
288
308
|
/*#__PURE__*/ _jsxs(OnHover, {
|
|
289
309
|
children: [
|
|
290
310
|
extraActions,
|
|
291
|
-
|
|
311
|
+
viewQueryAction,
|
|
292
312
|
readActions,
|
|
293
313
|
" ",
|
|
294
314
|
editActions,
|
|
@@ -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 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';\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 pluginActions?: ReactNode[];\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 pluginActions = [],\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: 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((): 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 // 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 // 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} {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} {readActions}\n <OverflowMenu title={title}>\n {editActions} {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} {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 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","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","pluginActions","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 } 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: 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((): 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 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","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","toString","join","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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"}
|
|
@@ -3,6 +3,7 @@ import { Link } from '@perses-dev/core';
|
|
|
3
3
|
import { QueryData } from '@perses-dev/plugin-system';
|
|
4
4
|
import { ReactElement, ReactNode } from 'react';
|
|
5
5
|
import { PanelActionsProps } from './PanelActions';
|
|
6
|
+
import { PanelOptions } from './Panel';
|
|
6
7
|
type OmittedProps = 'children' | 'action' | 'title' | 'disableTypography';
|
|
7
8
|
export interface PanelHeaderProps extends Omit<CardHeaderProps, OmittedProps> {
|
|
8
9
|
id: string;
|
|
@@ -11,10 +12,15 @@ export interface PanelHeaderProps extends Omit<CardHeaderProps, OmittedProps> {
|
|
|
11
12
|
links?: Link[];
|
|
12
13
|
extra?: ReactNode;
|
|
13
14
|
queryResults: QueryData[];
|
|
15
|
+
viewQueriesHandler?: PanelActionsProps['viewQueriesHandler'];
|
|
14
16
|
readHandlers?: PanelActionsProps['readHandlers'];
|
|
15
17
|
editHandlers?: PanelActionsProps['editHandlers'];
|
|
16
18
|
pluginActions?: ReactNode[];
|
|
19
|
+
showIcons: PanelOptions['showIcons'];
|
|
20
|
+
dimension?: {
|
|
21
|
+
width: number;
|
|
22
|
+
};
|
|
17
23
|
}
|
|
18
|
-
export declare function PanelHeader({ id, title: rawTitle, description: rawDescription, links, queryResults, readHandlers, editHandlers, sx, extra, pluginActions, ...rest }: PanelHeaderProps): ReactElement;
|
|
24
|
+
export declare function PanelHeader({ id, title: rawTitle, description: rawDescription, links, queryResults, readHandlers, editHandlers, sx, extra, pluginActions, showIcons, viewQueriesHandler, dimension, ...rest }: PanelHeaderProps): ReactElement;
|
|
19
25
|
export {};
|
|
20
26
|
//# 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,
|
|
1
|
+
{"version":3,"file":"PanelHeader.d.ts","sourceRoot":"","sources":["../../../src/components/Panel/PanelHeader.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAc,eAAe,EAA8B,MAAM,eAAe,CAAC;AAExF,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,SAAS,EAA+B,MAAM,2BAA2B,CAAC;AACnF,OAAO,EAAE,YAAY,EAAE,SAAS,EAA+B,MAAM,OAAO,CAAC;AAE7E,OAAO,EAAgB,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,KAAK,YAAY,GAAG,UAAU,GAAG,QAAQ,GAAG,OAAO,GAAG,mBAAmB,CAAC;AAE1E,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,kBAAkB,CAAC,EAAE,iBAAiB,CAAC,oBAAoB,CAAC,CAAC;IAC7D,YAAY,CAAC,EAAE,iBAAiB,CAAC,cAAc,CAAC,CAAC;IACjD,YAAY,CAAC,EAAE,iBAAiB,CAAC,cAAc,CAAC,CAAC;IACjD,aAAa,CAAC,EAAE,SAAS,EAAE,CAAC;IAC5B,SAAS,EAAE,YAAY,CAAC,WAAW,CAAC,CAAC;IACrC,SAAS,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/B;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,aAAa,EACb,SAAS,EACT,kBAAkB,EAClB,SAAS,EACT,GAAG,IAAI,EACR,EAAE,gBAAgB,GAAG,YAAY,CAyEjC"}
|
|
@@ -11,16 +11,27 @@
|
|
|
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 { CardHeader, Stack, Typography } from '@mui/material';
|
|
14
|
+
import { CardHeader, Stack, Typography, Tooltip } from '@mui/material';
|
|
15
15
|
import { combineSx } from '@perses-dev/components';
|
|
16
16
|
import { useReplaceVariablesInString } from '@perses-dev/plugin-system';
|
|
17
|
+
import { useEffect, useRef, useState } 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, pluginActions, ...rest }) {
|
|
20
|
+
export function PanelHeader({ id, title: rawTitle, description: rawDescription, links, queryResults, readHandlers, editHandlers, sx, extra, pluginActions, showIcons, viewQueriesHandler, dimension, ...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 textRef = useRef(null);
|
|
26
|
+
const [isEllipsisActive, setIsEllipsisActive] = useState(false);
|
|
27
|
+
useEffect(()=>{
|
|
28
|
+
if (textRef.current && dimension?.width) {
|
|
29
|
+
setIsEllipsisActive(textRef.current.scrollWidth > textRef.current.clientWidth);
|
|
30
|
+
}
|
|
31
|
+
}, [
|
|
32
|
+
title,
|
|
33
|
+
dimension?.width
|
|
34
|
+
]);
|
|
24
35
|
return /*#__PURE__*/ _jsx(CardHeader, {
|
|
25
36
|
id: id,
|
|
26
37
|
component: "header",
|
|
@@ -32,19 +43,24 @@ export function PanelHeader({ id, title: rawTitle, description: rawDescription,
|
|
|
32
43
|
alignItems: "center",
|
|
33
44
|
height: "var(--panel-header-height, 30px)",
|
|
34
45
|
children: [
|
|
35
|
-
/*#__PURE__*/ _jsx(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
/*#__PURE__*/ _jsx(Tooltip, {
|
|
47
|
+
title: title,
|
|
48
|
+
disableHoverListener: !isEllipsisActive,
|
|
49
|
+
children: /*#__PURE__*/ _jsx(Typography, {
|
|
50
|
+
id: titleElementId,
|
|
51
|
+
variant: "subtitle1",
|
|
52
|
+
ref: textRef,
|
|
53
|
+
sx: {
|
|
54
|
+
// `minHeight` guarantees that the header has the correct height
|
|
55
|
+
// when there is no title (i.e. in the preview)
|
|
56
|
+
lineHeight: '24px',
|
|
57
|
+
minHeight: '26px',
|
|
58
|
+
whiteSpace: 'nowrap',
|
|
59
|
+
overflow: 'hidden',
|
|
60
|
+
textOverflow: 'ellipsis'
|
|
61
|
+
},
|
|
62
|
+
children: title
|
|
63
|
+
})
|
|
48
64
|
}),
|
|
49
65
|
/*#__PURE__*/ _jsx(PanelActions, {
|
|
50
66
|
title: title,
|
|
@@ -53,9 +69,11 @@ export function PanelHeader({ id, title: rawTitle, description: rawDescription,
|
|
|
53
69
|
links: links,
|
|
54
70
|
readHandlers: readHandlers,
|
|
55
71
|
editHandlers: editHandlers,
|
|
72
|
+
viewQueriesHandler: viewQueriesHandler,
|
|
56
73
|
extra: extra,
|
|
57
74
|
queryResults: queryResults,
|
|
58
|
-
pluginActions: pluginActions
|
|
75
|
+
pluginActions: pluginActions,
|
|
76
|
+
showIcons: showIcons
|
|
59
77
|
})
|
|
60
78
|
]
|
|
61
79
|
}),
|
|
@@ -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 pluginActions?: ReactNode[]; // Add pluginActions prop\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 pluginActions,\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\" alignItems=\"center\" height=\"var(--panel-header-height, 30px)\">\n <Typography\n
|
|
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, Tooltip } 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, useEffect, useRef, useState } from 'react';\nimport { HEADER_ACTIONS_CONTAINER_NAME } from '../../constants';\nimport { PanelActions, PanelActionsProps } from './PanelActions';\nimport { PanelOptions } from './Panel';\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 viewQueriesHandler?: PanelActionsProps['viewQueriesHandler'];\n readHandlers?: PanelActionsProps['readHandlers'];\n editHandlers?: PanelActionsProps['editHandlers'];\n pluginActions?: ReactNode[]; // Add pluginActions prop\n showIcons: PanelOptions['showIcons'];\n dimension?: { width: number };\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 pluginActions,\n showIcons,\n viewQueriesHandler,\n dimension,\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 textRef = useRef<HTMLDivElement>(null);\n const [isEllipsisActive, setIsEllipsisActive] = useState(false);\n\n useEffect(() => {\n if (textRef.current && dimension?.width) {\n setIsEllipsisActive(textRef.current.scrollWidth > textRef.current.clientWidth);\n }\n }, [title, dimension?.width]);\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\" alignItems=\"center\" height=\"var(--panel-header-height, 30px)\">\n <Tooltip title={title} disableHoverListener={!isEllipsisActive}>\n <Typography\n id={titleElementId}\n variant=\"subtitle1\"\n ref={textRef}\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 </Tooltip>\n <PanelActions\n title={title}\n description={description}\n descriptionTooltipId={descriptionTooltipId}\n links={links}\n readHandlers={readHandlers}\n editHandlers={editHandlers}\n viewQueriesHandler={viewQueriesHandler}\n extra={extra}\n queryResults={queryResults}\n pluginActions={pluginActions}\n showIcons={showIcons}\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","Tooltip","combineSx","useReplaceVariablesInString","useEffect","useRef","useState","HEADER_ACTIONS_CONTAINER_NAME","PanelActions","PanelHeader","id","title","rawTitle","description","rawDescription","links","queryResults","readHandlers","editHandlers","sx","extra","pluginActions","showIcons","viewQueriesHandler","dimension","rest","titleElementId","descriptionTooltipId","textRef","isEllipsisActive","setIsEllipsisActive","current","width","scrollWidth","clientWidth","component","aria-labelledby","aria-describedby","disableTypography","direction","alignItems","height","disableHoverListener","variant","ref","lineHeight","minHeight","whiteSpace","overflow","textOverflow","theme","containerType","containerName","padding","spacing","borderBottom","palette","divider"],"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,UAAU,EAAmBC,KAAK,EAAEC,UAAU,EAAEC,OAAO,QAAQ,gBAAgB;AACxF,SAASC,SAAS,QAAQ,yBAAyB;AAEnD,SAAoBC,2BAA2B,QAAQ,4BAA4B;AACnF,SAAkCC,SAAS,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,QAAQ;AAC7E,SAASC,6BAA6B,QAAQ,kBAAkB;AAChE,SAASC,YAAY,QAA2B,iBAAiB;AAoBjE,OAAO,SAASC,YAAY,EAC1BC,EAAE,EACFC,OAAOC,QAAQ,EACfC,aAAaC,cAAc,EAC3BC,KAAK,EACLC,YAAY,EACZC,YAAY,EACZC,YAAY,EACZC,EAAE,EACFC,KAAK,EACLC,aAAa,EACbC,SAAS,EACTC,kBAAkB,EAClBC,SAAS,EACT,GAAGC,MACc;IACjB,MAAMC,iBAAiB,GAAGhB,GAAG,MAAM,CAAC;IACpC,MAAMiB,uBAAuB,GAAGjB,GAAG,YAAY,CAAC;IAEhD,MAAMC,QAAQR,4BAA4BS;IAC1C,MAAMC,cAAcV,4BAA4BW;IAEhD,MAAMc,UAAUvB,OAAuB;IACvC,MAAM,CAACwB,kBAAkBC,oBAAoB,GAAGxB,SAAS;IAEzDF,UAAU;QACR,IAAIwB,QAAQG,OAAO,IAAIP,WAAWQ,OAAO;YACvCF,oBAAoBF,QAAQG,OAAO,CAACE,WAAW,GAAGL,QAAQG,OAAO,CAACG,WAAW;QAC/E;IACF,GAAG;QAACvB;QAAOa,WAAWQ;KAAM;IAE5B,qBACE,KAAClC;QACCY,IAAIA;QACJyB,WAAU;QACVC,mBAAiBV;QACjBW,oBAAkBV;QAClBW,iBAAiB;QACjB3B,qBACE,MAACZ;YAAMwC,WAAU;YAAMC,YAAW;YAASC,QAAO;;8BAChD,KAACxC;oBAAQU,OAAOA;oBAAO+B,sBAAsB,CAACb;8BAC5C,cAAA,KAAC7B;wBACCU,IAAIgB;wBACJiB,SAAQ;wBACRC,KAAKhB;wBACLT,IAAI;4BACF,gEAAgE;4BAChE,+CAA+C;4BAC/C0B,YAAY;4BACZC,WAAW;4BACXC,YAAY;4BACZC,UAAU;4BACVC,cAAc;wBAChB;kCAECtC;;;8BAGL,KAACH;oBACCG,OAAOA;oBACPE,aAAaA;oBACbc,sBAAsBA;oBACtBZ,OAAOA;oBACPE,cAAcA;oBACdC,cAAcA;oBACdK,oBAAoBA;oBACpBH,OAAOA;oBACPJ,cAAcA;oBACdK,eAAeA;oBACfC,WAAWA;;;;QAIjBH,IAAIjB,UACF,CAACgD,QAAW,CAAA;gBACVC,eAAe;gBACfC,eAAe7C;gBACf8C,SAASH,MAAMI,OAAO,CAAC;gBACvBC,cAAc,CAAC,UAAU,EAAEL,MAAMM,OAAO,CAACC,OAAO,EAAE;gBAClD,0BAA0B;oBACxBT,UAAU;gBACZ;YACF,CAAA,GACA7B;QAED,GAAGM,IAAI;;AAGd"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PanelDrawer.d.ts","sourceRoot":"","sources":["../../../src/components/PanelDrawer/PanelDrawer.tsx"],"names":[],"mappings":"AAcA,OAAO,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"PanelDrawer.d.ts","sourceRoot":"","sources":["../../../src/components/PanelDrawer/PanelDrawer.tsx"],"names":[],"mappings":"AAcA,OAAO,EAAE,YAAY,EAA6C,MAAM,OAAO,CAAC;AAOhF;;GAEG;AACH,eAAO,MAAM,WAAW,QAAO,YAsE9B,CAAC"}
|
|
@@ -11,8 +11,9 @@
|
|
|
11
11
|
// See the License for the specific language governing permissions and
|
|
12
12
|
// limitations under the License.
|
|
13
13
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
14
|
-
import { useState } from 'react';
|
|
14
|
+
import { useState, useMemo, useCallback } from 'react';
|
|
15
15
|
import { Drawer, ErrorAlert, ErrorBoundary } from '@perses-dev/components';
|
|
16
|
+
import { useVariableValues, VariableContext } from '@perses-dev/plugin-system';
|
|
16
17
|
import { usePanelEditor } from '../../context';
|
|
17
18
|
import { PanelEditorForm } from './PanelEditorForm';
|
|
18
19
|
/**
|
|
@@ -22,44 +23,80 @@ import { PanelEditorForm } from './PanelEditorForm';
|
|
|
22
23
|
// When the user clicks close, start closing but don't call the store yet to keep values stable during animtation
|
|
23
24
|
const [isClosing, setIsClosing] = useState(false);
|
|
24
25
|
// Drawer is open if we have a model and we're not transitioning out
|
|
25
|
-
const isOpen = panelEditor !== undefined && isClosing
|
|
26
|
-
|
|
26
|
+
const isOpen = panelEditor !== undefined && !isClosing;
|
|
27
|
+
const handleSave = useCallback((values)=>{
|
|
27
28
|
// This shouldn't happen since we don't render the submit button until we have a model, but check to make TS happy
|
|
28
29
|
if (panelEditor === undefined || values === undefined) {
|
|
29
30
|
throw new Error('Cannot apply changes');
|
|
30
31
|
}
|
|
31
32
|
panelEditor.applyChanges(values);
|
|
32
33
|
setIsClosing(true);
|
|
33
|
-
}
|
|
34
|
+
}, [
|
|
35
|
+
panelEditor
|
|
36
|
+
]);
|
|
34
37
|
const handleClose = ()=>{
|
|
35
38
|
setIsClosing(true);
|
|
36
39
|
};
|
|
37
40
|
// Don't call closeDrawer on the store until the Drawer has completely transitioned out and reset close state
|
|
38
|
-
const handleExited = ()=>{
|
|
41
|
+
const handleExited = useCallback(()=>{
|
|
39
42
|
panelEditor?.close();
|
|
40
43
|
setIsClosing(false);
|
|
41
|
-
}
|
|
44
|
+
}, [
|
|
45
|
+
panelEditor
|
|
46
|
+
]);
|
|
42
47
|
// Disables closing on click out. This is a quick-win solution to avoid losing draft changes.
|
|
43
48
|
// -> TODO find a way to enable closing by clicking-out in edit view, with a discard confirmation modal popping up
|
|
44
49
|
const handleClickOut = ()=>{
|
|
45
50
|
/* do nothing */ };
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
51
|
+
const drawer = useMemo(()=>{
|
|
52
|
+
return /*#__PURE__*/ _jsx(Drawer, {
|
|
53
|
+
isOpen: isOpen,
|
|
54
|
+
onClose: handleClickOut,
|
|
55
|
+
SlideProps: {
|
|
56
|
+
onExited: handleExited
|
|
57
|
+
},
|
|
58
|
+
"data-testid": "panel-editor",
|
|
59
|
+
children: panelEditor && /*#__PURE__*/ _jsx(ErrorBoundary, {
|
|
60
|
+
FallbackComponent: ErrorAlert,
|
|
61
|
+
children: /*#__PURE__*/ _jsx(PanelEditorForm, {
|
|
62
|
+
initialAction: panelEditor.mode,
|
|
63
|
+
initialValues: panelEditor.initialValues,
|
|
64
|
+
onSave: handleSave,
|
|
65
|
+
onClose: handleClose
|
|
66
|
+
})
|
|
60
67
|
})
|
|
61
|
-
})
|
|
62
|
-
}
|
|
68
|
+
});
|
|
69
|
+
}, [
|
|
70
|
+
handleExited,
|
|
71
|
+
handleSave,
|
|
72
|
+
isOpen,
|
|
73
|
+
panelEditor
|
|
74
|
+
]);
|
|
75
|
+
// If the panel editor is using a repeat variable, we need to wrap the drawer in a VariableContext.Provider
|
|
76
|
+
if (panelEditor?.panelGroupItemId?.repeatVariable) {
|
|
77
|
+
return /*#__PURE__*/ _jsx(RepeatVariableWrapper, {
|
|
78
|
+
repeatVariable: panelEditor.panelGroupItemId.repeatVariable,
|
|
79
|
+
children: drawer
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
return drawer;
|
|
63
83
|
};
|
|
84
|
+
// Wraps the drawer in a VariableContext.Provider to provide the repeat variable value
|
|
85
|
+
// This is necessary for previewing panels that use repeat variables and query editor
|
|
86
|
+
function RepeatVariableWrapper({ repeatVariable, children }) {
|
|
87
|
+
const variables = useVariableValues();
|
|
88
|
+
return /*#__PURE__*/ _jsx(VariableContext.Provider, {
|
|
89
|
+
value: {
|
|
90
|
+
state: {
|
|
91
|
+
...variables,
|
|
92
|
+
[repeatVariable[0]]: {
|
|
93
|
+
value: repeatVariable[1],
|
|
94
|
+
loading: false
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
children: children
|
|
99
|
+
});
|
|
100
|
+
}
|
|
64
101
|
|
|
65
102
|
//# sourceMappingURL=PanelDrawer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/PanelDrawer/PanelDrawer.tsx"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-empty-function */\n// 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, useState } from 'react';\nimport { Drawer, ErrorAlert, ErrorBoundary } from '@perses-dev/components';\nimport { PanelEditorValues } from '@perses-dev/core';\nimport { usePanelEditor } from '../../context';\nimport { PanelEditorForm } from './PanelEditorForm';\n\n/**\n * The Add/Edit panel drawer for editing a panel's options.\n */\nexport const PanelDrawer = (): ReactElement => {\n const panelEditor = usePanelEditor();\n\n // When the user clicks close, start closing but don't call the store yet to keep values stable during animtation\n const [isClosing, setIsClosing] = useState(false);\n\n // Drawer is open if we have a model and we're not transitioning out\n const isOpen = panelEditor !== undefined && isClosing
|
|
1
|
+
{"version":3,"sources":["../../../src/components/PanelDrawer/PanelDrawer.tsx"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-empty-function */\n// 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, useState, useMemo, ReactNode, useCallback } from 'react';\nimport { Drawer, ErrorAlert, ErrorBoundary } from '@perses-dev/components';\nimport { PanelEditorValues } from '@perses-dev/core';\nimport { useVariableValues, VariableContext } from '@perses-dev/plugin-system';\nimport { usePanelEditor } from '../../context';\nimport { PanelEditorForm } from './PanelEditorForm';\n\n/**\n * The Add/Edit panel drawer for editing a panel's options.\n */\nexport const PanelDrawer = (): ReactElement => {\n const panelEditor = usePanelEditor();\n\n // When the user clicks close, start closing but don't call the store yet to keep values stable during animtation\n const [isClosing, setIsClosing] = useState(false);\n\n // Drawer is open if we have a model and we're not transitioning out\n const isOpen = panelEditor !== undefined && !isClosing;\n\n const handleSave = useCallback(\n (values: PanelEditorValues) => {\n // This shouldn't happen since we don't render the submit button until we have a model, but check to make TS happy\n if (panelEditor === undefined || values === undefined) {\n throw new Error('Cannot apply changes');\n }\n panelEditor.applyChanges(values);\n setIsClosing(true);\n },\n [panelEditor]\n );\n\n const handleClose = (): void => {\n setIsClosing(true);\n };\n\n // Don't call closeDrawer on the store until the Drawer has completely transitioned out and reset close state\n const handleExited = useCallback(() => {\n panelEditor?.close();\n setIsClosing(false);\n }, [panelEditor]);\n\n // Disables closing on click out. This is a quick-win solution to avoid losing draft changes.\n // -> TODO find a way to enable closing by clicking-out in edit view, with a discard confirmation modal popping up\n const handleClickOut = (): void => {\n /* do nothing */\n };\n\n const drawer = useMemo(() => {\n return (\n <Drawer\n isOpen={isOpen}\n onClose={handleClickOut}\n SlideProps={{ onExited: handleExited }}\n data-testid=\"panel-editor\"\n >\n {/* When the drawer is opened, we should have panel editor state (this also ensures the form state gets reset between opens) */}\n {panelEditor && (\n <ErrorBoundary FallbackComponent={ErrorAlert}>\n <PanelEditorForm\n initialAction={panelEditor.mode}\n initialValues={panelEditor.initialValues}\n onSave={handleSave}\n onClose={handleClose}\n />\n </ErrorBoundary>\n )}\n </Drawer>\n );\n }, [handleExited, handleSave, isOpen, panelEditor]);\n\n // If the panel editor is using a repeat variable, we need to wrap the drawer in a VariableContext.Provider\n if (panelEditor?.panelGroupItemId?.repeatVariable) {\n return (\n <RepeatVariableWrapper repeatVariable={panelEditor.panelGroupItemId.repeatVariable}>\n {drawer}\n </RepeatVariableWrapper>\n );\n }\n\n return drawer;\n};\n\n// Wraps the drawer in a VariableContext.Provider to provide the repeat variable value\n// This is necessary for previewing panels that use repeat variables and query editor\nfunction RepeatVariableWrapper({\n repeatVariable,\n children,\n}: {\n repeatVariable: [string, string];\n children: ReactNode;\n}): ReactElement {\n const variables = useVariableValues();\n\n return (\n <VariableContext.Provider\n value={{ state: { ...variables, [repeatVariable[0]]: { value: repeatVariable[1], loading: false } } }}\n >\n {children}\n </VariableContext.Provider>\n );\n}\n"],"names":["useState","useMemo","useCallback","Drawer","ErrorAlert","ErrorBoundary","useVariableValues","VariableContext","usePanelEditor","PanelEditorForm","PanelDrawer","panelEditor","isClosing","setIsClosing","isOpen","undefined","handleSave","values","Error","applyChanges","handleClose","handleExited","close","handleClickOut","drawer","onClose","SlideProps","onExited","data-testid","FallbackComponent","initialAction","mode","initialValues","onSave","panelGroupItemId","repeatVariable","RepeatVariableWrapper","children","variables","Provider","value","state","loading"],"mappings":"AAAA,uDAAuD,GACvD,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,QAAQ,EAAEC,OAAO,EAAaC,WAAW,QAAQ,QAAQ;AAChF,SAASC,MAAM,EAAEC,UAAU,EAAEC,aAAa,QAAQ,yBAAyB;AAE3E,SAASC,iBAAiB,EAAEC,eAAe,QAAQ,4BAA4B;AAC/E,SAASC,cAAc,QAAQ,gBAAgB;AAC/C,SAASC,eAAe,QAAQ,oBAAoB;AAEpD;;CAEC,GACD,OAAO,MAAMC,cAAc;IACzB,MAAMC,cAAcH;IAEpB,iHAAiH;IACjH,MAAM,CAACI,WAAWC,aAAa,GAAGb,SAAS;IAE3C,oEAAoE;IACpE,MAAMc,SAASH,gBAAgBI,aAAa,CAACH;IAE7C,MAAMI,aAAad,YACjB,CAACe;QACC,kHAAkH;QAClH,IAAIN,gBAAgBI,aAAaE,WAAWF,WAAW;YACrD,MAAM,IAAIG,MAAM;QAClB;QACAP,YAAYQ,YAAY,CAACF;QACzBJ,aAAa;IACf,GACA;QAACF;KAAY;IAGf,MAAMS,cAAc;QAClBP,aAAa;IACf;IAEA,6GAA6G;IAC7G,MAAMQ,eAAenB,YAAY;QAC/BS,aAAaW;QACbT,aAAa;IACf,GAAG;QAACF;KAAY;IAEhB,6FAA6F;IAC7F,kHAAkH;IAClH,MAAMY,iBAAiB;IACrB,cAAc,GAChB;IAEA,MAAMC,SAASvB,QAAQ;QACrB,qBACE,KAACE;YACCW,QAAQA;YACRW,SAASF;YACTG,YAAY;gBAAEC,UAAUN;YAAa;YACrCO,eAAY;sBAGXjB,6BACC,KAACN;gBAAcwB,mBAAmBzB;0BAChC,cAAA,KAACK;oBACCqB,eAAenB,YAAYoB,IAAI;oBAC/BC,eAAerB,YAAYqB,aAAa;oBACxCC,QAAQjB;oBACRS,SAASL;;;;IAMrB,GAAG;QAACC;QAAcL;QAAYF;QAAQH;KAAY;IAElD,2GAA2G;IAC3G,IAAIA,aAAauB,kBAAkBC,gBAAgB;QACjD,qBACE,KAACC;YAAsBD,gBAAgBxB,YAAYuB,gBAAgB,CAACC,cAAc;sBAC/EX;;IAGP;IAEA,OAAOA;AACT,EAAE;AAEF,sFAAsF;AACtF,qFAAqF;AACrF,SAASY,sBAAsB,EAC7BD,cAAc,EACdE,QAAQ,EAIT;IACC,MAAMC,YAAYhC;IAElB,qBACE,KAACC,gBAAgBgC,QAAQ;QACvBC,OAAO;YAAEC,OAAO;gBAAE,GAAGH,SAAS;gBAAE,CAACH,cAAc,CAAC,EAAE,CAAC,EAAE;oBAAEK,OAAOL,cAAc,CAAC,EAAE;oBAAEO,SAAS;gBAAM;YAAE;QAAE;kBAEnGL;;AAGP"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PanelGroupDialog.d.ts","sourceRoot":"","sources":["../../../src/components/PanelGroupDialog/PanelGroupDialog.tsx"],"names":[],"mappings":"AAeA,OAAO,EAAE,YAAY,EAAY,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"PanelGroupDialog.d.ts","sourceRoot":"","sources":["../../../src/components/PanelGroupDialog/PanelGroupDialog.tsx"],"names":[],"mappings":"AAeA,OAAO,EAAE,YAAY,EAAY,MAAM,OAAO,CAAC;AAK/C;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,YAAY,CA6D/C"}
|
|
@@ -14,12 +14,14 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
14
14
|
import { IconButton, Dialog, DialogTitle, DialogContent, DialogActions, Button } from '@mui/material';
|
|
15
15
|
import CloseIcon from 'mdi-material-ui/Close';
|
|
16
16
|
import { useState } from 'react';
|
|
17
|
+
import { useVariableValues } from '@perses-dev/plugin-system';
|
|
17
18
|
import { usePanelGroupEditor } from '../../context';
|
|
18
19
|
import { PanelGroupEditorForm, panelGroupEditorFormId } from './PanelGroupEditorForm';
|
|
19
20
|
/**
|
|
20
21
|
* A dialog for adding or editing a Panel Group. Open and initial state is controlled by the DashboardStore.
|
|
21
22
|
*/ export function PanelGroupDialog() {
|
|
22
23
|
const panelGroupEditor = usePanelGroupEditor();
|
|
24
|
+
const variables = useVariableValues();
|
|
23
25
|
// When the user clicks close, start closing but don't call the store yet to keep values stable during animtation
|
|
24
26
|
const [isClosing, setIsClosing] = useState(false);
|
|
25
27
|
const handleClose = ()=>setIsClosing(true);
|
|
@@ -68,6 +70,7 @@ import { PanelGroupEditorForm, panelGroupEditorFormId } from './PanelGroupEditor
|
|
|
68
70
|
},
|
|
69
71
|
children: /*#__PURE__*/ _jsx(PanelGroupEditorForm, {
|
|
70
72
|
initialValues: panelGroupEditor.initialValues,
|
|
73
|
+
variables: Object.keys(variables),
|
|
71
74
|
onSubmit: handleSubmit
|
|
72
75
|
})
|
|
73
76
|
}),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/PanelGroupDialog/PanelGroupDialog.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 { IconButton, Dialog, DialogTitle, DialogContent, DialogActions, Button } from '@mui/material';\nimport CloseIcon from 'mdi-material-ui/Close';\nimport { ReactElement, useState } from 'react';\nimport { usePanelGroupEditor } from '../../context';\nimport { PanelGroupEditorForm, panelGroupEditorFormId, PanelGroupEditorFormProps } from './PanelGroupEditorForm';\n\n/**\n * A dialog for adding or editing a Panel Group. Open and initial state is controlled by the DashboardStore.\n */\nexport function PanelGroupDialog(): ReactElement {\n const panelGroupEditor = usePanelGroupEditor();\n\n // When the user clicks close, start closing but don't call the store yet to keep values stable during animtation\n const [isClosing, setIsClosing] = useState(false);\n const handleClose = (): void => setIsClosing(true);\n\n // Don't call close on the store until the Dialog has completely transitioned out\n const handleExited = (): void => {\n panelGroupEditor?.close();\n setIsClosing(false);\n };\n\n // Dialog is open if we have a model and we're not transitioning out\n const isOpen = panelGroupEditor !== undefined && isClosing === false;\n\n const handleSubmit: PanelGroupEditorFormProps['onSubmit'] = (values) => {\n // This shouldn't happen since we don't render the submit button until we have a model, but check to make TS happy\n if (panelGroupEditor === undefined) {\n throw new Error('Cannot apply changes');\n }\n panelGroupEditor.applyChanges(values);\n handleClose();\n };\n\n return (\n <Dialog open={isOpen} TransitionProps={{ onExited: handleExited }}>\n {panelGroupEditor !== undefined && (\n <>\n <DialogTitle>{panelGroupEditor.mode} Panel Group</DialogTitle>\n <IconButton\n aria-label=\"Close\"\n onClick={panelGroupEditor.close}\n sx={(theme) => ({\n position: 'absolute',\n top: theme.spacing(0.5),\n right: theme.spacing(0.5),\n })}\n >\n <CloseIcon />\n </IconButton>\n <DialogContent dividers sx={{ width: '500px' }}>\n <PanelGroupEditorForm
|
|
1
|
+
{"version":3,"sources":["../../../src/components/PanelGroupDialog/PanelGroupDialog.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 { IconButton, Dialog, DialogTitle, DialogContent, DialogActions, Button } from '@mui/material';\nimport CloseIcon from 'mdi-material-ui/Close';\nimport { ReactElement, useState } from 'react';\nimport { useVariableValues } from '@perses-dev/plugin-system';\nimport { usePanelGroupEditor } from '../../context';\nimport { PanelGroupEditorForm, panelGroupEditorFormId, PanelGroupEditorFormProps } from './PanelGroupEditorForm';\n\n/**\n * A dialog for adding or editing a Panel Group. Open and initial state is controlled by the DashboardStore.\n */\nexport function PanelGroupDialog(): ReactElement {\n const panelGroupEditor = usePanelGroupEditor();\n const variables = useVariableValues();\n\n // When the user clicks close, start closing but don't call the store yet to keep values stable during animtation\n const [isClosing, setIsClosing] = useState(false);\n const handleClose = (): void => setIsClosing(true);\n\n // Don't call close on the store until the Dialog has completely transitioned out\n const handleExited = (): void => {\n panelGroupEditor?.close();\n setIsClosing(false);\n };\n\n // Dialog is open if we have a model and we're not transitioning out\n const isOpen = panelGroupEditor !== undefined && isClosing === false;\n\n const handleSubmit: PanelGroupEditorFormProps['onSubmit'] = (values) => {\n // This shouldn't happen since we don't render the submit button until we have a model, but check to make TS happy\n if (panelGroupEditor === undefined) {\n throw new Error('Cannot apply changes');\n }\n panelGroupEditor.applyChanges(values);\n handleClose();\n };\n\n return (\n <Dialog open={isOpen} TransitionProps={{ onExited: handleExited }}>\n {panelGroupEditor !== undefined && (\n <>\n <DialogTitle>{panelGroupEditor.mode} Panel Group</DialogTitle>\n <IconButton\n aria-label=\"Close\"\n onClick={panelGroupEditor.close}\n sx={(theme) => ({\n position: 'absolute',\n top: theme.spacing(0.5),\n right: theme.spacing(0.5),\n })}\n >\n <CloseIcon />\n </IconButton>\n <DialogContent dividers sx={{ width: '500px' }}>\n <PanelGroupEditorForm\n initialValues={panelGroupEditor.initialValues}\n variables={Object.keys(variables)}\n onSubmit={handleSubmit}\n />\n </DialogContent>\n <DialogActions>\n <Button variant=\"contained\" type=\"submit\" form={panelGroupEditorFormId}>\n {panelGroupEditor.mode === 'Edit' ? 'Apply' : 'Add'}\n </Button>\n <Button variant=\"outlined\" color=\"secondary\" onClick={panelGroupEditor.close}>\n Cancel\n </Button>\n </DialogActions>\n </>\n )}\n </Dialog>\n );\n}\n"],"names":["IconButton","Dialog","DialogTitle","DialogContent","DialogActions","Button","CloseIcon","useState","useVariableValues","usePanelGroupEditor","PanelGroupEditorForm","panelGroupEditorFormId","PanelGroupDialog","panelGroupEditor","variables","isClosing","setIsClosing","handleClose","handleExited","close","isOpen","undefined","handleSubmit","values","Error","applyChanges","open","TransitionProps","onExited","mode","aria-label","onClick","sx","theme","position","top","spacing","right","dividers","width","initialValues","Object","keys","onSubmit","variant","type","form","color"],"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,UAAU,EAAEC,MAAM,EAAEC,WAAW,EAAEC,aAAa,EAAEC,aAAa,EAAEC,MAAM,QAAQ,gBAAgB;AACtG,OAAOC,eAAe,wBAAwB;AAC9C,SAAuBC,QAAQ,QAAQ,QAAQ;AAC/C,SAASC,iBAAiB,QAAQ,4BAA4B;AAC9D,SAASC,mBAAmB,QAAQ,gBAAgB;AACpD,SAASC,oBAAoB,EAAEC,sBAAsB,QAAmC,yBAAyB;AAEjH;;CAEC,GACD,OAAO,SAASC;IACd,MAAMC,mBAAmBJ;IACzB,MAAMK,YAAYN;IAElB,iHAAiH;IACjH,MAAM,CAACO,WAAWC,aAAa,GAAGT,SAAS;IAC3C,MAAMU,cAAc,IAAYD,aAAa;IAE7C,iFAAiF;IACjF,MAAME,eAAe;QACnBL,kBAAkBM;QAClBH,aAAa;IACf;IAEA,oEAAoE;IACpE,MAAMI,SAASP,qBAAqBQ,aAAaN,cAAc;IAE/D,MAAMO,eAAsD,CAACC;QAC3D,kHAAkH;QAClH,IAAIV,qBAAqBQ,WAAW;YAClC,MAAM,IAAIG,MAAM;QAClB;QACAX,iBAAiBY,YAAY,CAACF;QAC9BN;IACF;IAEA,qBACE,KAAChB;QAAOyB,MAAMN;QAAQO,iBAAiB;YAAEC,UAAUV;QAAa;kBAC7DL,qBAAqBQ,2BACpB;;8BACE,MAACnB;;wBAAaW,iBAAiBgB,IAAI;wBAAC;;;8BACpC,KAAC7B;oBACC8B,cAAW;oBACXC,SAASlB,iBAAiBM,KAAK;oBAC/Ba,IAAI,CAACC,QAAW,CAAA;4BACdC,UAAU;4BACVC,KAAKF,MAAMG,OAAO,CAAC;4BACnBC,OAAOJ,MAAMG,OAAO,CAAC;wBACvB,CAAA;8BAEA,cAAA,KAAC9B;;8BAEH,KAACH;oBAAcmC,QAAQ;oBAACN,IAAI;wBAAEO,OAAO;oBAAQ;8BAC3C,cAAA,KAAC7B;wBACC8B,eAAe3B,iBAAiB2B,aAAa;wBAC7C1B,WAAW2B,OAAOC,IAAI,CAAC5B;wBACvB6B,UAAUrB;;;8BAGd,MAAClB;;sCACC,KAACC;4BAAOuC,SAAQ;4BAAYC,MAAK;4BAASC,MAAMnC;sCAC7CE,iBAAiBgB,IAAI,KAAK,SAAS,UAAU;;sCAEhD,KAACxB;4BAAOuC,SAAQ;4BAAWG,OAAM;4BAAYhB,SAASlB,iBAAiBM,KAAK;sCAAE;;;;;;;AAQ1F"}
|
|
@@ -2,6 +2,7 @@ import { ReactElement } from 'react';
|
|
|
2
2
|
import { PanelGroupEditorValues } from '../../context';
|
|
3
3
|
export interface PanelGroupEditorFormProps {
|
|
4
4
|
initialValues: PanelGroupEditorValues;
|
|
5
|
+
variables?: string[];
|
|
5
6
|
onSubmit: (next: PanelGroupEditorValues) => void;
|
|
6
7
|
}
|
|
7
8
|
export declare function PanelGroupEditorForm(props: PanelGroupEditorFormProps): ReactElement;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PanelGroupEditorForm.d.ts","sourceRoot":"","sources":["../../../src/components/PanelGroupDialog/PanelGroupEditorForm.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAoB,YAAY,EAAY,MAAM,OAAO,CAAC;AAEjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"PanelGroupEditorForm.d.ts","sourceRoot":"","sources":["../../../src/components/PanelGroupDialog/PanelGroupEditorForm.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAoB,YAAY,EAAY,MAAM,OAAO,CAAC;AAEjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAEvD,MAAM,WAAW,yBAAyB;IACxC,aAAa,EAAE,sBAAsB,CAAC;IACtC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,EAAE,CAAC,IAAI,EAAE,sBAAsB,KAAK,IAAI,CAAC;CAClD;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,yBAAyB,GAAG,YAAY,CA2DnF;AAED;;GAEG;AACH,eAAO,MAAM,sBAAsB,4BAA4B,CAAC"}
|