@perses-dev/dashboards 0.0.0-snapshot-panel-actions-520389b → 0.0.0-snapshot-ts-panel-actions-90e9ef0
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/DownloadButton/DownloadButton.js +3 -33
- package/dist/cjs/components/DownloadButton/serializeDashboard.js +64 -0
- package/dist/cjs/components/Panel/Panel.js +3 -61
- package/dist/cjs/components/Panel/PanelActions.js +16 -86
- package/dist/cjs/components/Panel/PanelHeader.js +3 -47
- 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 +0 -5
- package/dist/components/Panel/Panel.d.ts.map +1 -1
- package/dist/components/Panel/Panel.js +3 -61
- package/dist/components/Panel/Panel.js.map +1 -1
- package/dist/components/Panel/PanelActions.d.ts +3 -5
- package/dist/components/Panel/PanelActions.d.ts.map +1 -1
- package/dist/components/Panel/PanelActions.js +17 -87
- package/dist/components/Panel/PanelActions.js.map +1 -1
- package/dist/components/Panel/PanelHeader.d.ts +1 -5
- package/dist/components/Panel/PanelHeader.d.ts.map +1 -1
- package/dist/components/Panel/PanelHeader.js +3 -47
- package/dist/components/Panel/PanelHeader.js.map +1 -1
- package/package.json +5 -5
|
@@ -25,8 +25,8 @@ const _material = require("@mui/material");
|
|
|
25
25
|
const _components = require("@perses-dev/components");
|
|
26
26
|
const _DownloadOutline = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/DownloadOutline"));
|
|
27
27
|
const _react = /*#__PURE__*/ _interop_require_wildcard(require("react"));
|
|
28
|
-
const _yaml = require("yaml");
|
|
29
28
|
const _context = require("../../context");
|
|
29
|
+
const _serializeDashboard = require("./serializeDashboard");
|
|
30
30
|
function _interop_require_default(obj) {
|
|
31
31
|
return obj && obj.__esModule ? obj : {
|
|
32
32
|
default: obj
|
|
@@ -83,43 +83,13 @@ function DownloadButton() {
|
|
|
83
83
|
};
|
|
84
84
|
const handleItemClick = (format, shape)=>()=>{
|
|
85
85
|
setAnchorEl(null);
|
|
86
|
-
|
|
87
|
-
switch(format){
|
|
88
|
-
case 'json':
|
|
89
|
-
type = 'application/json';
|
|
90
|
-
content = JSON.stringify(dashboard, null, 2);
|
|
91
|
-
break;
|
|
92
|
-
case 'yaml':
|
|
93
|
-
{
|
|
94
|
-
type = 'application/yaml';
|
|
95
|
-
if (shape === 'cr') {
|
|
96
|
-
const name = dashboard.metadata.name.toLowerCase().replace(/[^a-z0-9-]/g, '-');
|
|
97
|
-
content = (0, _yaml.stringify)({
|
|
98
|
-
apiVersion: 'perses.dev/v1alpha1',
|
|
99
|
-
kind: 'PersesDashboard',
|
|
100
|
-
metadata: {
|
|
101
|
-
labels: {
|
|
102
|
-
'app.kubernetes.io/name': 'perses-dashboard',
|
|
103
|
-
'app.kubernetes.io/instance': name,
|
|
104
|
-
'app.kubernetes.io/part-of': 'perses-operator'
|
|
105
|
-
},
|
|
106
|
-
name
|
|
107
|
-
},
|
|
108
|
-
namespace: dashboard.metadata.project,
|
|
109
|
-
spec: dashboard.spec
|
|
110
|
-
});
|
|
111
|
-
} else {
|
|
112
|
-
content = (0, _yaml.stringify)(dashboard);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
break;
|
|
116
|
-
}
|
|
86
|
+
const { contentType, content } = (0, _serializeDashboard.serializeDashboard)(dashboard, format, shape);
|
|
117
87
|
if (!hiddenLinkRef || !hiddenLinkRef.current) return;
|
|
118
88
|
// Create blob URL
|
|
119
89
|
const hiddenLinkUrl = URL.createObjectURL(new Blob([
|
|
120
90
|
content
|
|
121
91
|
], {
|
|
122
|
-
type
|
|
92
|
+
type: contentType
|
|
123
93
|
}));
|
|
124
94
|
// Simulate click
|
|
125
95
|
hiddenLinkRef.current.download = `${dashboard.metadata.name}${shape === 'cr' ? '-cr' : ''}.${format}`;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// Copyright 2023 The Perses Authors
|
|
2
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
+
// you may not use this file except in compliance with the License.
|
|
4
|
+
// You may obtain a copy of the License at
|
|
5
|
+
//
|
|
6
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
//
|
|
8
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
+
// See the License for the specific language governing permissions and
|
|
12
|
+
// limitations under the License.
|
|
13
|
+
"use strict";
|
|
14
|
+
Object.defineProperty(exports, "__esModule", {
|
|
15
|
+
value: true
|
|
16
|
+
});
|
|
17
|
+
Object.defineProperty(exports, "serializeDashboard", {
|
|
18
|
+
enumerable: true,
|
|
19
|
+
get: function() {
|
|
20
|
+
return serializeDashboard;
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
const _yaml = require("yaml");
|
|
24
|
+
function serializeYaml(dashboard, shape) {
|
|
25
|
+
let content;
|
|
26
|
+
if (shape === 'cr') {
|
|
27
|
+
const name = dashboard.metadata.name.toLowerCase().replace(/[^a-z0-9-]/g, '-');
|
|
28
|
+
content = (0, _yaml.stringify)({
|
|
29
|
+
apiVersion: 'perses.dev/v1alpha1',
|
|
30
|
+
kind: 'PersesDashboard',
|
|
31
|
+
metadata: {
|
|
32
|
+
labels: {
|
|
33
|
+
'app.kubernetes.io/name': 'perses-dashboard',
|
|
34
|
+
'app.kubernetes.io/instance': name,
|
|
35
|
+
'app.kubernetes.io/part-of': 'perses-operator'
|
|
36
|
+
},
|
|
37
|
+
name,
|
|
38
|
+
namespace: dashboard.metadata.project
|
|
39
|
+
},
|
|
40
|
+
spec: dashboard.spec
|
|
41
|
+
}, {
|
|
42
|
+
schema: 'yaml-1.1'
|
|
43
|
+
});
|
|
44
|
+
} else {
|
|
45
|
+
content = (0, _yaml.stringify)(dashboard, {
|
|
46
|
+
schema: 'yaml-1.1'
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
contentType: 'application/yaml',
|
|
51
|
+
content
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function serializeDashboard(dashboard, format, shape) {
|
|
55
|
+
switch(format){
|
|
56
|
+
case 'json':
|
|
57
|
+
return {
|
|
58
|
+
contentType: 'application/json',
|
|
59
|
+
content: JSON.stringify(dashboard, null, 2)
|
|
60
|
+
};
|
|
61
|
+
case 'yaml':
|
|
62
|
+
return serializeYaml(dashboard, shape);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -33,41 +33,8 @@ function _interop_require_default(obj) {
|
|
|
33
33
|
default: obj
|
|
34
34
|
};
|
|
35
35
|
}
|
|
36
|
-
// Function to extract project name from URL (kept as fallback)
|
|
37
|
-
const extractProjectNameFromUrl = ()=>{
|
|
38
|
-
try {
|
|
39
|
-
if (process.env.NODE_ENV === 'test') {
|
|
40
|
-
return 'test-project';
|
|
41
|
-
}
|
|
42
|
-
if (typeof window !== 'undefined' && (window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1')) {
|
|
43
|
-
const urlPath = window.location.pathname;
|
|
44
|
-
if (urlPath === '/' || urlPath === '') {
|
|
45
|
-
return 'dev-project';
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
const urlPath = window.location.pathname;
|
|
49
|
-
// Split the path and look for the project name after "/projects/"
|
|
50
|
-
const pathSegments = urlPath.split('/').filter((segment)=>segment.length > 0);
|
|
51
|
-
const projectsIndex = pathSegments.findIndex((segment)=>segment === 'projects');
|
|
52
|
-
if (projectsIndex !== -1 && projectsIndex + 1 < pathSegments.length) {
|
|
53
|
-
const projectName = pathSegments[projectsIndex + 1];
|
|
54
|
-
if (projectName && projectName.trim().length > 0) {
|
|
55
|
-
return projectName;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
// Fallback: try to extract from URL parameters
|
|
59
|
-
const urlParams = new URLSearchParams(window.location.search);
|
|
60
|
-
const projectParam = urlParams.get('project');
|
|
61
|
-
if (projectParam && projectParam.trim().length > 0) {
|
|
62
|
-
return projectParam;
|
|
63
|
-
}
|
|
64
|
-
return 'unknown-project';
|
|
65
|
-
} catch {
|
|
66
|
-
return 'unknown-project';
|
|
67
|
-
}
|
|
68
|
-
};
|
|
69
36
|
const Panel = /*#__PURE__*/ (0, _react.memo)(function Panel(props) {
|
|
70
|
-
const { definition, readHandlers, editHandlers, onMouseEnter, onMouseLeave, sx, panelOptions, panelGroupItemId,
|
|
37
|
+
const { definition, readHandlers, editHandlers, onMouseEnter, onMouseLeave, sx, panelOptions, panelGroupItemId, ...others } = props;
|
|
71
38
|
// Make sure we have an ID we can use for aria attributes
|
|
72
39
|
const generatedPanelId = (0, _components.useId)('Panel');
|
|
73
40
|
const headerId = `${generatedPanelId}-header`;
|
|
@@ -87,29 +54,6 @@ const Panel = /*#__PURE__*/ (0, _react.memo)(function Panel(props) {
|
|
|
87
54
|
]);
|
|
88
55
|
const chartsTheme = (0, _components.useChartsTheme)();
|
|
89
56
|
const { queryResults } = (0, _pluginsystem.useDataQueriesContext)();
|
|
90
|
-
// Use provided project name or extract from URL as fallback
|
|
91
|
-
const projectName = (0, _react.useMemo)(()=>{
|
|
92
|
-
return providedProjectName || extractProjectNameFromUrl();
|
|
93
|
-
}, [
|
|
94
|
-
providedProjectName
|
|
95
|
-
]);
|
|
96
|
-
const panelPropsForActions = (0, _react.useMemo)(()=>{
|
|
97
|
-
return {
|
|
98
|
-
spec: definition.spec.plugin.spec,
|
|
99
|
-
queryResults: queryResults.map((query)=>({
|
|
100
|
-
definition: query.definition,
|
|
101
|
-
data: query.data
|
|
102
|
-
})),
|
|
103
|
-
contentDimensions,
|
|
104
|
-
definition,
|
|
105
|
-
projectName
|
|
106
|
-
};
|
|
107
|
-
}, [
|
|
108
|
-
definition,
|
|
109
|
-
contentDimensions,
|
|
110
|
-
queryResults,
|
|
111
|
-
projectName
|
|
112
|
-
]);
|
|
113
57
|
const handleMouseEnter = (e)=>{
|
|
114
58
|
onMouseEnter?.(e);
|
|
115
59
|
};
|
|
@@ -144,12 +88,9 @@ const Panel = /*#__PURE__*/ (0, _react.memo)(function Panel(props) {
|
|
|
144
88
|
title: definition.spec.display.name,
|
|
145
89
|
description: definition.spec.display.description,
|
|
146
90
|
queryResults: queryResults,
|
|
147
|
-
panelPluginKind: definition.spec.plugin.kind,
|
|
148
91
|
readHandlers: readHandlers,
|
|
149
92
|
editHandlers: editHandlers,
|
|
150
93
|
links: definition.spec.links,
|
|
151
|
-
projectName: projectName,
|
|
152
|
-
panelProps: panelPropsForActions,
|
|
153
94
|
sx: {
|
|
154
95
|
paddingX: `${chartsTheme.container.padding.default}px`
|
|
155
96
|
}
|
|
@@ -171,7 +112,8 @@ const Panel = /*#__PURE__*/ (0, _react.memo)(function Panel(props) {
|
|
|
171
112
|
children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.ErrorBoundary, {
|
|
172
113
|
FallbackComponent: _components.ErrorAlert,
|
|
173
114
|
resetKeys: [
|
|
174
|
-
definition.spec
|
|
115
|
+
definition.spec,
|
|
116
|
+
queryResults
|
|
175
117
|
],
|
|
176
118
|
children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_PanelContent.PanelContent, {
|
|
177
119
|
definition: definition,
|
|
@@ -24,7 +24,6 @@ const _jsxruntime = require("react/jsx-runtime");
|
|
|
24
24
|
const _material = require("@mui/material");
|
|
25
25
|
const _react = require("react");
|
|
26
26
|
const _components = require("@perses-dev/components");
|
|
27
|
-
const _pluginsystem = require("@perses-dev/plugin-system");
|
|
28
27
|
const _ArrowCollapse = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/ArrowCollapse"));
|
|
29
28
|
const _ArrowExpand = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/ArrowExpand"));
|
|
30
29
|
const _PencilOutline = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/PencilOutline"));
|
|
@@ -48,72 +47,7 @@ const ConditionalBox = (0, _material.styled)(_material.Box)({
|
|
|
48
47
|
flexGrow: 1,
|
|
49
48
|
justifyContent: 'flex-end'
|
|
50
49
|
});
|
|
51
|
-
const PanelActions = ({ editHandlers, readHandlers, extra, title, description, descriptionTooltipId, links, queryResults
|
|
52
|
-
const { isFetching, errors } = (0, _pluginsystem.useDataQueriesContext)();
|
|
53
|
-
const { getPlugin } = (0, _pluginsystem.usePluginRegistry)();
|
|
54
|
-
const [pluginActions, setPluginActions] = (0, _react.useState)([]);
|
|
55
|
-
(0, _react.useEffect)(()=>{
|
|
56
|
-
let cancelled = false;
|
|
57
|
-
const loadPluginActions = async ()=>{
|
|
58
|
-
if (!panelPluginKind || !panelProps) {
|
|
59
|
-
if (!cancelled) {
|
|
60
|
-
setPluginActions([]);
|
|
61
|
-
}
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
try {
|
|
65
|
-
// Add defensive check for getPlugin availability
|
|
66
|
-
if (!getPlugin || typeof getPlugin !== 'function') {
|
|
67
|
-
if (!cancelled) {
|
|
68
|
-
setPluginActions([]);
|
|
69
|
-
}
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
const plugin = await getPlugin('Panel', panelPluginKind);
|
|
73
|
-
if (cancelled) return;
|
|
74
|
-
// More defensive checking for plugin and actions
|
|
75
|
-
if (!plugin || typeof plugin !== 'object' || !plugin.actions || !Array.isArray(plugin.actions) || plugin.actions.length === 0) {
|
|
76
|
-
if (!cancelled) {
|
|
77
|
-
setPluginActions([]);
|
|
78
|
-
}
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
// Render plugin actions in header location
|
|
82
|
-
const headerActions = plugin.actions.filter((action)=>!action.location || action.location === 'header').map((action, index)=>{
|
|
83
|
-
const ActionComponent = action.component;
|
|
84
|
-
try {
|
|
85
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
86
|
-
return /*#__PURE__*/ (0, _jsxruntime.jsx)(ActionComponent, {
|
|
87
|
-
...panelProps
|
|
88
|
-
}, `plugin-action-${index}`);
|
|
89
|
-
} catch (error) {
|
|
90
|
-
console.warn(`Failed to render plugin action ${index}:`, error);
|
|
91
|
-
return null;
|
|
92
|
-
}
|
|
93
|
-
}).filter((item)=>Boolean(item));
|
|
94
|
-
if (!cancelled) {
|
|
95
|
-
setPluginActions(headerActions);
|
|
96
|
-
}
|
|
97
|
-
} catch (error) {
|
|
98
|
-
if (!cancelled) {
|
|
99
|
-
console.warn('Failed to load plugin actions:', error);
|
|
100
|
-
setPluginActions([]);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
};
|
|
104
|
-
// Use setTimeout to defer the async operation to the next tick
|
|
105
|
-
const timeoutId = setTimeout(()=>{
|
|
106
|
-
loadPluginActions();
|
|
107
|
-
}, 0);
|
|
108
|
-
return ()=>{
|
|
109
|
-
cancelled = true;
|
|
110
|
-
clearTimeout(timeoutId);
|
|
111
|
-
};
|
|
112
|
-
}, [
|
|
113
|
-
panelPluginKind,
|
|
114
|
-
panelProps,
|
|
115
|
-
getPlugin
|
|
116
|
-
]);
|
|
50
|
+
const PanelActions = ({ editHandlers, readHandlers, extra, title, description, descriptionTooltipId, links, queryResults })=>{
|
|
117
51
|
const descriptionAction = (0, _react.useMemo)(()=>{
|
|
118
52
|
if (description && description.trim().length > 0) {
|
|
119
53
|
return /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.InfoTooltip, {
|
|
@@ -144,23 +78,19 @@ const PanelActions = ({ editHandlers, readHandlers, extra, title, description, d
|
|
|
144
78
|
});
|
|
145
79
|
const extraActions = editHandlers === undefined && extra;
|
|
146
80
|
const queryStateIndicator = (0, _react.useMemo)(()=>{
|
|
147
|
-
const hasData = queryResults
|
|
81
|
+
const hasData = queryResults.some((q)=>q.data);
|
|
82
|
+
const isFetching = queryResults.some((q)=>q.isFetching);
|
|
83
|
+
const queryErrors = queryResults.filter((q)=>q.error);
|
|
148
84
|
if (isFetching && hasData) {
|
|
85
|
+
// If the panel has no data, the panel content will show the loading overlay.
|
|
86
|
+
// Therefore, show the circular loading indicator only in case the panel doesn't display the loading overlay already.
|
|
149
87
|
return /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.CircularProgress, {
|
|
150
88
|
"aria-label": "loading",
|
|
151
89
|
size: "1.125rem"
|
|
152
90
|
});
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
const errorTexts = validErrors.map((e)=>{
|
|
157
|
-
if (typeof e === 'string') return e;
|
|
158
|
-
if (e && typeof e === 'object') {
|
|
159
|
-
const errorObj = e;
|
|
160
|
-
return errorObj.message ?? errorObj.toString?.() ?? 'Unknown error';
|
|
161
|
-
}
|
|
162
|
-
return 'Unknown error';
|
|
163
|
-
}).join('\n');
|
|
91
|
+
} else if (queryErrors.length > 0) {
|
|
92
|
+
const errorTexts = queryErrors.map((q)=>q.error).map((e)=>e?.message ?? e?.toString() ?? 'Unknown error') // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
93
|
+
.join('\n');
|
|
164
94
|
return /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.InfoTooltip, {
|
|
165
95
|
description: errorTexts,
|
|
166
96
|
children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_HeaderIconButton.HeaderIconButton, {
|
|
@@ -173,9 +103,7 @@ const PanelActions = ({ editHandlers, readHandlers, extra, title, description, d
|
|
|
173
103
|
});
|
|
174
104
|
}
|
|
175
105
|
}, [
|
|
176
|
-
queryResults
|
|
177
|
-
isFetching,
|
|
178
|
-
errors
|
|
106
|
+
queryResults
|
|
179
107
|
]);
|
|
180
108
|
const readActions = (0, _react.useMemo)(()=>{
|
|
181
109
|
if (readHandlers !== undefined) {
|
|
@@ -200,6 +128,7 @@ const PanelActions = ({ editHandlers, readHandlers, extra, title, description, d
|
|
|
200
128
|
]);
|
|
201
129
|
const editActions = (0, _react.useMemo)(()=>{
|
|
202
130
|
if (editHandlers !== undefined) {
|
|
131
|
+
// If there are edit handlers, always just show the edit buttons
|
|
203
132
|
return /*#__PURE__*/ (0, _jsxruntime.jsxs)(_jsxruntime.Fragment, {
|
|
204
133
|
children: [
|
|
205
134
|
/*#__PURE__*/ (0, _jsxruntime.jsx)(_components.InfoTooltip, {
|
|
@@ -222,6 +151,8 @@ const PanelActions = ({ editHandlers, readHandlers, extra, title, description, d
|
|
|
222
151
|
children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_ContentCopy.default, {
|
|
223
152
|
fontSize: "inherit",
|
|
224
153
|
sx: {
|
|
154
|
+
// Shrink this icon a little bit to look more consistent
|
|
155
|
+
// with the other icons in the header.
|
|
225
156
|
transform: 'scale(0.925)'
|
|
226
157
|
}
|
|
227
158
|
})
|
|
@@ -311,7 +242,6 @@ const PanelActions = ({ editHandlers, readHandlers, extra, title, description, d
|
|
|
311
242
|
editActions
|
|
312
243
|
]
|
|
313
244
|
}),
|
|
314
|
-
pluginActions,
|
|
315
245
|
moveAction
|
|
316
246
|
]
|
|
317
247
|
})
|
|
@@ -339,7 +269,6 @@ const PanelActions = ({ editHandlers, readHandlers, extra, title, description, d
|
|
|
339
269
|
extraActions,
|
|
340
270
|
" ",
|
|
341
271
|
readActions,
|
|
342
|
-
pluginActions,
|
|
343
272
|
/*#__PURE__*/ (0, _jsxruntime.jsx)(OverflowMenu, {
|
|
344
273
|
title: title,
|
|
345
274
|
children: editActions
|
|
@@ -351,6 +280,7 @@ const PanelActions = ({ editHandlers, readHandlers, extra, title, description, d
|
|
|
351
280
|
}),
|
|
352
281
|
/*#__PURE__*/ (0, _jsxruntime.jsxs)(ConditionalBox, {
|
|
353
282
|
sx: (theme)=>({
|
|
283
|
+
// flip the logic here; if the browser (or jsdom) does not support container queries, always show all icons
|
|
354
284
|
display: 'flex',
|
|
355
285
|
[theme.containerQueries(_constants.HEADER_ACTIONS_CONTAINER_NAME).down(_constants.HEADER_MEDIUM_WIDTH)]: {
|
|
356
286
|
display: 'none'
|
|
@@ -372,7 +302,7 @@ const PanelActions = ({ editHandlers, readHandlers, extra, title, description, d
|
|
|
372
302
|
extraActions,
|
|
373
303
|
" ",
|
|
374
304
|
readActions,
|
|
375
|
-
|
|
305
|
+
" ",
|
|
376
306
|
editActions,
|
|
377
307
|
" ",
|
|
378
308
|
moveAction
|
|
@@ -385,7 +315,7 @@ const PanelActions = ({ editHandlers, readHandlers, extra, title, description, d
|
|
|
385
315
|
};
|
|
386
316
|
const OverflowMenu = ({ children, title })=>{
|
|
387
317
|
const [anchorPosition, setAnchorPosition] = (0, _react.useState)();
|
|
388
|
-
// do not show overflow menu if there is no content
|
|
318
|
+
// do not show overflow menu if there is no content (for example, edit actions are hidden)
|
|
389
319
|
const hasContent = /*#__PURE__*/ (0, _react.isValidElement)(children) || Array.isArray(children) && children.some(_react.isValidElement);
|
|
390
320
|
if (!hasContent) {
|
|
391
321
|
return undefined;
|
|
@@ -24,53 +24,13 @@ const _jsxruntime = require("react/jsx-runtime");
|
|
|
24
24
|
const _material = require("@mui/material");
|
|
25
25
|
const _components = require("@perses-dev/components");
|
|
26
26
|
const _pluginsystem = require("@perses-dev/plugin-system");
|
|
27
|
-
const _react = require("react");
|
|
28
27
|
const _constants = require("../../constants");
|
|
29
28
|
const _PanelActions = require("./PanelActions");
|
|
30
|
-
function PanelHeader({ id, title: rawTitle, description: rawDescription, links, queryResults, readHandlers, editHandlers, sx, extra,
|
|
29
|
+
function PanelHeader({ id, title: rawTitle, description: rawDescription, links, queryResults, readHandlers, editHandlers, sx, extra, ...rest }) {
|
|
31
30
|
const titleElementId = `${id}-title`;
|
|
32
31
|
const descriptionTooltipId = `${id}-description`;
|
|
33
32
|
const title = (0, _pluginsystem.useReplaceVariablesInString)(rawTitle);
|
|
34
33
|
const description = (0, _pluginsystem.useReplaceVariablesInString)(rawDescription);
|
|
35
|
-
const timeSeriesDataForExport = (0, _react.useMemo)(()=>{
|
|
36
|
-
// Collect all series from all queries
|
|
37
|
-
const allSeries = [];
|
|
38
|
-
let timeRange = undefined;
|
|
39
|
-
let stepMs = undefined;
|
|
40
|
-
let metadata = undefined;
|
|
41
|
-
queryResults.forEach((query)=>{
|
|
42
|
-
if (query.data && 'series' in query.data) {
|
|
43
|
-
const timeSeriesData = query.data;
|
|
44
|
-
// Collect series from this query
|
|
45
|
-
if (timeSeriesData.series && timeSeriesData.series.length > 0) {
|
|
46
|
-
allSeries.push(...timeSeriesData.series);
|
|
47
|
-
// Use the first query's metadata/timeRange/stepMs as the base
|
|
48
|
-
if (!timeRange && timeSeriesData.timeRange) {
|
|
49
|
-
timeRange = timeSeriesData.timeRange;
|
|
50
|
-
}
|
|
51
|
-
if (!stepMs && timeSeriesData.stepMs) {
|
|
52
|
-
stepMs = timeSeriesData.stepMs;
|
|
53
|
-
}
|
|
54
|
-
if (!metadata && timeSeriesData.metadata) {
|
|
55
|
-
metadata = timeSeriesData.metadata;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
// If we found series, create a combined TimeSeriesData object
|
|
61
|
-
if (allSeries.length > 0) {
|
|
62
|
-
const combinedData = {
|
|
63
|
-
series: allSeries,
|
|
64
|
-
timeRange,
|
|
65
|
-
stepMs,
|
|
66
|
-
metadata
|
|
67
|
-
};
|
|
68
|
-
return combinedData;
|
|
69
|
-
}
|
|
70
|
-
return undefined;
|
|
71
|
-
}, [
|
|
72
|
-
queryResults
|
|
73
|
-
]);
|
|
74
34
|
return /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.CardHeader, {
|
|
75
35
|
id: id,
|
|
76
36
|
component: "header",
|
|
@@ -99,14 +59,10 @@ function PanelHeader({ id, title: rawTitle, description: rawDescription, links,
|
|
|
99
59
|
description: description,
|
|
100
60
|
descriptionTooltipId: descriptionTooltipId,
|
|
101
61
|
links: links,
|
|
102
|
-
queryResults:
|
|
103
|
-
panelPluginKind: panelPluginKind,
|
|
62
|
+
queryResults: queryResults,
|
|
104
63
|
readHandlers: readHandlers,
|
|
105
64
|
editHandlers: editHandlers,
|
|
106
|
-
extra: extra
|
|
107
|
-
projectName: projectName,
|
|
108
|
-
// ========== ADDED: Pass panel props for actions ==========
|
|
109
|
-
panelProps: panelProps
|
|
65
|
+
extra: extra
|
|
110
66
|
})
|
|
111
67
|
]
|
|
112
68
|
}),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DownloadButton.d.ts","sourceRoot":"","sources":["../../../src/components/DownloadButton/DownloadButton.tsx"],"names":[],"mappings":"AAgBA,OAAc,EAAE,YAAY,EAAU,MAAM,OAAO,CAAC;AAKpD,wBAAgB,cAAc,IAAI,YAAY,
|
|
1
|
+
{"version":3,"file":"DownloadButton.d.ts","sourceRoot":"","sources":["../../../src/components/DownloadButton/DownloadButton.tsx"],"names":[],"mappings":"AAgBA,OAAc,EAAE,YAAY,EAAU,MAAM,OAAO,CAAC;AAKpD,wBAAgB,cAAc,IAAI,YAAY,CA+D7C"}
|
|
@@ -15,8 +15,8 @@ import { ClickAwayListener, Menu, MenuItem, MenuList } from '@mui/material';
|
|
|
15
15
|
import { ToolbarIconButton } from '@perses-dev/components';
|
|
16
16
|
import DownloadIcon from 'mdi-material-ui/DownloadOutline';
|
|
17
17
|
import React, { useRef } from 'react';
|
|
18
|
-
import { stringify } from 'yaml';
|
|
19
18
|
import { useDashboard } from '../../context';
|
|
19
|
+
import { serializeDashboard } from './serializeDashboard';
|
|
20
20
|
// Button that enables downloading the dashboard as a JSON file
|
|
21
21
|
export function DownloadButton() {
|
|
22
22
|
const { dashboard } = useDashboard();
|
|
@@ -28,43 +28,13 @@ export function DownloadButton() {
|
|
|
28
28
|
};
|
|
29
29
|
const handleItemClick = (format, shape)=>()=>{
|
|
30
30
|
setAnchorEl(null);
|
|
31
|
-
|
|
32
|
-
switch(format){
|
|
33
|
-
case 'json':
|
|
34
|
-
type = 'application/json';
|
|
35
|
-
content = JSON.stringify(dashboard, null, 2);
|
|
36
|
-
break;
|
|
37
|
-
case 'yaml':
|
|
38
|
-
{
|
|
39
|
-
type = 'application/yaml';
|
|
40
|
-
if (shape === 'cr') {
|
|
41
|
-
const name = dashboard.metadata.name.toLowerCase().replace(/[^a-z0-9-]/g, '-');
|
|
42
|
-
content = stringify({
|
|
43
|
-
apiVersion: 'perses.dev/v1alpha1',
|
|
44
|
-
kind: 'PersesDashboard',
|
|
45
|
-
metadata: {
|
|
46
|
-
labels: {
|
|
47
|
-
'app.kubernetes.io/name': 'perses-dashboard',
|
|
48
|
-
'app.kubernetes.io/instance': name,
|
|
49
|
-
'app.kubernetes.io/part-of': 'perses-operator'
|
|
50
|
-
},
|
|
51
|
-
name
|
|
52
|
-
},
|
|
53
|
-
namespace: dashboard.metadata.project,
|
|
54
|
-
spec: dashboard.spec
|
|
55
|
-
});
|
|
56
|
-
} else {
|
|
57
|
-
content = stringify(dashboard);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
break;
|
|
61
|
-
}
|
|
31
|
+
const { contentType, content } = serializeDashboard(dashboard, format, shape);
|
|
62
32
|
if (!hiddenLinkRef || !hiddenLinkRef.current) return;
|
|
63
33
|
// Create blob URL
|
|
64
34
|
const hiddenLinkUrl = URL.createObjectURL(new Blob([
|
|
65
35
|
content
|
|
66
36
|
], {
|
|
67
|
-
type
|
|
37
|
+
type: contentType
|
|
68
38
|
}));
|
|
69
39
|
// Simulate click
|
|
70
40
|
hiddenLinkRef.current.download = `${dashboard.metadata.name}${shape === 'cr' ? '-cr' : ''}.${format}`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/DownloadButton/DownloadButton.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 { ClickAwayListener, Menu, MenuItem, MenuList } from '@mui/material';\nimport { ToolbarIconButton } from '@perses-dev/components';\nimport DownloadIcon from 'mdi-material-ui/DownloadOutline';\nimport React, { ReactElement, useRef } from 'react';\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../src/components/DownloadButton/DownloadButton.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 { ClickAwayListener, Menu, MenuItem, MenuList } from '@mui/material';\nimport { ToolbarIconButton } from '@perses-dev/components';\nimport DownloadIcon from 'mdi-material-ui/DownloadOutline';\nimport React, { ReactElement, useRef } from 'react';\nimport { useDashboard } from '../../context';\nimport { serializeDashboard } from './serializeDashboard';\n\n// Button that enables downloading the dashboard as a JSON file\nexport function DownloadButton(): ReactElement {\n const { dashboard } = useDashboard();\n const hiddenLinkRef = useRef<HTMLAnchorElement>(null);\n const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);\n const open = Boolean(anchorEl);\n const handleClick = (event: React.MouseEvent<HTMLButtonElement>): void => {\n setAnchorEl(event.currentTarget);\n };\n const handleItemClick = (format: 'json' | 'yaml', shape?: 'cr') => (): void => {\n setAnchorEl(null);\n\n const { contentType, content } = serializeDashboard(dashboard, format, shape);\n\n if (!hiddenLinkRef || !hiddenLinkRef.current) return;\n // Create blob URL\n const hiddenLinkUrl = URL.createObjectURL(new Blob([content], { type: contentType }));\n // Simulate click\n hiddenLinkRef.current.download = `${dashboard.metadata.name}${shape === 'cr' ? '-cr' : ''}.${format}`;\n hiddenLinkRef.current.href = hiddenLinkUrl;\n hiddenLinkRef.current.click();\n // Remove blob URL (for memory management)\n URL.revokeObjectURL(hiddenLinkUrl);\n };\n\n return (\n <>\n <ToolbarIconButton\n id=\"download-dashboard-button\"\n aria-controls={open ? 'basic-menu' : undefined}\n aria-haspopup=\"true\"\n aria-expanded={open ? 'true' : undefined}\n onClick={handleClick}\n >\n <DownloadIcon />\n </ToolbarIconButton>\n\n <Menu\n id=\"download-dashboard-formats\"\n anchorEl={anchorEl}\n open={open}\n hideBackdrop={true}\n onClose={() => setAnchorEl(null)}\n MenuListProps={{\n 'aria-labelledby': 'download-dashboard-button',\n }}\n >\n <div>\n <ClickAwayListener onClickAway={() => setAnchorEl(null)}>\n <MenuList>\n <MenuItem onClick={handleItemClick('json')}>JSON</MenuItem>\n <MenuItem onClick={handleItemClick('yaml')}>YAML</MenuItem>\n <MenuItem onClick={handleItemClick('yaml', 'cr')}>YAML (CR)</MenuItem>\n </MenuList>\n </ClickAwayListener>\n </div>\n </Menu>\n\n {/* Hidden link to download the dashboard as a JSON or YAML file */}\n {/* eslint-disable jsx-a11y/anchor-has-content */}\n {/* eslint-disable jsx-a11y/anchor-is-valid */}\n <a ref={hiddenLinkRef} style={{ display: 'none' }} />\n </>\n );\n}\n"],"names":["ClickAwayListener","Menu","MenuItem","MenuList","ToolbarIconButton","DownloadIcon","React","useRef","useDashboard","serializeDashboard","DownloadButton","dashboard","hiddenLinkRef","anchorEl","setAnchorEl","useState","open","Boolean","handleClick","event","currentTarget","handleItemClick","format","shape","contentType","content","current","hiddenLinkUrl","URL","createObjectURL","Blob","type","download","metadata","name","href","click","revokeObjectURL","id","aria-controls","undefined","aria-haspopup","aria-expanded","onClick","hideBackdrop","onClose","MenuListProps","div","onClickAway","a","ref","style","display"],"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,iBAAiB,EAAEC,IAAI,EAAEC,QAAQ,EAAEC,QAAQ,QAAQ,gBAAgB;AAC5E,SAASC,iBAAiB,QAAQ,yBAAyB;AAC3D,OAAOC,kBAAkB,kCAAkC;AAC3D,OAAOC,SAAuBC,MAAM,QAAQ,QAAQ;AACpD,SAASC,YAAY,QAAQ,gBAAgB;AAC7C,SAASC,kBAAkB,QAAQ,uBAAuB;AAE1D,+DAA+D;AAC/D,OAAO,SAASC;IACd,MAAM,EAAEC,SAAS,EAAE,GAAGH;IACtB,MAAMI,gBAAgBL,OAA0B;IAChD,MAAM,CAACM,UAAUC,YAAY,GAAGR,MAAMS,QAAQ,CAAqB;IACnE,MAAMC,OAAOC,QAAQJ;IACrB,MAAMK,cAAc,CAACC;QACnBL,YAAYK,MAAMC,aAAa;IACjC;IACA,MAAMC,kBAAkB,CAACC,QAAyBC,QAAiB;YACjET,YAAY;YAEZ,MAAM,EAAEU,WAAW,EAAEC,OAAO,EAAE,GAAGhB,mBAAmBE,WAAWW,QAAQC;YAEvE,IAAI,CAACX,iBAAiB,CAACA,cAAcc,OAAO,EAAE;YAC9C,kBAAkB;YAClB,MAAMC,gBAAgBC,IAAIC,eAAe,CAAC,IAAIC,KAAK;gBAACL;aAAQ,EAAE;gBAAEM,MAAMP;YAAY;YAClF,iBAAiB;YACjBZ,cAAcc,OAAO,CAACM,QAAQ,GAAG,GAAGrB,UAAUsB,QAAQ,CAACC,IAAI,GAAGX,UAAU,OAAO,QAAQ,GAAG,CAAC,EAAED,QAAQ;YACrGV,cAAcc,OAAO,CAACS,IAAI,GAAGR;YAC7Bf,cAAcc,OAAO,CAACU,KAAK;YAC3B,0CAA0C;YAC1CR,IAAIS,eAAe,CAACV;QACtB;IAEA,qBACE;;0BACE,KAACvB;gBACCkC,IAAG;gBACHC,iBAAevB,OAAO,eAAewB;gBACrCC,iBAAc;gBACdC,iBAAe1B,OAAO,SAASwB;gBAC/BG,SAASzB;0BAET,cAAA,KAACb;;0BAGH,KAACJ;gBACCqC,IAAG;gBACHzB,UAAUA;gBACVG,MAAMA;gBACN4B,cAAc;gBACdC,SAAS,IAAM/B,YAAY;gBAC3BgC,eAAe;oBACb,mBAAmB;gBACrB;0BAEA,cAAA,KAACC;8BACC,cAAA,KAAC/C;wBAAkBgD,aAAa,IAAMlC,YAAY;kCAChD,cAAA,MAACX;;8CACC,KAACD;oCAASyC,SAAStB,gBAAgB;8CAAS;;8CAC5C,KAACnB;oCAASyC,SAAStB,gBAAgB;8CAAS;;8CAC5C,KAACnB;oCAASyC,SAAStB,gBAAgB,QAAQ;8CAAO;;;;;;;0BAS1D,KAAC4B;gBAAEC,KAAKtC;gBAAeuC,OAAO;oBAAEC,SAAS;gBAAO;;;;AAGtD"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { DashboardResource, EphemeralDashboardResource } from '@perses-dev/core';
|
|
2
|
+
type SerializedDashboard = {
|
|
3
|
+
contentType: string;
|
|
4
|
+
content: string;
|
|
5
|
+
};
|
|
6
|
+
export declare function serializeDashboard(dashboard: DashboardResource | EphemeralDashboardResource, format: 'json' | 'yaml', shape?: 'cr'): SerializedDashboard;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=serializeDashboard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serializeDashboard.d.ts","sourceRoot":"","sources":["../../../src/components/DownloadButton/serializeDashboard.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,iBAAiB,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAGjF,KAAK,mBAAmB,GAAG;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AA+BF,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,iBAAiB,GAAG,0BAA0B,EACzD,MAAM,EAAE,MAAM,GAAG,MAAM,EACvB,KAAK,CAAC,EAAE,IAAI,GACX,mBAAmB,CAOrB"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// Copyright 2023 The Perses Authors
|
|
2
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
+
// you may not use this file except in compliance with the License.
|
|
4
|
+
// You may obtain a copy of the License at
|
|
5
|
+
//
|
|
6
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
//
|
|
8
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
+
// See the License for the specific language governing permissions and
|
|
12
|
+
// limitations under the License.
|
|
13
|
+
import { stringify } from 'yaml';
|
|
14
|
+
function serializeYaml(dashboard, shape) {
|
|
15
|
+
let content;
|
|
16
|
+
if (shape === 'cr') {
|
|
17
|
+
const name = dashboard.metadata.name.toLowerCase().replace(/[^a-z0-9-]/g, '-');
|
|
18
|
+
content = stringify({
|
|
19
|
+
apiVersion: 'perses.dev/v1alpha1',
|
|
20
|
+
kind: 'PersesDashboard',
|
|
21
|
+
metadata: {
|
|
22
|
+
labels: {
|
|
23
|
+
'app.kubernetes.io/name': 'perses-dashboard',
|
|
24
|
+
'app.kubernetes.io/instance': name,
|
|
25
|
+
'app.kubernetes.io/part-of': 'perses-operator'
|
|
26
|
+
},
|
|
27
|
+
name,
|
|
28
|
+
namespace: dashboard.metadata.project
|
|
29
|
+
},
|
|
30
|
+
spec: dashboard.spec
|
|
31
|
+
}, {
|
|
32
|
+
schema: 'yaml-1.1'
|
|
33
|
+
});
|
|
34
|
+
} else {
|
|
35
|
+
content = stringify(dashboard, {
|
|
36
|
+
schema: 'yaml-1.1'
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
contentType: 'application/yaml',
|
|
41
|
+
content
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export function serializeDashboard(dashboard, format, shape) {
|
|
45
|
+
switch(format){
|
|
46
|
+
case 'json':
|
|
47
|
+
return {
|
|
48
|
+
contentType: 'application/json',
|
|
49
|
+
content: JSON.stringify(dashboard, null, 2)
|
|
50
|
+
};
|
|
51
|
+
case 'yaml':
|
|
52
|
+
return serializeYaml(dashboard, shape);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
//# sourceMappingURL=serializeDashboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/DownloadButton/serializeDashboard.ts"],"sourcesContent":["// Copyright 2023 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { DashboardResource, EphemeralDashboardResource } from '@perses-dev/core';\nimport { stringify } from 'yaml';\n\ntype SerializedDashboard = {\n contentType: string;\n content: string;\n};\n\nfunction serializeYaml(dashboard: DashboardResource | EphemeralDashboardResource, shape?: 'cr'): SerializedDashboard {\n let content: string;\n\n if (shape === 'cr') {\n const name = dashboard.metadata.name.toLowerCase().replace(/[^a-z0-9-]/g, '-');\n content = stringify(\n {\n apiVersion: 'perses.dev/v1alpha1',\n kind: 'PersesDashboard',\n metadata: {\n labels: {\n 'app.kubernetes.io/name': 'perses-dashboard',\n 'app.kubernetes.io/instance': name,\n 'app.kubernetes.io/part-of': 'perses-operator',\n },\n name,\n namespace: dashboard.metadata.project,\n },\n spec: dashboard.spec,\n },\n { schema: 'yaml-1.1' }\n );\n } else {\n content = stringify(dashboard, { schema: 'yaml-1.1' });\n }\n\n return { contentType: 'application/yaml', content };\n}\n\nexport function serializeDashboard(\n dashboard: DashboardResource | EphemeralDashboardResource,\n format: 'json' | 'yaml',\n shape?: 'cr'\n): SerializedDashboard {\n switch (format) {\n case 'json':\n return { contentType: 'application/json', content: JSON.stringify(dashboard, null, 2) };\n case 'yaml':\n return serializeYaml(dashboard, shape);\n }\n}\n"],"names":["stringify","serializeYaml","dashboard","shape","content","name","metadata","toLowerCase","replace","apiVersion","kind","labels","namespace","project","spec","schema","contentType","serializeDashboard","format","JSON"],"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;AAGjC,SAASA,SAAS,QAAQ,OAAO;AAOjC,SAASC,cAAcC,SAAyD,EAAEC,KAAY;IAC5F,IAAIC;IAEJ,IAAID,UAAU,MAAM;QAClB,MAAME,OAAOH,UAAUI,QAAQ,CAACD,IAAI,CAACE,WAAW,GAAGC,OAAO,CAAC,eAAe;QAC1EJ,UAAUJ,UACR;YACES,YAAY;YACZC,MAAM;YACNJ,UAAU;gBACRK,QAAQ;oBACN,0BAA0B;oBAC1B,8BAA8BN;oBAC9B,6BAA6B;gBAC/B;gBACAA;gBACAO,WAAWV,UAAUI,QAAQ,CAACO,OAAO;YACvC;YACAC,MAAMZ,UAAUY,IAAI;QACtB,GACA;YAAEC,QAAQ;QAAW;IAEzB,OAAO;QACLX,UAAUJ,UAAUE,WAAW;YAAEa,QAAQ;QAAW;IACtD;IAEA,OAAO;QAAEC,aAAa;QAAoBZ;IAAQ;AACpD;AAEA,OAAO,SAASa,mBACdf,SAAyD,EACzDgB,MAAuB,EACvBf,KAAY;IAEZ,OAAQe;QACN,KAAK;YACH,OAAO;gBAAEF,aAAa;gBAAoBZ,SAASe,KAAKnB,SAAS,CAACE,WAAW,MAAM;YAAG;QACxF,KAAK;YACH,OAAOD,cAAcC,WAAWC;IACpC;AACF"}
|