@perses-dev/dashboards 0.0.0-snapshot-time-zone-selector-946f408 → 0.0.0-snapshot-timeseries-panel-actions-e28c1fe
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/DashboardToolbar/DashboardToolbar.js +98 -109
- package/dist/cjs/components/DownloadButton/DownloadButton.js +3 -33
- package/dist/cjs/components/DownloadButton/serializeDashboard.js +64 -0
- package/dist/cjs/components/Panel/Panel.js +85 -1
- package/dist/cjs/components/Panel/PanelActions.js +45 -8
- package/dist/cjs/components/Panel/PanelHeader.js +11 -3
- package/dist/cjs/components/SaveChangesConfirmationDialog/SaveChangesConfirmationDialog.js +1 -13
- package/dist/cjs/components/SaveDashboardButton/SaveDashboardButton.js +3 -10
- package/dist/cjs/context/DashboardProvider/DashboardProvider.js +2 -4
- package/dist/cjs/context/useDashboard.js +1 -3
- package/dist/cjs/views/ViewDashboard/ViewDashboard.js +0 -2
- package/dist/components/DashboardToolbar/DashboardToolbar.d.ts.map +1 -1
- package/dist/components/DashboardToolbar/DashboardToolbar.js +100 -111
- package/dist/components/DashboardToolbar/DashboardToolbar.js.map +1 -1
- package/dist/components/DownloadButton/DownloadButton.d.ts.map +1 -1
- package/dist/components/DownloadButton/DownloadButton.js +3 -33
- package/dist/components/DownloadButton/DownloadButton.js.map +1 -1
- package/dist/components/DownloadButton/serializeDashboard.d.ts +8 -0
- package/dist/components/DownloadButton/serializeDashboard.d.ts.map +1 -0
- package/dist/components/DownloadButton/serializeDashboard.js +56 -0
- package/dist/components/DownloadButton/serializeDashboard.js.map +1 -0
- package/dist/components/Panel/Panel.d.ts.map +1 -1
- package/dist/components/Panel/Panel.js +87 -3
- package/dist/components/Panel/Panel.js.map +1 -1
- package/dist/components/Panel/PanelActions.d.ts +4 -3
- package/dist/components/Panel/PanelActions.d.ts.map +1 -1
- package/dist/components/Panel/PanelActions.js +45 -8
- package/dist/components/Panel/PanelActions.js.map +1 -1
- package/dist/components/Panel/PanelHeader.d.ts +2 -1
- package/dist/components/Panel/PanelHeader.d.ts.map +1 -1
- package/dist/components/Panel/PanelHeader.js +11 -3
- package/dist/components/Panel/PanelHeader.js.map +1 -1
- package/dist/components/SaveChangesConfirmationDialog/SaveChangesConfirmationDialog.d.ts.map +1 -1
- package/dist/components/SaveChangesConfirmationDialog/SaveChangesConfirmationDialog.js +2 -14
- package/dist/components/SaveChangesConfirmationDialog/SaveChangesConfirmationDialog.js.map +1 -1
- package/dist/components/SaveDashboardButton/SaveDashboardButton.d.ts.map +1 -1
- package/dist/components/SaveDashboardButton/SaveDashboardButton.js +4 -11
- package/dist/components/SaveDashboardButton/SaveDashboardButton.js.map +1 -1
- package/dist/context/DashboardProvider/DashboardProvider.d.ts +0 -1
- package/dist/context/DashboardProvider/DashboardProvider.d.ts.map +1 -1
- package/dist/context/DashboardProvider/DashboardProvider.js +3 -5
- package/dist/context/DashboardProvider/DashboardProvider.js.map +1 -1
- package/dist/context/DashboardProvider/save-changes-dialog-slice.d.ts +1 -2
- package/dist/context/DashboardProvider/save-changes-dialog-slice.d.ts.map +1 -1
- package/dist/context/DashboardProvider/save-changes-dialog-slice.js.map +1 -1
- package/dist/context/useDashboard.d.ts.map +1 -1
- package/dist/context/useDashboard.js +1 -3
- package/dist/context/useDashboard.js.map +1 -1
- package/dist/views/ViewDashboard/ViewDashboard.d.ts.map +1 -1
- package/dist/views/ViewDashboard/ViewDashboard.js +1 -3
- package/dist/views/ViewDashboard/ViewDashboard.js.map +1 -1
- package/package.json +5 -5
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
14
14
|
import { Card, CardContent } from '@mui/material';
|
|
15
15
|
import { ErrorAlert, ErrorBoundary, combineSx, useChartsTheme, useId } from '@perses-dev/components';
|
|
16
|
-
import { useDataQueriesContext } from '@perses-dev/plugin-system';
|
|
17
|
-
import { memo, useMemo, useState } from 'react';
|
|
16
|
+
import { useDataQueriesContext, usePluginRegistry } from '@perses-dev/plugin-system';
|
|
17
|
+
import { memo, useMemo, useState, useEffect } from 'react';
|
|
18
18
|
import useResizeObserver from 'use-resize-observer';
|
|
19
19
|
import { PanelContent } from './PanelContent';
|
|
20
20
|
import { PanelHeader } from './PanelHeader';
|
|
@@ -46,6 +46,88 @@ import { PanelHeader } from './PanelHeader';
|
|
|
46
46
|
]);
|
|
47
47
|
const chartsTheme = useChartsTheme();
|
|
48
48
|
const { queryResults } = useDataQueriesContext();
|
|
49
|
+
const { getPlugin } = usePluginRegistry();
|
|
50
|
+
const panelPropsForActions = useMemo(()=>{
|
|
51
|
+
return {
|
|
52
|
+
spec: definition.spec.plugin.spec,
|
|
53
|
+
queryResults: queryResults.map((query)=>({
|
|
54
|
+
definition: query.definition,
|
|
55
|
+
data: query.data
|
|
56
|
+
})),
|
|
57
|
+
contentDimensions,
|
|
58
|
+
definition
|
|
59
|
+
};
|
|
60
|
+
}, [
|
|
61
|
+
definition,
|
|
62
|
+
contentDimensions,
|
|
63
|
+
queryResults
|
|
64
|
+
]);
|
|
65
|
+
// Load plugin actions from the plugin
|
|
66
|
+
const [pluginActions, setPluginActions] = useState([]);
|
|
67
|
+
useEffect(()=>{
|
|
68
|
+
let cancelled = false;
|
|
69
|
+
const loadPluginActions = async ()=>{
|
|
70
|
+
const panelPluginKind = definition.spec.plugin.kind;
|
|
71
|
+
const panelProps = panelPropsForActions;
|
|
72
|
+
if (!panelPluginKind || !panelProps) {
|
|
73
|
+
if (!cancelled) {
|
|
74
|
+
setPluginActions([]);
|
|
75
|
+
}
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
// Add defensive check for getPlugin availability
|
|
80
|
+
if (!getPlugin || typeof getPlugin !== 'function') {
|
|
81
|
+
if (!cancelled) {
|
|
82
|
+
setPluginActions([]);
|
|
83
|
+
}
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const plugin = await getPlugin('Panel', panelPluginKind);
|
|
87
|
+
if (cancelled) return;
|
|
88
|
+
// More defensive checking for plugin and actions
|
|
89
|
+
if (!plugin || typeof plugin !== 'object' || !plugin.actions || !Array.isArray(plugin.actions) || plugin.actions.length === 0) {
|
|
90
|
+
if (!cancelled) {
|
|
91
|
+
setPluginActions([]);
|
|
92
|
+
}
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
// Render plugin actions in header location
|
|
96
|
+
const headerActions = plugin.actions.filter((action)=>!action.location || action.location === 'header').map((action, index)=>{
|
|
97
|
+
const ActionComponent = action.component;
|
|
98
|
+
try {
|
|
99
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
100
|
+
return /*#__PURE__*/ _jsx(ActionComponent, {
|
|
101
|
+
...panelProps
|
|
102
|
+
}, `plugin-action-${index}`);
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.warn(`Failed to render plugin action ${index}:`, error);
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
}).filter((item)=>Boolean(item));
|
|
108
|
+
if (!cancelled) {
|
|
109
|
+
setPluginActions(headerActions);
|
|
110
|
+
}
|
|
111
|
+
} catch (error) {
|
|
112
|
+
if (!cancelled) {
|
|
113
|
+
console.warn('Failed to load plugin actions:', error);
|
|
114
|
+
setPluginActions([]);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
// Use setTimeout to defer the async operation to the next tick
|
|
119
|
+
const timeoutId = setTimeout(()=>{
|
|
120
|
+
loadPluginActions();
|
|
121
|
+
}, 0);
|
|
122
|
+
return ()=>{
|
|
123
|
+
cancelled = true;
|
|
124
|
+
clearTimeout(timeoutId);
|
|
125
|
+
};
|
|
126
|
+
}, [
|
|
127
|
+
definition.spec.plugin.kind,
|
|
128
|
+
panelPropsForActions,
|
|
129
|
+
getPlugin
|
|
130
|
+
]);
|
|
49
131
|
const handleMouseEnter = (e)=>{
|
|
50
132
|
onMouseEnter?.(e);
|
|
51
133
|
};
|
|
@@ -83,6 +165,7 @@ import { PanelHeader } from './PanelHeader';
|
|
|
83
165
|
readHandlers: readHandlers,
|
|
84
166
|
editHandlers: editHandlers,
|
|
85
167
|
links: definition.spec.links,
|
|
168
|
+
pluginActions: pluginActions,
|
|
86
169
|
sx: {
|
|
87
170
|
paddingX: `${chartsTheme.container.padding.default}px`
|
|
88
171
|
}
|
|
@@ -104,7 +187,8 @@ import { PanelHeader } from './PanelHeader';
|
|
|
104
187
|
children: /*#__PURE__*/ _jsx(ErrorBoundary, {
|
|
105
188
|
FallbackComponent: ErrorAlert,
|
|
106
189
|
resetKeys: [
|
|
107
|
-
definition.spec
|
|
190
|
+
definition.spec,
|
|
191
|
+
queryResults
|
|
108
192
|
],
|
|
109
193
|
children: /*#__PURE__*/ _jsx(PanelContent, {
|
|
110
194
|
definition: definition,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/Panel/Panel.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 { Card, CardContent, CardProps } from '@mui/material';\nimport { ErrorAlert, ErrorBoundary, combineSx, useChartsTheme, useId } from '@perses-dev/components';\nimport { PanelDefinition } from '@perses-dev/core';\nimport { useDataQueriesContext } from '@perses-dev/plugin-system';\nimport { ReactNode, memo, useMemo, useState } from 'react';\nimport useResizeObserver from 'use-resize-observer';\nimport { PanelGroupItemId } from '../../context';\nimport { PanelContent } from './PanelContent';\nimport { PanelHeader, PanelHeaderProps } from './PanelHeader';\n\nexport interface PanelProps extends CardProps<'section'> {\n definition: PanelDefinition;\n readHandlers?: PanelHeaderProps['readHandlers'];\n editHandlers?: PanelHeaderProps['editHandlers'];\n panelOptions?: PanelOptions;\n panelGroupItemId?: PanelGroupItemId;\n}\n\nexport type PanelOptions = {\n /**\n * Allow you to hide the panel header if desired.\n * This can be useful in embedded mode for example.\n */\n hideHeader?: boolean;\n /**\n * Content to render in right of the panel header. (top right of the panel)\n * It will only be rendered when the panel is in edit mode.\n */\n extra?: (props: PanelExtraProps) => ReactNode;\n};\n\nexport type PanelExtraProps = {\n /**\n * The PanelDefinition for the panel.\n */\n panelDefinition?: PanelDefinition;\n /**\n * The PanelGroupItemId for the panel.\n */\n panelGroupItemId?: PanelGroupItemId;\n};\n\n/**\n * Renders a PanelDefinition's content inside of a Card.\n *\n * Internal structure:\n * <Panel> // renders an entire panel, incl. header and action buttons\n * <PanelContent> // renders loading, error or panel based on the queries' status\n * <PanelPluginLoader> // loads a panel plugin from the plugin registry and renders the PanelComponent with data from props.queryResults\n */\nexport const Panel = memo(function Panel(props: PanelProps) {\n const {\n definition,\n readHandlers,\n editHandlers,\n onMouseEnter,\n onMouseLeave,\n sx,\n panelOptions,\n panelGroupItemId,\n ...others\n } = props;\n\n // Make sure we have an ID we can use for aria attributes\n const generatedPanelId = useId('Panel');\n const headerId = `${generatedPanelId}-header`;\n\n const [contentElement, setContentElement] = useState<HTMLElement | null>(null);\n\n const { width, height } = useResizeObserver({ ref: contentElement });\n\n const contentDimensions = useMemo(() => {\n if (width === undefined || height === undefined) return undefined;\n return { width, height };\n }, [width, height]);\n\n const chartsTheme = useChartsTheme();\n\n const { queryResults } = useDataQueriesContext();\n\n const handleMouseEnter: CardProps['onMouseEnter'] = (e) => {\n onMouseEnter?.(e);\n };\n\n const handleMouseLeave: CardProps['onMouseLeave'] = (e) => {\n onMouseLeave?.(e);\n };\n\n return (\n <Card\n component=\"section\"\n sx={combineSx(\n {\n width: '100%',\n height: '100%',\n display: 'flex',\n flexFlow: 'column nowrap',\n ':hover': { '--panel-hover': 'block' },\n },\n sx\n )}\n variant=\"outlined\"\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n aria-labelledby={headerId}\n aria-describedby={headerId}\n data-testid=\"panel\"\n {...others}\n >\n {!panelOptions?.hideHeader && (\n <PanelHeader\n extra={panelOptions?.extra?.({ panelDefinition: definition, panelGroupItemId })}\n id={headerId}\n title={definition.spec.display.name}\n description={definition.spec.display.description}\n queryResults={queryResults}\n readHandlers={readHandlers}\n editHandlers={editHandlers}\n links={definition.spec.links}\n sx={{ paddingX: `${chartsTheme.container.padding.default}px` }}\n />\n )}\n <CardContent\n component=\"figure\"\n sx={{\n position: 'relative',\n overflow: 'hidden',\n flexGrow: 1,\n margin: 0,\n padding: 0,\n // Override MUI default style for last-child\n ':last-child': {\n padding: 0,\n },\n }}\n ref={setContentElement}\n >\n <ErrorBoundary FallbackComponent={ErrorAlert} resetKeys={[definition.spec]}>\n <PanelContent\n definition={definition}\n panelPluginKind={definition.spec.plugin.kind}\n spec={definition.spec.plugin.spec}\n contentDimensions={contentDimensions}\n queryResults={queryResults}\n />\n </ErrorBoundary>\n </CardContent>\n </Card>\n );\n});\n"],"names":["Card","CardContent","ErrorAlert","ErrorBoundary","combineSx","useChartsTheme","useId","useDataQueriesContext","memo","useMemo","useState","useResizeObserver","PanelContent","PanelHeader","Panel","props","definition","readHandlers","editHandlers","onMouseEnter","onMouseLeave","sx","panelOptions","panelGroupItemId","others","generatedPanelId","headerId","contentElement","setContentElement","width","height","ref","contentDimensions","undefined","chartsTheme","queryResults","handleMouseEnter","e","handleMouseLeave","component","display","flexFlow","variant","aria-labelledby","aria-describedby","data-testid","hideHeader","extra","panelDefinition","id","title","spec","name","description","links","paddingX","container","padding","default","position","overflow","flexGrow","margin","FallbackComponent","resetKeys","panelPluginKind","plugin","kind"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/Panel/Panel.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 { Card, CardContent, CardProps } from '@mui/material';\nimport { ErrorAlert, ErrorBoundary, combineSx, useChartsTheme, useId } from '@perses-dev/components';\nimport { PanelDefinition } from '@perses-dev/core';\nimport { useDataQueriesContext, usePluginRegistry } from '@perses-dev/plugin-system';\nimport { ReactNode, memo, useMemo, useState, useEffect } from 'react';\nimport useResizeObserver from 'use-resize-observer';\nimport { PanelGroupItemId } from '../../context';\nimport { PanelContent } from './PanelContent';\nimport { PanelHeader, PanelHeaderProps } from './PanelHeader';\n\nexport interface PanelProps extends CardProps<'section'> {\n definition: PanelDefinition;\n readHandlers?: PanelHeaderProps['readHandlers'];\n editHandlers?: PanelHeaderProps['editHandlers'];\n panelOptions?: PanelOptions;\n panelGroupItemId?: PanelGroupItemId;\n}\n\nexport type PanelOptions = {\n /**\n * Allow you to hide the panel header if desired.\n * This can be useful in embedded mode for example.\n */\n hideHeader?: boolean;\n /**\n * Content to render in right of the panel header. (top right of the panel)\n * It will only be rendered when the panel is in edit mode.\n */\n extra?: (props: PanelExtraProps) => ReactNode;\n};\n\nexport type PanelExtraProps = {\n /**\n * The PanelDefinition for the panel.\n */\n panelDefinition?: PanelDefinition;\n /**\n * The PanelGroupItemId for the panel.\n */\n panelGroupItemId?: PanelGroupItemId;\n};\n\n/**\n * Renders a PanelDefinition's content inside of a Card.\n *\n * Internal structure:\n * <Panel> // renders an entire panel, incl. header and action buttons\n * <PanelContent> // renders loading, error or panel based on the queries' status\n * <PanelPluginLoader> // loads a panel plugin from the plugin registry and renders the PanelComponent with data from props.queryResults\n */\nexport const Panel = memo(function Panel(props: PanelProps) {\n const {\n definition,\n readHandlers,\n editHandlers,\n onMouseEnter,\n onMouseLeave,\n sx,\n panelOptions,\n panelGroupItemId,\n ...others\n } = props;\n\n // Make sure we have an ID we can use for aria attributes\n const generatedPanelId = useId('Panel');\n const headerId = `${generatedPanelId}-header`;\n\n const [contentElement, setContentElement] = useState<HTMLElement | null>(null);\n\n const { width, height } = useResizeObserver({ ref: contentElement });\n\n const contentDimensions = useMemo(() => {\n if (width === undefined || height === undefined) return undefined;\n return { width, height };\n }, [width, height]);\n\n const chartsTheme = useChartsTheme();\n\n const { queryResults } = useDataQueriesContext();\n const { getPlugin } = usePluginRegistry();\n\n const panelPropsForActions = useMemo(() => {\n return {\n spec: definition.spec.plugin.spec,\n queryResults: queryResults.map((query) => ({\n definition: query.definition,\n data: query.data,\n })),\n contentDimensions,\n definition,\n };\n }, [definition, contentDimensions, queryResults]);\n\n // Load plugin actions from the plugin\n const [pluginActions, setPluginActions] = useState<ReactNode[]>([]);\n\n useEffect(() => {\n let cancelled = false;\n\n const loadPluginActions = async (): Promise<void> => {\n const panelPluginKind = definition.spec.plugin.kind;\n const panelProps = panelPropsForActions;\n\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 }, [definition.spec.plugin.kind, panelPropsForActions, getPlugin]);\n\n const handleMouseEnter: CardProps['onMouseEnter'] = (e) => {\n onMouseEnter?.(e);\n };\n\n const handleMouseLeave: CardProps['onMouseLeave'] = (e) => {\n onMouseLeave?.(e);\n };\n\n return (\n <Card\n component=\"section\"\n sx={combineSx(\n {\n width: '100%',\n height: '100%',\n display: 'flex',\n flexFlow: 'column nowrap',\n ':hover': { '--panel-hover': 'block' },\n },\n sx\n )}\n variant=\"outlined\"\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n aria-labelledby={headerId}\n aria-describedby={headerId}\n data-testid=\"panel\"\n {...others}\n >\n {!panelOptions?.hideHeader && (\n <PanelHeader\n extra={panelOptions?.extra?.({ panelDefinition: definition, panelGroupItemId })}\n id={headerId}\n title={definition.spec.display.name}\n description={definition.spec.display.description}\n queryResults={queryResults}\n readHandlers={readHandlers}\n editHandlers={editHandlers}\n links={definition.spec.links}\n pluginActions={pluginActions}\n sx={{ paddingX: `${chartsTheme.container.padding.default}px` }}\n />\n )}\n <CardContent\n component=\"figure\"\n sx={{\n position: 'relative',\n overflow: 'hidden',\n flexGrow: 1,\n margin: 0,\n padding: 0,\n // Override MUI default style for last-child\n ':last-child': {\n padding: 0,\n },\n }}\n ref={setContentElement}\n >\n <ErrorBoundary FallbackComponent={ErrorAlert} resetKeys={[definition.spec, queryResults]}>\n <PanelContent\n definition={definition}\n panelPluginKind={definition.spec.plugin.kind}\n spec={definition.spec.plugin.spec}\n contentDimensions={contentDimensions}\n queryResults={queryResults}\n />\n </ErrorBoundary>\n </CardContent>\n </Card>\n );\n});\n"],"names":["Card","CardContent","ErrorAlert","ErrorBoundary","combineSx","useChartsTheme","useId","useDataQueriesContext","usePluginRegistry","memo","useMemo","useState","useEffect","useResizeObserver","PanelContent","PanelHeader","Panel","props","definition","readHandlers","editHandlers","onMouseEnter","onMouseLeave","sx","panelOptions","panelGroupItemId","others","generatedPanelId","headerId","contentElement","setContentElement","width","height","ref","contentDimensions","undefined","chartsTheme","queryResults","getPlugin","panelPropsForActions","spec","plugin","map","query","data","pluginActions","setPluginActions","cancelled","loadPluginActions","panelPluginKind","kind","panelProps","actions","Array","isArray","length","headerActions","filter","action","location","index","ActionComponent","component","error","console","warn","item","Boolean","timeoutId","setTimeout","clearTimeout","handleMouseEnter","e","handleMouseLeave","display","flexFlow","variant","aria-labelledby","aria-describedby","data-testid","hideHeader","extra","panelDefinition","id","title","name","description","links","paddingX","container","padding","default","position","overflow","flexGrow","margin","FallbackComponent","resetKeys"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
import { QueryData } from '@perses-dev/plugin-system';
|
|
1
|
+
import { ReactNode } from 'react';
|
|
3
2
|
import { Link } from '@perses-dev/core';
|
|
3
|
+
import { PanelContentProps } from './PanelContent';
|
|
4
4
|
export interface PanelActionsProps {
|
|
5
5
|
title: string;
|
|
6
6
|
description?: string;
|
|
@@ -16,7 +16,8 @@ export interface PanelActionsProps {
|
|
|
16
16
|
isPanelViewed?: boolean;
|
|
17
17
|
onViewPanelClick: () => void;
|
|
18
18
|
};
|
|
19
|
-
|
|
19
|
+
panelContentProps: Pick<PanelContentProps, 'queryResults'>;
|
|
20
|
+
pluginActions?: ReactNode[];
|
|
20
21
|
}
|
|
21
22
|
export declare const PanelActions: React.FC<PanelActionsProps>;
|
|
22
23
|
//# sourceMappingURL=PanelActions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PanelActions.d.ts","sourceRoot":"","sources":["../../../src/components/Panel/PanelActions.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"PanelActions.d.ts","sourceRoot":"","sources":["../../../src/components/Panel/PanelActions.tsx"],"names":[],"mappings":"AAcA,OAAO,EAAqC,SAAS,EAAqB,MAAM,OAAO,CAAC;AAYxF,OAAO,EAAE,IAAI,EAAkB,MAAM,kBAAkB,CAAC;AAUxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEnD,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;IACf,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,YAAY,CAAC,EAAE;QACb,gBAAgB,EAAE,MAAM,IAAI,CAAC;QAC7B,qBAAqB,EAAE,MAAM,IAAI,CAAC;QAClC,kBAAkB,EAAE,MAAM,IAAI,CAAC;KAChC,CAAC;IACF,YAAY,CAAC,EAAE;QACb,aAAa,CAAC,EAAE,OAAO,CAAC;QACxB,gBAAgB,EAAE,MAAM,IAAI,CAAC;KAC9B,CAAC;IACF,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,EAAE,cAAc,CAAC,CAAC;IAC3D,aAAa,CAAC,EAAE,SAAS,EAAE,CAAC;CAC7B;AASD,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CA4OpD,CAAC"}
|
|
@@ -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 { 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,10 @@ 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,
|
|
36
|
+
export const PanelActions = ({ editHandlers, readHandlers, extra, title, description, descriptionTooltipId, links, panelContentProps, pluginActions = [] })=>{
|
|
37
|
+
const { isFetching, errors } = useDataQueriesContext();
|
|
38
|
+
// Only destructure queryResults since we removed panelPluginKind and spec
|
|
39
|
+
const { queryResults } = panelContentProps;
|
|
36
40
|
const descriptionAction = useMemo(()=>{
|
|
37
41
|
if (description && description.trim().length > 0) {
|
|
38
42
|
return /*#__PURE__*/ _jsx(InfoTooltip, {
|
|
@@ -63,19 +67,45 @@ export const PanelActions = ({ editHandlers, readHandlers, extra, title, descrip
|
|
|
63
67
|
});
|
|
64
68
|
const extraActions = editHandlers === undefined && extra;
|
|
65
69
|
const queryStateIndicator = useMemo(()=>{
|
|
66
|
-
|
|
67
|
-
const
|
|
70
|
+
// Check if any query is fetching
|
|
71
|
+
const isQueryFetching = queryResults.some((q)=>q.isFetching);
|
|
72
|
+
// Get query-specific errors
|
|
68
73
|
const queryErrors = queryResults.filter((q)=>q.error);
|
|
69
|
-
|
|
74
|
+
// Convert QueryData[] to TimeSeriesData format for data availability check
|
|
75
|
+
const timeSeriesData = queryResults && queryResults.length > 0 ? {
|
|
76
|
+
series: queryResults.flatMap((q)=>{
|
|
77
|
+
// Only extract series if the data type is TimeSeriesData
|
|
78
|
+
if (q.data && typeof q.data === 'object' && 'series' in q.data) {
|
|
79
|
+
return q.data.series || [];
|
|
80
|
+
}
|
|
81
|
+
return [];
|
|
82
|
+
})
|
|
83
|
+
} : undefined;
|
|
84
|
+
const hasData = timeSeriesData && timeSeriesData.series && timeSeriesData.series.length > 0;
|
|
85
|
+
// Show loading indicator if queries are fetching AND we already have data
|
|
86
|
+
if ((isFetching || isQueryFetching) && hasData) {
|
|
70
87
|
// If the panel has no data, the panel content will show the loading overlay.
|
|
71
88
|
// Therefore, show the circular loading indicator only in case the panel doesn't display the loading overlay already.
|
|
72
89
|
return /*#__PURE__*/ _jsx(CircularProgress, {
|
|
73
90
|
"aria-label": "loading",
|
|
74
91
|
size: "1.125rem"
|
|
75
92
|
});
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
93
|
+
}
|
|
94
|
+
// Check for errors from both context and query results
|
|
95
|
+
const contextErrors = (errors || []).filter((error)=>error !== null);
|
|
96
|
+
const allErrors = [
|
|
97
|
+
...contextErrors,
|
|
98
|
+
...queryErrors.map((q)=>q.error)
|
|
99
|
+
].filter(Boolean);
|
|
100
|
+
if (allErrors.length > 0) {
|
|
101
|
+
const errorTexts = allErrors.map((e)=>{
|
|
102
|
+
if (typeof e === 'string') return e;
|
|
103
|
+
if (e && typeof e === 'object') {
|
|
104
|
+
const errorObj = e;
|
|
105
|
+
return errorObj.message ?? errorObj.toString?.() ?? 'Unknown error';
|
|
106
|
+
}
|
|
107
|
+
return 'Unknown error';
|
|
108
|
+
}).join('\n');
|
|
79
109
|
return /*#__PURE__*/ _jsx(InfoTooltip, {
|
|
80
110
|
description: errorTexts,
|
|
81
111
|
children: /*#__PURE__*/ _jsx(HeaderIconButton, {
|
|
@@ -88,7 +118,9 @@ export const PanelActions = ({ editHandlers, readHandlers, extra, title, descrip
|
|
|
88
118
|
});
|
|
89
119
|
}
|
|
90
120
|
}, [
|
|
91
|
-
queryResults
|
|
121
|
+
queryResults,
|
|
122
|
+
isFetching,
|
|
123
|
+
errors
|
|
92
124
|
]);
|
|
93
125
|
const readActions = useMemo(()=>{
|
|
94
126
|
if (readHandlers !== undefined) {
|
|
@@ -227,6 +259,7 @@ export const PanelActions = ({ editHandlers, readHandlers, extra, title, descrip
|
|
|
227
259
|
editActions
|
|
228
260
|
]
|
|
229
261
|
}),
|
|
262
|
+
pluginActions,
|
|
230
263
|
moveAction
|
|
231
264
|
]
|
|
232
265
|
})
|
|
@@ -254,6 +287,8 @@ export const PanelActions = ({ editHandlers, readHandlers, extra, title, descrip
|
|
|
254
287
|
extraActions,
|
|
255
288
|
" ",
|
|
256
289
|
readActions,
|
|
290
|
+
" ",
|
|
291
|
+
pluginActions,
|
|
257
292
|
/*#__PURE__*/ _jsx(OverflowMenu, {
|
|
258
293
|
title: title,
|
|
259
294
|
children: editActions
|
|
@@ -288,6 +323,8 @@ export const PanelActions = ({ editHandlers, readHandlers, extra, title, descrip
|
|
|
288
323
|
" ",
|
|
289
324
|
readActions,
|
|
290
325
|
" ",
|
|
326
|
+
pluginActions,
|
|
327
|
+
" ",
|
|
291
328
|
editActions,
|
|
292
329
|
" ",
|
|
293
330
|
moveAction
|
|
@@ -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 } from 'react';\nimport { InfoTooltip } from '@perses-dev/components';\nimport { 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';\nimport { PanelContentProps } from './PanelContent';\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 panelContentProps: Pick<PanelContentProps, 'queryResults'>;\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 panelContentProps,\n pluginActions = [],\n}) => {\n const { isFetching, errors } = useDataQueriesContext();\n\n // Only destructure queryResults since we removed panelPluginKind and spec\n const { queryResults } = panelContentProps;\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 // Check if any query is fetching\n const isQueryFetching = queryResults.some((q) => q.isFetching);\n // Get query-specific errors\n const queryErrors = queryResults.filter((q) => q.error);\n\n // Convert QueryData[] to TimeSeriesData format for data availability check\n const timeSeriesData: TimeSeriesData | undefined =\n queryResults && queryResults.length > 0\n ? {\n series: queryResults.flatMap((q) => {\n // Only extract series if the data type is TimeSeriesData\n if (q.data && typeof q.data === 'object' && 'series' in q.data) {\n return q.data.series || [];\n }\n return [];\n }),\n }\n : undefined;\n\n const hasData = timeSeriesData && timeSeriesData.series && timeSeriesData.series.length > 0;\n\n // Show loading indicator if queries are fetching AND we already have data\n if ((isFetching || isQueryFetching) && 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 }\n\n // Check for errors from both context and query results\n const contextErrors = (errors || []).filter((error) => error !== null);\n const allErrors = [...contextErrors, ...queryErrors.map((q) => q.error)].filter(Boolean);\n\n if (allErrors.length > 0) {\n const errorTexts = allErrors\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 // 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} {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} {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 // 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} {pluginActions} {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>): 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","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","panelContentProps","pluginActions","isFetching","errors","queryResults","descriptionAction","trim","length","id","enterDelay","aria-label","size","aria-describedby","aria-hidden","fontSize","sx","color","theme","palette","text","secondary","undefined","linksAction","extraActions","queryStateIndicator","isQueryFetching","some","q","queryErrors","filter","error","timeSeriesData","series","flatMap","data","hasData","contextErrors","allErrors","map","Boolean","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","Array","isArray","handleClick","event","currentTarget","getBoundingClientRect","handleClose","open","showPanelActions","anchorReference","onClose","anchorOrigin","vertical","horizontal","direction","padding"],"mappings":"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"}
|
|
@@ -13,7 +13,8 @@ export interface PanelHeaderProps extends Omit<CardHeaderProps, OmittedProps> {
|
|
|
13
13
|
queryResults: QueryData[];
|
|
14
14
|
readHandlers?: PanelActionsProps['readHandlers'];
|
|
15
15
|
editHandlers?: PanelActionsProps['editHandlers'];
|
|
16
|
+
pluginActions?: ReactNode[];
|
|
16
17
|
}
|
|
17
|
-
export declare function PanelHeader({ id, title: rawTitle, description: rawDescription, links, queryResults, readHandlers, editHandlers, sx, extra, ...rest }: PanelHeaderProps): ReactElement;
|
|
18
|
+
export declare function PanelHeader({ id, title: rawTitle, description: rawDescription, links, queryResults, readHandlers, editHandlers, sx, extra, pluginActions, ...rest }: PanelHeaderProps): ReactElement;
|
|
18
19
|
export {};
|
|
19
20
|
//# 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,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,SAAS,EAA+B,MAAM,2BAA2B,CAAC;AACnF,OAAO,EAAE,YAAY,EAAE,SAAS,
|
|
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,EAAE,MAAM,kBAAkB,CAAC;AACxC,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;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,YAAY,CAAC,EAAE,iBAAiB,CAAC,cAAc,CAAC,CAAC;IACjD,YAAY,CAAC,EAAE,iBAAiB,CAAC,cAAc,CAAC,CAAC;IACjD,aAAa,CAAC,EAAE,SAAS,EAAE,CAAC;CAC7B;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,GAAG,IAAI,EACR,EAAE,gBAAgB,GAAG,YAAY,CAmEjC"}
|
|
@@ -14,13 +14,20 @@ 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, pluginActions, ...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
|
+
// Create the panelContentProps object with only queryResults
|
|
26
|
+
const panelContentProps = useMemo(()=>({
|
|
27
|
+
queryResults
|
|
28
|
+
}), [
|
|
29
|
+
queryResults
|
|
30
|
+
]);
|
|
24
31
|
return /*#__PURE__*/ _jsx(CardHeader, {
|
|
25
32
|
id: id,
|
|
26
33
|
component: "header",
|
|
@@ -49,10 +56,11 @@ export function PanelHeader({ id, title: rawTitle, description: rawDescription,
|
|
|
49
56
|
description: description,
|
|
50
57
|
descriptionTooltipId: descriptionTooltipId,
|
|
51
58
|
links: links,
|
|
52
|
-
queryResults: queryResults,
|
|
53
59
|
readHandlers: readHandlers,
|
|
54
60
|
editHandlers: editHandlers,
|
|
55
|
-
extra: extra
|
|
61
|
+
extra: extra,
|
|
62
|
+
panelContentProps: panelContentProps,
|
|
63
|
+
pluginActions: pluginActions
|
|
56
64
|
})
|
|
57
65
|
]
|
|
58
66
|
}),
|
|
@@ -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
|
|
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, useMemo } 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 // Create the panelContentProps object with only queryResults\n const panelContentProps = useMemo(\n () => ({\n queryResults,\n }),\n [queryResults]\n );\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 readHandlers={readHandlers}\n editHandlers={editHandlers}\n extra={extra}\n panelContentProps={panelContentProps}\n pluginActions={pluginActions}\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","pluginActions","rest","titleElementId","descriptionTooltipId","panelContentProps","component","aria-labelledby","aria-describedby","disableTypography","direction","variant","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,QAAQ,gBAAgB;AAC/E,SAASC,SAAS,QAAQ,yBAAyB;AAEnD,SAAoBC,2BAA2B,QAAQ,4BAA4B;AACnF,SAAkCC,OAAO,QAAQ,QAAQ;AACzD,SAASC,6BAA6B,QAAQ,kBAAkB;AAChE,SAASC,YAAY,QAA2B,iBAAiB;AAgBjE,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,EACb,GAAGC,MACc;IACjB,MAAMC,iBAAiB,GAAGb,GAAG,MAAM,CAAC;IACpC,MAAMc,uBAAuB,GAAGd,GAAG,YAAY,CAAC;IAEhD,MAAMC,QAAQN,4BAA4BO;IAC1C,MAAMC,cAAcR,4BAA4BS;IAEhD,6DAA6D;IAC7D,MAAMW,oBAAoBnB,QACxB,IAAO,CAAA;YACLU;QACF,CAAA,GACA;QAACA;KAAa;IAGhB,qBACE,KAACf;QACCS,IAAIA;QACJgB,WAAU;QACVC,mBAAiBJ;QACjBK,oBAAkBJ;QAClBK,iBAAiB;QACjBlB,qBACE,MAACT;YAAM4B,WAAU;;8BACf,KAAC3B;oBACCO,IAAIa;oBACJQ,SAAQ;oBACRZ,IAAI;wBACF,gEAAgE;wBAChE,+CAA+C;wBAC/Ca,YAAY;wBACZC,WAAW;wBACXC,YAAY;wBACZC,UAAU;wBACVC,cAAc;oBAChB;8BAECzB;;8BAEH,KAACH;oBACCG,OAAOA;oBACPE,aAAaA;oBACbW,sBAAsBA;oBACtBT,OAAOA;oBACPE,cAAcA;oBACdC,cAAcA;oBACdE,OAAOA;oBACPK,mBAAmBA;oBACnBJ,eAAeA;;;;QAIrBF,IAAIf,UACF,CAACiC,QAAW,CAAA;gBACVC,eAAe;gBACfC,eAAehC;gBACfiC,SAASH,MAAMI,OAAO,CAAC;gBACvBC,cAAc,CAAC,UAAU,EAAEL,MAAMM,OAAO,CAACC,OAAO,EAAE;gBAClD,0BAA0B;oBACxBT,UAAU;gBACZ;YACF,CAAA,GACAhB;QAED,GAAGG,IAAI;;AAGd"}
|
package/dist/components/SaveChangesConfirmationDialog/SaveChangesConfirmationDialog.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SaveChangesConfirmationDialog.d.ts","sourceRoot":"","sources":["../../../src/components/SaveChangesConfirmationDialog/SaveChangesConfirmationDialog.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAE,YAAY,EAAY,MAAM,OAAO,CAAC;AAO/C,eAAO,MAAM,6BAA6B,QAAO,
|
|
1
|
+
{"version":3,"file":"SaveChangesConfirmationDialog.d.ts","sourceRoot":"","sources":["../../../src/components/SaveChangesConfirmationDialog/SaveChangesConfirmationDialog.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAE,YAAY,EAAY,MAAM,OAAO,CAAC;AAO/C,eAAO,MAAM,6BAA6B,QAAO,YAqEhD,CAAC"}
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
14
14
|
import { useState } from 'react';
|
|
15
15
|
import { Checkbox, FormGroup, FormControlLabel, Typography } from '@mui/material';
|
|
16
|
-
import { useTimeRange
|
|
16
|
+
import { useTimeRange } from '@perses-dev/plugin-system';
|
|
17
17
|
import { isRelativeTimeRange, SAVE_DEFAULTS_DIALOG_TEXT } from '@perses-dev/core';
|
|
18
18
|
import { Dialog } from '@perses-dev/components';
|
|
19
19
|
import { useSaveChangesConfirmationDialog, useVariableDefinitionActions } from '../../context';
|
|
@@ -21,11 +21,8 @@ export const SaveChangesConfirmationDialog = ()=>{
|
|
|
21
21
|
const { saveChangesConfirmationDialog: dialog } = useSaveChangesConfirmationDialog();
|
|
22
22
|
const isSavedDurationModified = dialog?.isSavedDurationModified ?? true;
|
|
23
23
|
const isSavedVariableModified = dialog?.isSavedVariableModified ?? true;
|
|
24
|
-
const isSavedTimeZoneModified = dialog?.isSavedTimeZoneModified ?? true;
|
|
25
24
|
const [saveDefaultTimeRange, setSaveDefaultTimeRange] = useState(isSavedDurationModified);
|
|
26
25
|
const [saveDefaultVariables, setSaveDefaultVariables] = useState(isSavedVariableModified);
|
|
27
|
-
const [saveDefaultTimeZone, setSaveDefaultTimeZone] = useState(isSavedTimeZoneModified);
|
|
28
|
-
const { timeZone } = useTimeZone();
|
|
29
26
|
const { getSavedVariablesStatus } = useVariableDefinitionActions();
|
|
30
27
|
const { modifiedVariableNames } = getSavedVariablesStatus();
|
|
31
28
|
const isOpen = dialog !== undefined;
|
|
@@ -33,7 +30,6 @@ export const SaveChangesConfirmationDialog = ()=>{
|
|
|
33
30
|
const currentTimeRangeText = isRelativeTimeRange(timeRange) ? `(Last ${timeRange.pastDuration})` : '(Absolute time ranges can not be saved)';
|
|
34
31
|
const saveTimeRangeText = `Save current time range as new default ${currentTimeRangeText}`;
|
|
35
32
|
const saveVariablesText = `Save current variable values as new default (${modifiedVariableNames.length > 0 ? modifiedVariableNames.join(', ') : 'No modified variables'})`;
|
|
36
|
-
const saveTimeZoneText = `Save time zone as "${timeZone}" time`;
|
|
37
33
|
return /*#__PURE__*/ _jsx(Dialog, {
|
|
38
34
|
open: isOpen,
|
|
39
35
|
children: dialog !== undefined && /*#__PURE__*/ _jsxs(_Fragment, {
|
|
@@ -65,14 +61,6 @@ export const SaveChangesConfirmationDialog = ()=>{
|
|
|
65
61
|
onChange: (e)=>setSaveDefaultVariables(e.target.checked)
|
|
66
62
|
}),
|
|
67
63
|
label: saveVariablesText
|
|
68
|
-
}),
|
|
69
|
-
/*#__PURE__*/ _jsx(FormControlLabel, {
|
|
70
|
-
control: /*#__PURE__*/ _jsx(Checkbox, {
|
|
71
|
-
disabled: !isSavedTimeZoneModified,
|
|
72
|
-
checked: saveDefaultTimeZone && isSavedTimeZoneModified,
|
|
73
|
-
onChange: (e)=>setSaveDefaultTimeZone(e.target.checked)
|
|
74
|
-
}),
|
|
75
|
-
label: saveTimeZoneText
|
|
76
64
|
})
|
|
77
65
|
]
|
|
78
66
|
})
|
|
@@ -82,7 +70,7 @@ export const SaveChangesConfirmationDialog = ()=>{
|
|
|
82
70
|
children: [
|
|
83
71
|
/*#__PURE__*/ _jsx(Dialog.PrimaryButton, {
|
|
84
72
|
onClick: ()=>{
|
|
85
|
-
return dialog.onSaveChanges(saveDefaultTimeRange, saveDefaultVariables
|
|
73
|
+
return dialog.onSaveChanges(saveDefaultTimeRange, saveDefaultVariables);
|
|
86
74
|
},
|
|
87
75
|
children: "Save Changes"
|
|
88
76
|
}),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/SaveChangesConfirmationDialog/SaveChangesConfirmationDialog.tsx"],"sourcesContent":["// Copyright 2024 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 { Checkbox, FormGroup, FormControlLabel, Typography } from '@mui/material';\nimport { useTimeRange
|
|
1
|
+
{"version":3,"sources":["../../../src/components/SaveChangesConfirmationDialog/SaveChangesConfirmationDialog.tsx"],"sourcesContent":["// Copyright 2024 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 { Checkbox, FormGroup, FormControlLabel, Typography } from '@mui/material';\nimport { useTimeRange } from '@perses-dev/plugin-system';\nimport { isRelativeTimeRange, SAVE_DEFAULTS_DIALOG_TEXT } from '@perses-dev/core';\nimport { Dialog } from '@perses-dev/components';\nimport { useSaveChangesConfirmationDialog, useVariableDefinitionActions } from '../../context';\n\nexport const SaveChangesConfirmationDialog = (): ReactElement => {\n const { saveChangesConfirmationDialog: dialog } = useSaveChangesConfirmationDialog();\n const isSavedDurationModified = dialog?.isSavedDurationModified ?? true;\n const isSavedVariableModified = dialog?.isSavedVariableModified ?? true;\n const [saveDefaultTimeRange, setSaveDefaultTimeRange] = useState(isSavedDurationModified);\n const [saveDefaultVariables, setSaveDefaultVariables] = useState(isSavedVariableModified);\n\n const { getSavedVariablesStatus } = useVariableDefinitionActions();\n const { modifiedVariableNames } = getSavedVariablesStatus();\n\n const isOpen = dialog !== undefined;\n\n const { timeRange } = useTimeRange();\n const currentTimeRangeText = isRelativeTimeRange(timeRange)\n ? `(Last ${timeRange.pastDuration})`\n : '(Absolute time ranges can not be saved)';\n\n const saveTimeRangeText = `Save current time range as new default ${currentTimeRangeText}`;\n\n const saveVariablesText = `Save current variable values as new default (${\n modifiedVariableNames.length > 0 ? modifiedVariableNames.join(', ') : 'No modified variables'\n })`;\n\n return (\n <Dialog open={isOpen}>\n {dialog !== undefined && (\n <>\n <Dialog.Header onClose={() => dialog.onCancel()}>Save Dashboard</Dialog.Header>\n\n <Dialog.Content>\n <Typography marginBottom={2}>{dialog.description || SAVE_DEFAULTS_DIALOG_TEXT}</Typography>\n <FormGroup>\n <FormControlLabel\n control={\n <Checkbox\n disabled={!isSavedDurationModified || !isRelativeTimeRange(timeRange)}\n checked={saveDefaultTimeRange && isSavedDurationModified && isRelativeTimeRange(timeRange)}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => setSaveDefaultTimeRange(e.target.checked)}\n />\n }\n label={saveTimeRangeText}\n />\n <FormControlLabel\n control={\n <Checkbox\n disabled={!isSavedVariableModified}\n checked={saveDefaultVariables && isSavedVariableModified}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => setSaveDefaultVariables(e.target.checked)}\n />\n }\n label={saveVariablesText}\n />\n </FormGroup>\n </Dialog.Content>\n\n <Dialog.Actions>\n <Dialog.PrimaryButton\n onClick={() => {\n return dialog.onSaveChanges(saveDefaultTimeRange, saveDefaultVariables);\n }}\n >\n Save Changes\n </Dialog.PrimaryButton>\n <Dialog.SecondaryButton onClick={() => dialog.onCancel()}>Cancel</Dialog.SecondaryButton>\n </Dialog.Actions>\n </>\n )}\n </Dialog>\n );\n};\n"],"names":["useState","Checkbox","FormGroup","FormControlLabel","Typography","useTimeRange","isRelativeTimeRange","SAVE_DEFAULTS_DIALOG_TEXT","Dialog","useSaveChangesConfirmationDialog","useVariableDefinitionActions","SaveChangesConfirmationDialog","saveChangesConfirmationDialog","dialog","isSavedDurationModified","isSavedVariableModified","saveDefaultTimeRange","setSaveDefaultTimeRange","saveDefaultVariables","setSaveDefaultVariables","getSavedVariablesStatus","modifiedVariableNames","isOpen","undefined","timeRange","currentTimeRangeText","pastDuration","saveTimeRangeText","saveVariablesText","length","join","open","Header","onClose","onCancel","Content","marginBottom","description","control","disabled","checked","onChange","e","target","label","Actions","PrimaryButton","onClick","onSaveChanges","SecondaryButton"],"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,QAAQ,QAAQ,QAAQ;AAC/C,SAASC,QAAQ,EAAEC,SAAS,EAAEC,gBAAgB,EAAEC,UAAU,QAAQ,gBAAgB;AAClF,SAASC,YAAY,QAAQ,4BAA4B;AACzD,SAASC,mBAAmB,EAAEC,yBAAyB,QAAQ,mBAAmB;AAClF,SAASC,MAAM,QAAQ,yBAAyB;AAChD,SAASC,gCAAgC,EAAEC,4BAA4B,QAAQ,gBAAgB;AAE/F,OAAO,MAAMC,gCAAgC;IAC3C,MAAM,EAAEC,+BAA+BC,MAAM,EAAE,GAAGJ;IAClD,MAAMK,0BAA0BD,QAAQC,2BAA2B;IACnE,MAAMC,0BAA0BF,QAAQE,2BAA2B;IACnE,MAAM,CAACC,sBAAsBC,wBAAwB,GAAGjB,SAASc;IACjE,MAAM,CAACI,sBAAsBC,wBAAwB,GAAGnB,SAASe;IAEjE,MAAM,EAAEK,uBAAuB,EAAE,GAAGV;IACpC,MAAM,EAAEW,qBAAqB,EAAE,GAAGD;IAElC,MAAME,SAAST,WAAWU;IAE1B,MAAM,EAAEC,SAAS,EAAE,GAAGnB;IACtB,MAAMoB,uBAAuBnB,oBAAoBkB,aAC7C,CAAC,MAAM,EAAEA,UAAUE,YAAY,CAAC,CAAC,CAAC,GAClC;IAEJ,MAAMC,oBAAoB,CAAC,uCAAuC,EAAEF,sBAAsB;IAE1F,MAAMG,oBAAoB,CAAC,6CAA6C,EACtEP,sBAAsBQ,MAAM,GAAG,IAAIR,sBAAsBS,IAAI,CAAC,QAAQ,wBACvE,CAAC,CAAC;IAEH,qBACE,KAACtB;QAAOuB,MAAMT;kBACXT,WAAWU,2BACV;;8BACE,KAACf,OAAOwB,MAAM;oBAACC,SAAS,IAAMpB,OAAOqB,QAAQ;8BAAI;;8BAEjD,MAAC1B,OAAO2B,OAAO;;sCACb,KAAC/B;4BAAWgC,cAAc;sCAAIvB,OAAOwB,WAAW,IAAI9B;;sCACpD,MAACL;;8CACC,KAACC;oCACCmC,uBACE,KAACrC;wCACCsC,UAAU,CAACzB,2BAA2B,CAACR,oBAAoBkB;wCAC3DgB,SAASxB,wBAAwBF,2BAA2BR,oBAAoBkB;wCAChFiB,UAAU,CAACC,IAA2CzB,wBAAwByB,EAAEC,MAAM,CAACH,OAAO;;oCAGlGI,OAAOjB;;8CAET,KAACxB;oCACCmC,uBACE,KAACrC;wCACCsC,UAAU,CAACxB;wCACXyB,SAAStB,wBAAwBH;wCACjC0B,UAAU,CAACC,IAA2CvB,wBAAwBuB,EAAEC,MAAM,CAACH,OAAO;;oCAGlGI,OAAOhB;;;;;;8BAKb,MAACpB,OAAOqC,OAAO;;sCACb,KAACrC,OAAOsC,aAAa;4BACnBC,SAAS;gCACP,OAAOlC,OAAOmC,aAAa,CAAChC,sBAAsBE;4BACpD;sCACD;;sCAGD,KAACV,OAAOyC,eAAe;4BAACF,SAAS,IAAMlC,OAAOqB,QAAQ;sCAAI;;;;;;;AAMtE,EAAE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SaveDashboardButton.d.ts","sourceRoot":"","sources":["../../../src/components/SaveDashboardButton/SaveDashboardButton.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAE,YAAY,EAAY,MAAM,OAAO,CAAC;AAC/C,OAAO,EAAU,WAAW,EAAE,MAAM,eAAe,CAAC;AAGpD,OAAO,EACL,eAAe,EAKhB,MAAM,eAAe,CAAC;AAEvB,MAAM,WAAW,wBAAyB,SAAQ,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC;IAC9E,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,UAAU,CAAC;CAC7C;AAED,eAAO,MAAM,mBAAmB,qCAI7B,wBAAwB,KAAG,
|
|
1
|
+
{"version":3,"file":"SaveDashboardButton.d.ts","sourceRoot":"","sources":["../../../src/components/SaveDashboardButton/SaveDashboardButton.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAE,YAAY,EAAY,MAAM,OAAO,CAAC;AAC/C,OAAO,EAAU,WAAW,EAAE,MAAM,eAAe,CAAC;AAGpD,OAAO,EACL,eAAe,EAKhB,MAAM,eAAe,CAAC;AAEvB,MAAM,WAAW,wBAAyB,SAAQ,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC;IAC9E,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,UAAU,CAAC;CAC7C;AAED,eAAO,MAAM,mBAAmB,qCAI7B,wBAAwB,KAAG,YA8D7B,CAAC"}
|