@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
|
@@ -24,7 +24,6 @@ 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 _context = require("../../context");
|
|
29
28
|
const _AddPanelButton = require("../AddPanelButton");
|
|
30
29
|
const _AddGroupButton = require("../AddGroupButton");
|
|
@@ -40,126 +39,116 @@ const DashboardToolbar = (props)=>{
|
|
|
40
39
|
const { isEditMode } = (0, _context.useEditMode)();
|
|
41
40
|
const isBiggerThanSm = (0, _material.useMediaQuery)((0, _material.useTheme)().breakpoints.up('sm'));
|
|
42
41
|
const isBiggerThanMd = (0, _material.useMediaQuery)((0, _material.useTheme)().breakpoints.up('md'));
|
|
43
|
-
const { timeZone, setTimeZone } = (0, _pluginsystem.useTimeZone)();
|
|
44
|
-
const timeZoneOptions = (0, _components.getTimeZoneOptions)();
|
|
45
42
|
const dashboardTitle = dashboardTitleComponent ? dashboardTitleComponent : /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Typography, {
|
|
46
43
|
variant: "h2",
|
|
47
44
|
children: dashboardName
|
|
48
45
|
});
|
|
49
46
|
const testId = 'dashboard-toolbar';
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
},
|
|
65
|
-
children: [
|
|
66
|
-
dashboardTitle,
|
|
67
|
-
isEditMode ? /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Stack, {
|
|
68
|
-
direction: "row",
|
|
69
|
-
gap: 1,
|
|
70
|
-
ml: "auto",
|
|
71
|
-
children: [
|
|
72
|
-
isReadonly && /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Alert, {
|
|
73
|
-
severity: "warning",
|
|
74
|
-
sx: {
|
|
75
|
-
backgroundColor: 'transparent',
|
|
76
|
-
padding: 0
|
|
77
|
-
},
|
|
78
|
-
children: "Dashboard managed via code only. Download JSON and commit changes to save."
|
|
79
|
-
}),
|
|
80
|
-
/*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Stack, {
|
|
81
|
-
direction: "row",
|
|
82
|
-
spacing: 0.5,
|
|
83
|
-
ml: 1,
|
|
84
|
-
whiteSpace: "nowrap",
|
|
85
|
-
children: [
|
|
86
|
-
isVariableEnabled && /*#__PURE__*/ (0, _jsxruntime.jsx)(_Variables.EditVariablesButton, {}),
|
|
87
|
-
isDatasourceEnabled && /*#__PURE__*/ (0, _jsxruntime.jsx)(_Datasources.EditDatasourcesButton, {}),
|
|
88
|
-
/*#__PURE__*/ (0, _jsxruntime.jsx)(_AddPanelButton.AddPanelButton, {}),
|
|
89
|
-
/*#__PURE__*/ (0, _jsxruntime.jsx)(_AddGroupButton.AddGroupButton, {})
|
|
90
|
-
]
|
|
91
|
-
}),
|
|
92
|
-
/*#__PURE__*/ (0, _jsxruntime.jsx)(_SaveDashboardButton.SaveDashboardButton, {
|
|
93
|
-
onSave: onSave,
|
|
94
|
-
isDisabled: isReadonly
|
|
95
|
-
}),
|
|
96
|
-
/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Button, {
|
|
97
|
-
variant: "outlined",
|
|
98
|
-
onClick: onCancelButtonClick,
|
|
99
|
-
children: "Cancel"
|
|
100
|
-
})
|
|
101
|
-
]
|
|
102
|
-
}) : /*#__PURE__*/ (0, _jsxruntime.jsx)(_jsxruntime.Fragment, {
|
|
103
|
-
children: isBiggerThanSm && /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Stack, {
|
|
47
|
+
return /*#__PURE__*/ (0, _jsxruntime.jsx)(_jsxruntime.Fragment, {
|
|
48
|
+
children: /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Stack, {
|
|
49
|
+
"data-testid": testId,
|
|
50
|
+
children: [
|
|
51
|
+
/*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Box, {
|
|
52
|
+
px: 2,
|
|
53
|
+
py: 1.5,
|
|
54
|
+
display: "flex",
|
|
55
|
+
sx: {
|
|
56
|
+
backgroundColor: (theme)=>theme.palette.primary.main + (isEditMode ? '30' : '0')
|
|
57
|
+
},
|
|
58
|
+
children: [
|
|
59
|
+
dashboardTitle,
|
|
60
|
+
isEditMode ? /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Stack, {
|
|
104
61
|
direction: "row",
|
|
105
62
|
gap: 1,
|
|
106
63
|
ml: "auto",
|
|
107
|
-
children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_EditButton.EditButton, {
|
|
108
|
-
onClick: onEditButtonClick
|
|
109
|
-
})
|
|
110
|
-
})
|
|
111
|
-
})
|
|
112
|
-
]
|
|
113
|
-
}),
|
|
114
|
-
/*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Box, {
|
|
115
|
-
sx: {
|
|
116
|
-
display: 'flex',
|
|
117
|
-
width: '100%',
|
|
118
|
-
alignItems: 'start',
|
|
119
|
-
padding: (theme)=>theme.spacing(1, 2, 0, 2),
|
|
120
|
-
flexDirection: isBiggerThanMd ? 'row' : 'column',
|
|
121
|
-
flexWrap: 'nowrap',
|
|
122
|
-
gap: 1
|
|
123
|
-
},
|
|
124
|
-
children: [
|
|
125
|
-
/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Box, {
|
|
126
|
-
width: "100%",
|
|
127
|
-
children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.ErrorBoundary, {
|
|
128
|
-
FallbackComponent: _components.ErrorAlert,
|
|
129
|
-
children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_DashboardStickyToolbar.DashboardStickyToolbar, {
|
|
130
|
-
initialVariableIsSticky: initialVariableIsSticky,
|
|
131
|
-
sx: {
|
|
132
|
-
backgroundColor: ({ palette })=>palette.background.default
|
|
133
|
-
}
|
|
134
|
-
})
|
|
135
|
-
})
|
|
136
|
-
}),
|
|
137
|
-
/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Stack, {
|
|
138
|
-
direction: "row",
|
|
139
|
-
ml: "auto",
|
|
140
|
-
flexWrap: "wrap",
|
|
141
|
-
justifyContent: "end",
|
|
142
|
-
children: /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Stack, {
|
|
143
|
-
direction: "row",
|
|
144
|
-
spacing: 1,
|
|
145
|
-
mt: 1,
|
|
146
|
-
ml: 1,
|
|
147
64
|
children: [
|
|
148
|
-
/*#__PURE__*/ (0, _jsxruntime.jsx)(
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
65
|
+
isReadonly && /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Alert, {
|
|
66
|
+
severity: "warning",
|
|
67
|
+
sx: {
|
|
68
|
+
backgroundColor: 'transparent',
|
|
69
|
+
padding: 0
|
|
70
|
+
},
|
|
71
|
+
children: "Dashboard managed via code only. Download JSON and commit changes to save."
|
|
153
72
|
}),
|
|
154
|
-
/*#__PURE__*/ (0, _jsxruntime.
|
|
155
|
-
|
|
156
|
-
|
|
73
|
+
/*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Stack, {
|
|
74
|
+
direction: "row",
|
|
75
|
+
spacing: 0.5,
|
|
76
|
+
ml: 1,
|
|
77
|
+
whiteSpace: "nowrap",
|
|
78
|
+
children: [
|
|
79
|
+
isVariableEnabled && /*#__PURE__*/ (0, _jsxruntime.jsx)(_Variables.EditVariablesButton, {}),
|
|
80
|
+
isDatasourceEnabled && /*#__PURE__*/ (0, _jsxruntime.jsx)(_Datasources.EditDatasourcesButton, {}),
|
|
81
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(_AddPanelButton.AddPanelButton, {}),
|
|
82
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(_AddGroupButton.AddGroupButton, {})
|
|
83
|
+
]
|
|
84
|
+
}),
|
|
85
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(_SaveDashboardButton.SaveDashboardButton, {
|
|
86
|
+
onSave: onSave,
|
|
87
|
+
isDisabled: isReadonly
|
|
88
|
+
}),
|
|
89
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Button, {
|
|
90
|
+
variant: "outlined",
|
|
91
|
+
onClick: onCancelButtonClick,
|
|
92
|
+
children: "Cancel"
|
|
157
93
|
})
|
|
158
94
|
]
|
|
95
|
+
}) : /*#__PURE__*/ (0, _jsxruntime.jsx)(_jsxruntime.Fragment, {
|
|
96
|
+
children: isBiggerThanSm && /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Stack, {
|
|
97
|
+
direction: "row",
|
|
98
|
+
gap: 1,
|
|
99
|
+
ml: "auto",
|
|
100
|
+
children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_EditButton.EditButton, {
|
|
101
|
+
onClick: onEditButtonClick
|
|
102
|
+
})
|
|
103
|
+
})
|
|
104
|
+
})
|
|
105
|
+
]
|
|
106
|
+
}),
|
|
107
|
+
/*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Box, {
|
|
108
|
+
sx: {
|
|
109
|
+
display: 'flex',
|
|
110
|
+
width: '100%',
|
|
111
|
+
alignItems: 'start',
|
|
112
|
+
padding: (theme)=>theme.spacing(1, 2, 0, 2),
|
|
113
|
+
flexDirection: isBiggerThanMd ? 'row' : 'column',
|
|
114
|
+
flexWrap: 'nowrap',
|
|
115
|
+
gap: 1
|
|
116
|
+
},
|
|
117
|
+
children: [
|
|
118
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Box, {
|
|
119
|
+
width: "100%",
|
|
120
|
+
children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.ErrorBoundary, {
|
|
121
|
+
FallbackComponent: _components.ErrorAlert,
|
|
122
|
+
children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_DashboardStickyToolbar.DashboardStickyToolbar, {
|
|
123
|
+
initialVariableIsSticky: initialVariableIsSticky,
|
|
124
|
+
sx: {
|
|
125
|
+
backgroundColor: ({ palette })=>palette.background.default
|
|
126
|
+
}
|
|
127
|
+
})
|
|
128
|
+
})
|
|
129
|
+
}),
|
|
130
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Stack, {
|
|
131
|
+
direction: "row",
|
|
132
|
+
ml: "auto",
|
|
133
|
+
flexWrap: "wrap",
|
|
134
|
+
justifyContent: "end",
|
|
135
|
+
children: /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Stack, {
|
|
136
|
+
direction: "row",
|
|
137
|
+
spacing: 1,
|
|
138
|
+
mt: 1,
|
|
139
|
+
ml: 1,
|
|
140
|
+
children: [
|
|
141
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(_pluginsystem.TimeRangeControls, {}),
|
|
142
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(_DownloadButton.DownloadButton, {}),
|
|
143
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(_EditJsonButton.EditJsonButton, {
|
|
144
|
+
isReadonly: !isEditMode
|
|
145
|
+
})
|
|
146
|
+
]
|
|
147
|
+
})
|
|
159
148
|
})
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
149
|
+
]
|
|
150
|
+
})
|
|
151
|
+
]
|
|
152
|
+
})
|
|
164
153
|
});
|
|
165
154
|
};
|
|
@@ -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
|
+
}
|
|
@@ -54,6 +54,88 @@ const Panel = /*#__PURE__*/ (0, _react.memo)(function Panel(props) {
|
|
|
54
54
|
]);
|
|
55
55
|
const chartsTheme = (0, _components.useChartsTheme)();
|
|
56
56
|
const { queryResults } = (0, _pluginsystem.useDataQueriesContext)();
|
|
57
|
+
const { getPlugin } = (0, _pluginsystem.usePluginRegistry)();
|
|
58
|
+
const panelPropsForActions = (0, _react.useMemo)(()=>{
|
|
59
|
+
return {
|
|
60
|
+
spec: definition.spec.plugin.spec,
|
|
61
|
+
queryResults: queryResults.map((query)=>({
|
|
62
|
+
definition: query.definition,
|
|
63
|
+
data: query.data
|
|
64
|
+
})),
|
|
65
|
+
contentDimensions,
|
|
66
|
+
definition
|
|
67
|
+
};
|
|
68
|
+
}, [
|
|
69
|
+
definition,
|
|
70
|
+
contentDimensions,
|
|
71
|
+
queryResults
|
|
72
|
+
]);
|
|
73
|
+
// Load plugin actions from the plugin
|
|
74
|
+
const [pluginActions, setPluginActions] = (0, _react.useState)([]);
|
|
75
|
+
(0, _react.useEffect)(()=>{
|
|
76
|
+
let cancelled = false;
|
|
77
|
+
const loadPluginActions = async ()=>{
|
|
78
|
+
const panelPluginKind = definition.spec.plugin.kind;
|
|
79
|
+
const panelProps = panelPropsForActions;
|
|
80
|
+
if (!panelPluginKind || !panelProps) {
|
|
81
|
+
if (!cancelled) {
|
|
82
|
+
setPluginActions([]);
|
|
83
|
+
}
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
// Add defensive check for getPlugin availability
|
|
88
|
+
if (!getPlugin || typeof getPlugin !== 'function') {
|
|
89
|
+
if (!cancelled) {
|
|
90
|
+
setPluginActions([]);
|
|
91
|
+
}
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const plugin = await getPlugin('Panel', panelPluginKind);
|
|
95
|
+
if (cancelled) return;
|
|
96
|
+
// More defensive checking for plugin and actions
|
|
97
|
+
if (!plugin || typeof plugin !== 'object' || !plugin.actions || !Array.isArray(plugin.actions) || plugin.actions.length === 0) {
|
|
98
|
+
if (!cancelled) {
|
|
99
|
+
setPluginActions([]);
|
|
100
|
+
}
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
// Render plugin actions in header location
|
|
104
|
+
const headerActions = plugin.actions.filter((action)=>!action.location || action.location === 'header').map((action, index)=>{
|
|
105
|
+
const ActionComponent = action.component;
|
|
106
|
+
try {
|
|
107
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
108
|
+
return /*#__PURE__*/ (0, _jsxruntime.jsx)(ActionComponent, {
|
|
109
|
+
...panelProps
|
|
110
|
+
}, `plugin-action-${index}`);
|
|
111
|
+
} catch (error) {
|
|
112
|
+
console.warn(`Failed to render plugin action ${index}:`, error);
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
}).filter((item)=>Boolean(item));
|
|
116
|
+
if (!cancelled) {
|
|
117
|
+
setPluginActions(headerActions);
|
|
118
|
+
}
|
|
119
|
+
} catch (error) {
|
|
120
|
+
if (!cancelled) {
|
|
121
|
+
console.warn('Failed to load plugin actions:', error);
|
|
122
|
+
setPluginActions([]);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
// Use setTimeout to defer the async operation to the next tick
|
|
127
|
+
const timeoutId = setTimeout(()=>{
|
|
128
|
+
loadPluginActions();
|
|
129
|
+
}, 0);
|
|
130
|
+
return ()=>{
|
|
131
|
+
cancelled = true;
|
|
132
|
+
clearTimeout(timeoutId);
|
|
133
|
+
};
|
|
134
|
+
}, [
|
|
135
|
+
definition.spec.plugin.kind,
|
|
136
|
+
panelPropsForActions,
|
|
137
|
+
getPlugin
|
|
138
|
+
]);
|
|
57
139
|
const handleMouseEnter = (e)=>{
|
|
58
140
|
onMouseEnter?.(e);
|
|
59
141
|
};
|
|
@@ -91,6 +173,7 @@ const Panel = /*#__PURE__*/ (0, _react.memo)(function Panel(props) {
|
|
|
91
173
|
readHandlers: readHandlers,
|
|
92
174
|
editHandlers: editHandlers,
|
|
93
175
|
links: definition.spec.links,
|
|
176
|
+
pluginActions: pluginActions,
|
|
94
177
|
sx: {
|
|
95
178
|
paddingX: `${chartsTheme.container.padding.default}px`
|
|
96
179
|
}
|
|
@@ -112,7 +195,8 @@ const Panel = /*#__PURE__*/ (0, _react.memo)(function Panel(props) {
|
|
|
112
195
|
children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.ErrorBoundary, {
|
|
113
196
|
FallbackComponent: _components.ErrorAlert,
|
|
114
197
|
resetKeys: [
|
|
115
|
-
definition.spec
|
|
198
|
+
definition.spec,
|
|
199
|
+
queryResults
|
|
116
200
|
],
|
|
117
201
|
children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_PanelContent.PanelContent, {
|
|
118
202
|
definition: definition,
|
|
@@ -24,6 +24,7 @@ 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");
|
|
27
28
|
const _ArrowCollapse = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/ArrowCollapse"));
|
|
28
29
|
const _ArrowExpand = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/ArrowExpand"));
|
|
29
30
|
const _PencilOutline = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/PencilOutline"));
|
|
@@ -47,7 +48,10 @@ const ConditionalBox = (0, _material.styled)(_material.Box)({
|
|
|
47
48
|
flexGrow: 1,
|
|
48
49
|
justifyContent: 'flex-end'
|
|
49
50
|
});
|
|
50
|
-
const PanelActions = ({ editHandlers, readHandlers, extra, title, description, descriptionTooltipId, links,
|
|
51
|
+
const PanelActions = ({ editHandlers, readHandlers, extra, title, description, descriptionTooltipId, links, panelContentProps, pluginActions = [] })=>{
|
|
52
|
+
const { isFetching, errors } = (0, _pluginsystem.useDataQueriesContext)();
|
|
53
|
+
// Only destructure queryResults since we removed panelPluginKind and spec
|
|
54
|
+
const { queryResults } = panelContentProps;
|
|
51
55
|
const descriptionAction = (0, _react.useMemo)(()=>{
|
|
52
56
|
if (description && description.trim().length > 0) {
|
|
53
57
|
return /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.InfoTooltip, {
|
|
@@ -78,19 +82,45 @@ const PanelActions = ({ editHandlers, readHandlers, extra, title, description, d
|
|
|
78
82
|
});
|
|
79
83
|
const extraActions = editHandlers === undefined && extra;
|
|
80
84
|
const queryStateIndicator = (0, _react.useMemo)(()=>{
|
|
81
|
-
|
|
82
|
-
const
|
|
85
|
+
// Check if any query is fetching
|
|
86
|
+
const isQueryFetching = queryResults.some((q)=>q.isFetching);
|
|
87
|
+
// Get query-specific errors
|
|
83
88
|
const queryErrors = queryResults.filter((q)=>q.error);
|
|
84
|
-
|
|
89
|
+
// Convert QueryData[] to TimeSeriesData format for data availability check
|
|
90
|
+
const timeSeriesData = queryResults && queryResults.length > 0 ? {
|
|
91
|
+
series: queryResults.flatMap((q)=>{
|
|
92
|
+
// Only extract series if the data type is TimeSeriesData
|
|
93
|
+
if (q.data && typeof q.data === 'object' && 'series' in q.data) {
|
|
94
|
+
return q.data.series || [];
|
|
95
|
+
}
|
|
96
|
+
return [];
|
|
97
|
+
})
|
|
98
|
+
} : undefined;
|
|
99
|
+
const hasData = timeSeriesData && timeSeriesData.series && timeSeriesData.series.length > 0;
|
|
100
|
+
// Show loading indicator if queries are fetching AND we already have data
|
|
101
|
+
if ((isFetching || isQueryFetching) && hasData) {
|
|
85
102
|
// If the panel has no data, the panel content will show the loading overlay.
|
|
86
103
|
// Therefore, show the circular loading indicator only in case the panel doesn't display the loading overlay already.
|
|
87
104
|
return /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.CircularProgress, {
|
|
88
105
|
"aria-label": "loading",
|
|
89
106
|
size: "1.125rem"
|
|
90
107
|
});
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
|
|
108
|
+
}
|
|
109
|
+
// Check for errors from both context and query results
|
|
110
|
+
const contextErrors = (errors || []).filter((error)=>error !== null);
|
|
111
|
+
const allErrors = [
|
|
112
|
+
...contextErrors,
|
|
113
|
+
...queryErrors.map((q)=>q.error)
|
|
114
|
+
].filter(Boolean);
|
|
115
|
+
if (allErrors.length > 0) {
|
|
116
|
+
const errorTexts = allErrors.map((e)=>{
|
|
117
|
+
if (typeof e === 'string') return e;
|
|
118
|
+
if (e && typeof e === 'object') {
|
|
119
|
+
const errorObj = e;
|
|
120
|
+
return errorObj.message ?? errorObj.toString?.() ?? 'Unknown error';
|
|
121
|
+
}
|
|
122
|
+
return 'Unknown error';
|
|
123
|
+
}).join('\n');
|
|
94
124
|
return /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.InfoTooltip, {
|
|
95
125
|
description: errorTexts,
|
|
96
126
|
children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_HeaderIconButton.HeaderIconButton, {
|
|
@@ -103,7 +133,9 @@ const PanelActions = ({ editHandlers, readHandlers, extra, title, description, d
|
|
|
103
133
|
});
|
|
104
134
|
}
|
|
105
135
|
}, [
|
|
106
|
-
queryResults
|
|
136
|
+
queryResults,
|
|
137
|
+
isFetching,
|
|
138
|
+
errors
|
|
107
139
|
]);
|
|
108
140
|
const readActions = (0, _react.useMemo)(()=>{
|
|
109
141
|
if (readHandlers !== undefined) {
|
|
@@ -242,6 +274,7 @@ const PanelActions = ({ editHandlers, readHandlers, extra, title, description, d
|
|
|
242
274
|
editActions
|
|
243
275
|
]
|
|
244
276
|
}),
|
|
277
|
+
pluginActions,
|
|
245
278
|
moveAction
|
|
246
279
|
]
|
|
247
280
|
})
|
|
@@ -269,6 +302,8 @@ const PanelActions = ({ editHandlers, readHandlers, extra, title, description, d
|
|
|
269
302
|
extraActions,
|
|
270
303
|
" ",
|
|
271
304
|
readActions,
|
|
305
|
+
" ",
|
|
306
|
+
pluginActions,
|
|
272
307
|
/*#__PURE__*/ (0, _jsxruntime.jsx)(OverflowMenu, {
|
|
273
308
|
title: title,
|
|
274
309
|
children: editActions
|
|
@@ -303,6 +338,8 @@ const PanelActions = ({ editHandlers, readHandlers, extra, title, description, d
|
|
|
303
338
|
" ",
|
|
304
339
|
readActions,
|
|
305
340
|
" ",
|
|
341
|
+
pluginActions,
|
|
342
|
+
" ",
|
|
306
343
|
editActions,
|
|
307
344
|
" ",
|
|
308
345
|
moveAction
|
|
@@ -24,13 +24,20 @@ 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");
|
|
27
28
|
const _constants = require("../../constants");
|
|
28
29
|
const _PanelActions = require("./PanelActions");
|
|
29
|
-
function PanelHeader({ id, title: rawTitle, description: rawDescription, links, queryResults, readHandlers, editHandlers, sx, extra, ...rest }) {
|
|
30
|
+
function PanelHeader({ id, title: rawTitle, description: rawDescription, links, queryResults, readHandlers, editHandlers, sx, extra, pluginActions, ...rest }) {
|
|
30
31
|
const titleElementId = `${id}-title`;
|
|
31
32
|
const descriptionTooltipId = `${id}-description`;
|
|
32
33
|
const title = (0, _pluginsystem.useReplaceVariablesInString)(rawTitle);
|
|
33
34
|
const description = (0, _pluginsystem.useReplaceVariablesInString)(rawDescription);
|
|
35
|
+
// Create the panelContentProps object with only queryResults
|
|
36
|
+
const panelContentProps = (0, _react.useMemo)(()=>({
|
|
37
|
+
queryResults
|
|
38
|
+
}), [
|
|
39
|
+
queryResults
|
|
40
|
+
]);
|
|
34
41
|
return /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.CardHeader, {
|
|
35
42
|
id: id,
|
|
36
43
|
component: "header",
|
|
@@ -59,10 +66,11 @@ function PanelHeader({ id, title: rawTitle, description: rawDescription, links,
|
|
|
59
66
|
description: description,
|
|
60
67
|
descriptionTooltipId: descriptionTooltipId,
|
|
61
68
|
links: links,
|
|
62
|
-
queryResults: queryResults,
|
|
63
69
|
readHandlers: readHandlers,
|
|
64
70
|
editHandlers: editHandlers,
|
|
65
|
-
extra: extra
|
|
71
|
+
extra: extra,
|
|
72
|
+
panelContentProps: panelContentProps,
|
|
73
|
+
pluginActions: pluginActions
|
|
66
74
|
})
|
|
67
75
|
]
|
|
68
76
|
}),
|
|
@@ -31,11 +31,8 @@ const SaveChangesConfirmationDialog = ()=>{
|
|
|
31
31
|
const { saveChangesConfirmationDialog: dialog } = (0, _context.useSaveChangesConfirmationDialog)();
|
|
32
32
|
const isSavedDurationModified = dialog?.isSavedDurationModified ?? true;
|
|
33
33
|
const isSavedVariableModified = dialog?.isSavedVariableModified ?? true;
|
|
34
|
-
const isSavedTimeZoneModified = dialog?.isSavedTimeZoneModified ?? true;
|
|
35
34
|
const [saveDefaultTimeRange, setSaveDefaultTimeRange] = (0, _react.useState)(isSavedDurationModified);
|
|
36
35
|
const [saveDefaultVariables, setSaveDefaultVariables] = (0, _react.useState)(isSavedVariableModified);
|
|
37
|
-
const [saveDefaultTimeZone, setSaveDefaultTimeZone] = (0, _react.useState)(isSavedTimeZoneModified);
|
|
38
|
-
const { timeZone } = (0, _pluginsystem.useTimeZone)();
|
|
39
36
|
const { getSavedVariablesStatus } = (0, _context.useVariableDefinitionActions)();
|
|
40
37
|
const { modifiedVariableNames } = getSavedVariablesStatus();
|
|
41
38
|
const isOpen = dialog !== undefined;
|
|
@@ -43,7 +40,6 @@ const SaveChangesConfirmationDialog = ()=>{
|
|
|
43
40
|
const currentTimeRangeText = (0, _core.isRelativeTimeRange)(timeRange) ? `(Last ${timeRange.pastDuration})` : '(Absolute time ranges can not be saved)';
|
|
44
41
|
const saveTimeRangeText = `Save current time range as new default ${currentTimeRangeText}`;
|
|
45
42
|
const saveVariablesText = `Save current variable values as new default (${modifiedVariableNames.length > 0 ? modifiedVariableNames.join(', ') : 'No modified variables'})`;
|
|
46
|
-
const saveTimeZoneText = `Save time zone as "${timeZone}" time`;
|
|
47
43
|
return /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.Dialog, {
|
|
48
44
|
open: isOpen,
|
|
49
45
|
children: dialog !== undefined && /*#__PURE__*/ (0, _jsxruntime.jsxs)(_jsxruntime.Fragment, {
|
|
@@ -75,14 +71,6 @@ const SaveChangesConfirmationDialog = ()=>{
|
|
|
75
71
|
onChange: (e)=>setSaveDefaultVariables(e.target.checked)
|
|
76
72
|
}),
|
|
77
73
|
label: saveVariablesText
|
|
78
|
-
}),
|
|
79
|
-
/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.FormControlLabel, {
|
|
80
|
-
control: /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Checkbox, {
|
|
81
|
-
disabled: !isSavedTimeZoneModified,
|
|
82
|
-
checked: saveDefaultTimeZone && isSavedTimeZoneModified,
|
|
83
|
-
onChange: (e)=>setSaveDefaultTimeZone(e.target.checked)
|
|
84
|
-
}),
|
|
85
|
-
label: saveTimeZoneText
|
|
86
74
|
})
|
|
87
75
|
]
|
|
88
76
|
})
|
|
@@ -92,7 +80,7 @@ const SaveChangesConfirmationDialog = ()=>{
|
|
|
92
80
|
children: [
|
|
93
81
|
/*#__PURE__*/ (0, _jsxruntime.jsx)(_components.Dialog.PrimaryButton, {
|
|
94
82
|
onClick: ()=>{
|
|
95
|
-
return dialog.onSaveChanges(saveDefaultTimeRange, saveDefaultVariables
|
|
83
|
+
return dialog.onSaveChanges(saveDefaultTimeRange, saveDefaultVariables);
|
|
96
84
|
},
|
|
97
85
|
children: "Save Changes"
|
|
98
86
|
}),
|