@perses-dev/dashboards 0.14.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/DashboardToolbar/DashboardToolbar.js +9 -3
- package/dist/cjs/components/DownloadButton/DownloadButton.js +109 -0
- package/dist/cjs/{utils → components/DownloadButton}/index.js +1 -1
- package/dist/cjs/{css/styles.js → components/GridLayout/GridContainer.js} +66 -39
- package/dist/cjs/components/GridLayout/GridLayout.js +51 -64
- package/dist/cjs/components/GridLayout/GridTitle.js +11 -14
- package/dist/cjs/components/Panel/Panel.js +4 -2
- package/dist/cjs/components/Panel/PanelHeader.js +52 -48
- package/dist/cjs/components/PanelDrawer/PanelDrawer.test.js +23 -0
- package/dist/cjs/components/TimeRangeControls/TimeRangeControls.js +15 -54
- package/dist/cjs/components/TimeRangeControls/TimeRangeControls.test.js +27 -11
- package/dist/cjs/components/Variables/Variable.js +16 -4
- package/dist/cjs/components/Variables/VariableEditor.js +21 -1
- package/dist/cjs/components/Variables/VariableEditorForm/VariableEditorForm.js +63 -7
- package/dist/cjs/components/Variables/VariableEditorForm/variable-editor-form-model.js +3 -3
- package/dist/cjs/components/Variables/VariableList.js +81 -17
- package/dist/cjs/components/index.js +1 -0
- package/dist/cjs/context/DashboardProvider/DashboardProvider.js +2 -1
- package/dist/cjs/context/DashboardProvider/dashboard-provider-api.js +68 -39
- package/dist/cjs/context/DashboardProvider/panel-editor-slice.js +40 -15
- package/dist/cjs/context/DashboardProvider/panel-group-editor-slice.js +5 -9
- package/dist/cjs/context/DashboardProvider/panel-group-slice.js +16 -1
- package/dist/cjs/context/{TimeRangeProvider.js → TimeRangeProvider/TimeRangeProvider.js} +4 -4
- package/dist/cjs/{utils/component-ids.js → context/TimeRangeProvider/index.js} +12 -14
- package/dist/cjs/{utils/time-range-params.js → context/TimeRangeProvider/query-params.js} +11 -5
- package/dist/cjs/index.js +0 -1
- package/dist/cjs/test/testDashboard.js +1 -1
- package/dist/cjs/views/ViewDashboard/DashboardApp.js +2 -1
- package/dist/cjs/views/ViewDashboard/ViewDashboard.js +6 -7
- package/dist/cjs/views/ViewDashboard/tests/panelGroups.test.js +16 -22
- package/dist/components/DashboardToolbar/DashboardToolbar.d.ts +1 -0
- package/dist/components/DashboardToolbar/DashboardToolbar.d.ts.map +1 -1
- package/dist/components/DashboardToolbar/DashboardToolbar.js +9 -3
- package/dist/components/DashboardToolbar/DashboardToolbar.js.map +1 -1
- package/dist/components/DownloadButton/DownloadButton.d.ts +3 -0
- package/dist/components/DownloadButton/DownloadButton.d.ts.map +1 -0
- package/dist/components/DownloadButton/DownloadButton.js +60 -0
- package/dist/components/DownloadButton/DownloadButton.js.map +1 -0
- package/dist/components/DownloadButton/index.d.ts +2 -0
- package/dist/components/DownloadButton/index.d.ts.map +1 -0
- package/dist/{utils → components/DownloadButton}/index.js +1 -1
- package/dist/components/DownloadButton/index.js.map +1 -0
- package/dist/components/GridLayout/GridContainer.d.ts +6 -0
- package/dist/components/GridLayout/GridContainer.d.ts.map +1 -0
- package/dist/{css/styles.js → components/GridLayout/GridContainer.js} +65 -38
- package/dist/components/GridLayout/GridContainer.js.map +1 -0
- package/dist/components/GridLayout/GridLayout.d.ts +1 -2
- package/dist/components/GridLayout/GridLayout.d.ts.map +1 -1
- package/dist/components/GridLayout/GridLayout.js +53 -66
- package/dist/components/GridLayout/GridLayout.js.map +1 -1
- package/dist/components/GridLayout/GridTitle.d.ts.map +1 -1
- package/dist/components/GridLayout/GridTitle.js +12 -15
- package/dist/components/GridLayout/GridTitle.js.map +1 -1
- package/dist/components/Panel/Panel.d.ts.map +1 -1
- package/dist/components/Panel/Panel.js +4 -2
- package/dist/components/Panel/Panel.js.map +1 -1
- package/dist/components/Panel/PanelHeader.d.ts.map +1 -1
- package/dist/components/Panel/PanelHeader.js +52 -48
- package/dist/components/Panel/PanelHeader.js.map +1 -1
- package/dist/components/PanelDrawer/PanelDrawer.test.js +23 -0
- package/dist/components/PanelDrawer/PanelDrawer.test.js.map +1 -1
- package/dist/components/TimeRangeControls/TimeRangeControls.d.ts.map +1 -1
- package/dist/components/TimeRangeControls/TimeRangeControls.js +19 -58
- package/dist/components/TimeRangeControls/TimeRangeControls.js.map +1 -1
- package/dist/components/TimeRangeControls/TimeRangeControls.test.js +28 -12
- package/dist/components/TimeRangeControls/TimeRangeControls.test.js.map +1 -1
- package/dist/components/Variables/Variable.js +16 -4
- package/dist/components/Variables/Variable.js.map +1 -1
- package/dist/components/Variables/VariableEditor.d.ts.map +1 -1
- package/dist/components/Variables/VariableEditor.js +23 -3
- package/dist/components/Variables/VariableEditor.js.map +1 -1
- package/dist/components/Variables/VariableEditorForm/VariableEditorForm.d.ts.map +1 -1
- package/dist/components/Variables/VariableEditorForm/VariableEditorForm.js +25 -3
- package/dist/components/Variables/VariableEditorForm/VariableEditorForm.js.map +1 -1
- package/dist/components/Variables/VariableEditorForm/variable-editor-form-model.d.ts +1 -1
- package/dist/components/Variables/VariableEditorForm/variable-editor-form-model.d.ts.map +1 -1
- package/dist/components/Variables/VariableEditorForm/variable-editor-form-model.js +3 -3
- package/dist/components/Variables/VariableEditorForm/variable-editor-form-model.js.map +1 -1
- package/dist/components/Variables/VariableList.d.ts +5 -1
- package/dist/components/Variables/VariableList.d.ts.map +1 -1
- package/dist/components/Variables/VariableList.js +43 -18
- package/dist/components/Variables/VariableList.js.map +1 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +1 -0
- package/dist/components/index.js.map +1 -1
- package/dist/context/DashboardProvider/DashboardProvider.js +2 -1
- package/dist/context/DashboardProvider/DashboardProvider.js.map +1 -1
- package/dist/context/DashboardProvider/dashboard-provider-api.d.ts +1 -1
- package/dist/context/DashboardProvider/dashboard-provider-api.d.ts.map +1 -1
- package/dist/context/DashboardProvider/dashboard-provider-api.js +70 -41
- package/dist/context/DashboardProvider/dashboard-provider-api.js.map +1 -1
- package/dist/context/DashboardProvider/panel-editor-slice.d.ts.map +1 -1
- package/dist/context/DashboardProvider/panel-editor-slice.js +40 -15
- package/dist/context/DashboardProvider/panel-editor-slice.js.map +1 -1
- package/dist/context/DashboardProvider/panel-group-editor-slice.d.ts.map +1 -1
- package/dist/context/DashboardProvider/panel-group-editor-slice.js +5 -9
- package/dist/context/DashboardProvider/panel-group-editor-slice.js.map +1 -1
- package/dist/context/DashboardProvider/panel-group-slice.d.ts +9 -0
- package/dist/context/DashboardProvider/panel-group-slice.d.ts.map +1 -1
- package/dist/context/DashboardProvider/panel-group-slice.js +17 -0
- package/dist/context/DashboardProvider/panel-group-slice.js.map +1 -1
- package/dist/context/{TimeRangeProvider.d.ts → TimeRangeProvider/TimeRangeProvider.d.ts} +2 -2
- package/dist/context/TimeRangeProvider/TimeRangeProvider.d.ts.map +1 -0
- package/dist/context/{TimeRangeProvider.js → TimeRangeProvider/TimeRangeProvider.js} +4 -4
- package/dist/context/TimeRangeProvider/TimeRangeProvider.js.map +1 -0
- package/dist/context/TimeRangeProvider/index.d.ts +3 -0
- package/dist/context/TimeRangeProvider/index.d.ts.map +1 -0
- package/dist/{utils/component-ids.js → context/TimeRangeProvider/index.js} +3 -14
- package/dist/context/TimeRangeProvider/index.js.map +1 -0
- package/dist/{utils/time-range-params.d.ts → context/TimeRangeProvider/query-params.d.ts} +3 -3
- package/dist/context/TimeRangeProvider/query-params.d.ts.map +1 -0
- package/dist/{utils/time-range-params.js → context/TimeRangeProvider/query-params.js} +13 -7
- package/dist/context/TimeRangeProvider/query-params.js.map +1 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/test/testDashboard.js +1 -1
- package/dist/test/testDashboard.js.map +1 -1
- package/dist/views/ViewDashboard/DashboardApp.d.ts +1 -0
- package/dist/views/ViewDashboard/DashboardApp.d.ts.map +1 -1
- package/dist/views/ViewDashboard/DashboardApp.js +2 -1
- package/dist/views/ViewDashboard/DashboardApp.js.map +1 -1
- package/dist/views/ViewDashboard/ViewDashboard.d.ts +1 -0
- package/dist/views/ViewDashboard/ViewDashboard.d.ts.map +1 -1
- package/dist/views/ViewDashboard/ViewDashboard.js +6 -7
- package/dist/views/ViewDashboard/ViewDashboard.js.map +1 -1
- package/dist/views/ViewDashboard/tests/panelGroups.test.js +16 -22
- package/dist/views/ViewDashboard/tests/panelGroups.test.js.map +1 -1
- package/package.json +4 -4
- package/dist/context/TimeRangeProvider.d.ts.map +0 -1
- package/dist/context/TimeRangeProvider.js.map +0 -1
- package/dist/css/styles.d.ts +0 -172
- package/dist/css/styles.d.ts.map +0 -1
- package/dist/css/styles.js.map +0 -1
- package/dist/utils/component-ids.d.ts +0 -8
- package/dist/utils/component-ids.d.ts.map +0 -1
- package/dist/utils/component-ids.js.map +0 -1
- package/dist/utils/index.d.ts +0 -2
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/index.js.map +0 -1
- package/dist/utils/time-range-params.d.ts.map +0 -1
- package/dist/utils/time-range-params.js.map +0 -1
|
@@ -33,58 +33,55 @@ function _interopRequireDefault(obj) {
|
|
|
33
33
|
function PanelHeader({ id , title , description , editHandlers , isHovered , sx , ...rest }) {
|
|
34
34
|
const titleElementId = `${id}-title`;
|
|
35
35
|
const descriptionTooltipId = `${id}-description`;
|
|
36
|
-
// Don't show any actions unless panel is hovered
|
|
37
36
|
let action = undefined;
|
|
38
|
-
if (
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
className: "drag-handle",
|
|
63
|
-
sx: {
|
|
64
|
-
cursor: 'grab'
|
|
65
|
-
}
|
|
66
|
-
})
|
|
67
|
-
})
|
|
68
|
-
]
|
|
69
|
-
});
|
|
70
|
-
} else if (description !== undefined) {
|
|
71
|
-
// If there aren't edit handlers and we have a description, show a button with a tooltip for the panel description
|
|
72
|
-
action = /*#__PURE__*/ (0, _jsxRuntime.jsx)(_components.InfoTooltip, {
|
|
73
|
-
id: descriptionTooltipId,
|
|
74
|
-
description: description,
|
|
75
|
-
placement: _components.TooltipPlacement.Bottom,
|
|
76
|
-
children: /*#__PURE__*/ (0, _jsxRuntime.jsx)(HeaderIconButton, {
|
|
77
|
-
"aria-label": "Panel Description",
|
|
78
|
-
children: /*#__PURE__*/ (0, _jsxRuntime.jsx)(_informationOutline.default, {
|
|
79
|
-
"aria-describedby": "info-tooltip",
|
|
80
|
-
"aria-hidden": false,
|
|
37
|
+
if (editHandlers !== undefined) {
|
|
38
|
+
// If there are edit handlers, always just show the edit buttons
|
|
39
|
+
action = /*#__PURE__*/ (0, _jsxRuntime.jsxs)(_material.Stack, {
|
|
40
|
+
direction: "row",
|
|
41
|
+
alignItems: "center",
|
|
42
|
+
spacing: 0.5,
|
|
43
|
+
children: [
|
|
44
|
+
/*#__PURE__*/ (0, _jsxRuntime.jsx)(HeaderIconButton, {
|
|
45
|
+
"aria-label": `edit panel ${title}`,
|
|
46
|
+
size: "small",
|
|
47
|
+
onClick: editHandlers.onEditPanelClick,
|
|
48
|
+
children: /*#__PURE__*/ (0, _jsxRuntime.jsx)(_pencilOutline.default, {})
|
|
49
|
+
}),
|
|
50
|
+
/*#__PURE__*/ (0, _jsxRuntime.jsx)(HeaderIconButton, {
|
|
51
|
+
"aria-label": `delete panel ${title}`,
|
|
52
|
+
size: "small",
|
|
53
|
+
onClick: editHandlers.onDeletePanelClick,
|
|
54
|
+
children: /*#__PURE__*/ (0, _jsxRuntime.jsx)(_deleteOutline.default, {})
|
|
55
|
+
}),
|
|
56
|
+
/*#__PURE__*/ (0, _jsxRuntime.jsx)(HeaderIconButton, {
|
|
57
|
+
"aria-label": `move panel ${title}`,
|
|
58
|
+
size: "small",
|
|
59
|
+
children: /*#__PURE__*/ (0, _jsxRuntime.jsx)(_dragVertical.default, {
|
|
60
|
+
className: "drag-handle",
|
|
81
61
|
sx: {
|
|
82
|
-
|
|
62
|
+
cursor: 'grab'
|
|
83
63
|
}
|
|
84
64
|
})
|
|
85
65
|
})
|
|
86
|
-
|
|
87
|
-
}
|
|
66
|
+
]
|
|
67
|
+
});
|
|
68
|
+
} else if (description !== undefined && isHovered) {
|
|
69
|
+
// If there aren't edit handlers and we have a description, show a button with a tooltip for the panel description
|
|
70
|
+
action = /*#__PURE__*/ (0, _jsxRuntime.jsx)(_components.InfoTooltip, {
|
|
71
|
+
id: descriptionTooltipId,
|
|
72
|
+
description: description,
|
|
73
|
+
placement: _components.TooltipPlacement.Bottom,
|
|
74
|
+
children: /*#__PURE__*/ (0, _jsxRuntime.jsx)(HeaderIconButton, {
|
|
75
|
+
"aria-label": "Panel Description",
|
|
76
|
+
children: /*#__PURE__*/ (0, _jsxRuntime.jsx)(_informationOutline.default, {
|
|
77
|
+
"aria-describedby": "info-tooltip",
|
|
78
|
+
"aria-hidden": false,
|
|
79
|
+
sx: {
|
|
80
|
+
color: (theme)=>theme.palette.grey[700]
|
|
81
|
+
}
|
|
82
|
+
})
|
|
83
|
+
})
|
|
84
|
+
});
|
|
88
85
|
}
|
|
89
86
|
return /*#__PURE__*/ (0, _jsxRuntime.jsx)(_material.CardHeader, {
|
|
90
87
|
id: id,
|
|
@@ -96,6 +93,10 @@ function PanelHeader({ id , title , description , editHandlers , isHovered , sx
|
|
|
96
93
|
id: titleElementId,
|
|
97
94
|
variant: "subtitle1",
|
|
98
95
|
sx: {
|
|
96
|
+
// `minHeight` guarantees that the header has the correct height
|
|
97
|
+
// when there is no title (i.e. in the preview)
|
|
98
|
+
lineHeight: '24px',
|
|
99
|
+
minHeight: '24px',
|
|
99
100
|
whiteSpace: 'nowrap',
|
|
100
101
|
overflow: 'hidden',
|
|
101
102
|
textOverflow: 'ellipsis'
|
|
@@ -105,7 +106,10 @@ function PanelHeader({ id , title , description , editHandlers , isHovered , sx
|
|
|
105
106
|
action: action,
|
|
106
107
|
sx: (0, _components.combineSx)((theme)=>({
|
|
107
108
|
padding: theme.spacing(1),
|
|
108
|
-
borderBottom: `solid 1px ${theme.palette.divider}
|
|
109
|
+
borderBottom: `solid 1px ${theme.palette.divider}`,
|
|
110
|
+
'.MuiCardHeader-content': {
|
|
111
|
+
overflow: 'hidden'
|
|
112
|
+
}
|
|
109
113
|
}), sx),
|
|
110
114
|
...rest
|
|
111
115
|
});
|
|
@@ -70,6 +70,29 @@ describe('Panel Drawer', ()=>{
|
|
|
70
70
|
}
|
|
71
71
|
});
|
|
72
72
|
});
|
|
73
|
+
it('should add panel with duplicate panel name', async ()=>{
|
|
74
|
+
const storeApi = renderPanelDrawer();
|
|
75
|
+
(0, _testUtils.act)(()=>storeApi.getState().openAddPanel());
|
|
76
|
+
const nameInput = await _react.screen.findByLabelText(/Name/);
|
|
77
|
+
_userEvent.default.type(nameInput, 'cpu');
|
|
78
|
+
_userEvent.default.click(_react.screen.getByText('Add'));
|
|
79
|
+
const panels = storeApi.getState().panels;
|
|
80
|
+
expect(panels).toMatchObject({
|
|
81
|
+
// make sure we don't have duplicate panel key by appending "-1"
|
|
82
|
+
'cpu-1': {
|
|
83
|
+
kind: 'Panel',
|
|
84
|
+
spec: {
|
|
85
|
+
display: {
|
|
86
|
+
name: 'cpu'
|
|
87
|
+
},
|
|
88
|
+
plugin: {
|
|
89
|
+
kind: '',
|
|
90
|
+
spec: {}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
});
|
|
73
96
|
it('should edit an existing panel', async ()=>{
|
|
74
97
|
const storeApi = renderPanelDrawer();
|
|
75
98
|
// Open the drawer for an existing panel
|
|
@@ -25,8 +25,6 @@ _export(exports, {
|
|
|
25
25
|
TimeRangeControls: ()=>TimeRangeControls
|
|
26
26
|
});
|
|
27
27
|
const _jsxRuntime = require("react/jsx-runtime");
|
|
28
|
-
const _react = require("react");
|
|
29
|
-
const _material = require("@mui/material");
|
|
30
28
|
const _components = require("@perses-dev/components");
|
|
31
29
|
const _core = require("@perses-dev/core");
|
|
32
30
|
const _context = require("../../context");
|
|
@@ -88,58 +86,21 @@ const TIME_OPTIONS = [
|
|
|
88
86
|
];
|
|
89
87
|
function TimeRangeControls() {
|
|
90
88
|
const { timeRange , setTimeRange } = (0, _context.useDashboardTimeRange)();
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
return /*#__PURE__*/ (0, _jsxRuntime.jsxs)(_material.Stack, {
|
|
99
|
-
direction: "row",
|
|
100
|
-
spacing: 1,
|
|
101
|
-
children: [
|
|
102
|
-
/*#__PURE__*/ (0, _jsxRuntime.jsx)(_material.Popover, {
|
|
103
|
-
anchorEl: anchorEl.current,
|
|
104
|
-
anchorOrigin: {
|
|
105
|
-
vertical: 'bottom',
|
|
106
|
-
horizontal: 'center'
|
|
89
|
+
const defaultTimeRange = (0, _context.useDefaultTimeRange)();
|
|
90
|
+
// add time shortcut if one does not match duration from dashboard JSON
|
|
91
|
+
if (!TIME_OPTIONS.some((option)=>option.value.pastDuration === defaultTimeRange.pastDuration)) {
|
|
92
|
+
if ((0, _core.isDurationString)(defaultTimeRange.pastDuration)) {
|
|
93
|
+
TIME_OPTIONS.push({
|
|
94
|
+
value: {
|
|
95
|
+
pastDuration: defaultTimeRange.pastDuration
|
|
107
96
|
},
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
setTimeRange(timeRange);
|
|
117
|
-
setShowCustomDateSelector(false);
|
|
118
|
-
}
|
|
119
|
-
})
|
|
120
|
-
}),
|
|
121
|
-
/*#__PURE__*/ (0, _jsxRuntime.jsx)(_material.FormControl, {
|
|
122
|
-
fullWidth: true,
|
|
123
|
-
children: /*#__PURE__*/ (0, _jsxRuntime.jsx)(_material.Box, {
|
|
124
|
-
ref: anchorEl,
|
|
125
|
-
children: /*#__PURE__*/ (0, _jsxRuntime.jsx)(_components.TimeRangeSelector, {
|
|
126
|
-
timeOptions: TIME_OPTIONS,
|
|
127
|
-
value: timeRange,
|
|
128
|
-
onSelectChange: (event)=>{
|
|
129
|
-
const duration = event.target.value;
|
|
130
|
-
const relativeTimeInput = {
|
|
131
|
-
pastDuration: duration,
|
|
132
|
-
end: new Date()
|
|
133
|
-
};
|
|
134
|
-
setTimeRange(relativeTimeInput);
|
|
135
|
-
setShowCustomDateSelector(false);
|
|
136
|
-
},
|
|
137
|
-
onCustomClick: ()=>{
|
|
138
|
-
setShowCustomDateSelector(true);
|
|
139
|
-
}
|
|
140
|
-
})
|
|
141
|
-
})
|
|
142
|
-
})
|
|
143
|
-
]
|
|
97
|
+
display: `Last ${defaultTimeRange.pastDuration}`
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return /*#__PURE__*/ (0, _jsxRuntime.jsx)(_components.DateTimeRangePicker, {
|
|
102
|
+
timeOptions: TIME_OPTIONS,
|
|
103
|
+
value: timeRange,
|
|
104
|
+
onChange: setTimeRange
|
|
144
105
|
});
|
|
145
106
|
}
|
|
@@ -45,29 +45,45 @@ describe('TimeRangeControls', ()=>{
|
|
|
45
45
|
dashboardResource: _testDashboard.default
|
|
46
46
|
};
|
|
47
47
|
});
|
|
48
|
-
const renderTimeRangeControls = ()=>{
|
|
48
|
+
const renderTimeRangeControls = (testURLParams)=>{
|
|
49
49
|
(0, _test.renderWithContext)(/*#__PURE__*/ (0, _jsxRuntime.jsx)(_context.DashboardProvider, {
|
|
50
50
|
initialState: initialState,
|
|
51
51
|
children: /*#__PURE__*/ (0, _jsxRuntime.jsx)(_context.TimeRangeProvider, {
|
|
52
|
-
|
|
52
|
+
initialTimeRange: testDefaultTimeRange,
|
|
53
|
+
enabledURLParams: testURLParams,
|
|
53
54
|
children: /*#__PURE__*/ (0, _jsxRuntime.jsx)(_timeRangeControls.TimeRangeControls, {})
|
|
54
55
|
})
|
|
55
56
|
}), undefined, history);
|
|
56
57
|
};
|
|
57
|
-
it('should
|
|
58
|
-
renderTimeRangeControls();
|
|
59
|
-
expect(_react.screen.getByText('Last
|
|
60
|
-
});
|
|
61
|
-
// TODO: fix setTimeRange no-op, test query params
|
|
62
|
-
it('should be able to select the first option', ()=>{
|
|
63
|
-
renderTimeRangeControls();
|
|
58
|
+
it('should default to dashboard duration and update selected time option when clicked', async ()=>{
|
|
59
|
+
renderTimeRangeControls(false);
|
|
60
|
+
expect(_react.screen.getByText('Last 30 minutes')).toBeInTheDocument();
|
|
64
61
|
const dateButton = _react.screen.getByRole('button');
|
|
65
62
|
_userEvent.default.click(dateButton);
|
|
66
|
-
const
|
|
63
|
+
const firstSelected = _react.screen.getByRole('option', {
|
|
67
64
|
name: 'Last 5 minutes'
|
|
68
65
|
});
|
|
69
|
-
_userEvent.default.click(
|
|
66
|
+
_userEvent.default.click(firstSelected);
|
|
70
67
|
expect(dateButton).toHaveTextContent(/5 minutes/i);
|
|
71
68
|
});
|
|
69
|
+
it('should update URL params with correct time range values', ()=>{
|
|
70
|
+
renderTimeRangeControls(true);
|
|
71
|
+
const dateButton = _react.screen.getByRole('button');
|
|
72
|
+
_userEvent.default.click(dateButton);
|
|
73
|
+
const firstSelected = _react.screen.getByRole('option', {
|
|
74
|
+
name: 'Last 5 minutes'
|
|
75
|
+
});
|
|
76
|
+
_userEvent.default.click(firstSelected);
|
|
77
|
+
expect(history.location.search).toEqual('?start=5m');
|
|
78
|
+
// pick another option from TimeRangeSelector dropdown
|
|
79
|
+
const secondSelected = _react.screen.getByText('Last 12 hours');
|
|
80
|
+
_userEvent.default.click(secondSelected);
|
|
81
|
+
expect(history.location.search).toEqual('?start=12h');
|
|
82
|
+
// back button should return to first option selected
|
|
83
|
+
(0, _react.act)(()=>{
|
|
84
|
+
history.back();
|
|
85
|
+
});
|
|
86
|
+
expect(history.location.search).toEqual('?start=5m');
|
|
87
|
+
});
|
|
72
88
|
// TODO: add additional tests for absolute time selection, other inputs, form validation, etc.
|
|
73
89
|
});
|
|
@@ -57,16 +57,24 @@ function ListVariable({ name }) {
|
|
|
57
57
|
const { data: variablePlugin } = (0, _pluginSystem.usePlugin)('Variable', definition.spec.plugin.kind);
|
|
58
58
|
const { setVariableValue , setVariableLoading , setVariableOptions } = (0, _context.useTemplateVariableActions)();
|
|
59
59
|
const datasourceStore = (0, _pluginSystem.useDatasourceStore)();
|
|
60
|
+
const allVariables = (0, _pluginSystem.useTemplateVariableValues)();
|
|
61
|
+
const { timeRange } = (0, _pluginSystem.useTimeRange)();
|
|
62
|
+
const variablePluginCtx = {
|
|
63
|
+
timeRange,
|
|
64
|
+
datasourceStore,
|
|
65
|
+
variables: allVariables
|
|
66
|
+
};
|
|
60
67
|
const spec = definition.spec.plugin.spec;
|
|
61
68
|
let dependsOnVariables;
|
|
62
69
|
if (variablePlugin === null || variablePlugin === void 0 ? void 0 : variablePlugin.dependsOn) {
|
|
63
|
-
|
|
70
|
+
const dependencies = variablePlugin.dependsOn(spec, variablePluginCtx);
|
|
71
|
+
dependsOnVariables = dependencies.variables;
|
|
64
72
|
}
|
|
65
73
|
const variables = (0, _pluginSystem.useTemplateVariableValues)(dependsOnVariables);
|
|
66
74
|
const allowMultiple = (definition === null || definition === void 0 ? void 0 : definition.spec.allow_multiple) === true;
|
|
67
75
|
const allowAllValue = (definition === null || definition === void 0 ? void 0 : definition.spec.allow_all_value) === true;
|
|
68
76
|
var ref4;
|
|
69
|
-
const
|
|
77
|
+
const title = (ref4 = (ref = definition === null || definition === void 0 ? void 0 : definition.spec.display) === null || ref === void 0 ? void 0 : ref.name) !== null && ref4 !== void 0 ? ref4 : name;
|
|
70
78
|
let waitToLoad = false;
|
|
71
79
|
if (dependsOnVariables) {
|
|
72
80
|
waitToLoad = dependsOnVariables.some((v)=>{
|
|
@@ -75,7 +83,6 @@ function ListVariable({ name }) {
|
|
|
75
83
|
});
|
|
76
84
|
}
|
|
77
85
|
const variablesValueKey = getVariableValuesKey(variables);
|
|
78
|
-
const { timeRange } = (0, _pluginSystem.useTimeRange)();
|
|
79
86
|
const variablesOptionsQuery = (0, _reactQuery.useQuery)([
|
|
80
87
|
name,
|
|
81
88
|
definition,
|
|
@@ -165,7 +172,7 @@ function ListVariable({ name }) {
|
|
|
165
172
|
children: [
|
|
166
173
|
/*#__PURE__*/ (0, _jsxRuntime.jsx)(_material.InputLabel, {
|
|
167
174
|
id: name,
|
|
168
|
-
children:
|
|
175
|
+
children: title
|
|
169
176
|
}),
|
|
170
177
|
/*#__PURE__*/ (0, _jsxRuntime.jsxs)(_material.Select, {
|
|
171
178
|
sx: {
|
|
@@ -192,6 +199,11 @@ function ListVariable({ name }) {
|
|
|
192
199
|
disabled: true,
|
|
193
200
|
children: "Loading"
|
|
194
201
|
}),
|
|
202
|
+
finalOptions.length === 0 && /*#__PURE__*/ (0, _jsxRuntime.jsx)(_material.MenuItem, {
|
|
203
|
+
value: "empty",
|
|
204
|
+
disabled: true,
|
|
205
|
+
children: "No options"
|
|
206
|
+
}),
|
|
195
207
|
finalOptions.map((option)=>/*#__PURE__*/ (0, _jsxRuntime.jsx)(_material.MenuItem, {
|
|
196
208
|
value: option.value,
|
|
197
209
|
children: option.label
|
|
@@ -32,9 +32,24 @@ function _interopRequireDefault(obj) {
|
|
|
32
32
|
default: obj
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
|
+
function getValidation(variableDefinitions) {
|
|
36
|
+
const errors = [];
|
|
37
|
+
/** Variable names must be unique */ const variableNames = variableDefinitions.map((variableDefinition)=>variableDefinition.spec.name);
|
|
38
|
+
const uniqueVariableNames = new Set(variableNames);
|
|
39
|
+
if (variableNames.length !== uniqueVariableNames.size) {
|
|
40
|
+
errors.push('Variable names must be unique');
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
errors: errors,
|
|
44
|
+
isValid: errors.length === 0
|
|
45
|
+
};
|
|
46
|
+
}
|
|
35
47
|
function VariableEditor(props) {
|
|
36
48
|
const [variableDefinitions, setVariableDefinitions] = (0, _useImmer.useImmer)(props.variableDefinitions);
|
|
37
49
|
const [variableEditIdx, setVariableEditIdx] = (0, _react.useState)(null);
|
|
50
|
+
const validation = (0, _react.useMemo)(()=>getValidation(variableDefinitions), [
|
|
51
|
+
variableDefinitions
|
|
52
|
+
]);
|
|
38
53
|
const currentEditingVariableDefinition = typeof variableEditIdx === 'number' && variableDefinitions[variableEditIdx];
|
|
39
54
|
const removeVariable = (index)=>{
|
|
40
55
|
setVariableDefinitions((draft)=>{
|
|
@@ -60,6 +75,7 @@ function VariableEditor(props) {
|
|
|
60
75
|
}
|
|
61
76
|
if (!v.spec.display) {
|
|
62
77
|
v.spec.display = {
|
|
78
|
+
name: v.spec.name,
|
|
63
79
|
hidden: false
|
|
64
80
|
};
|
|
65
81
|
}
|
|
@@ -117,7 +133,7 @@ function VariableEditor(props) {
|
|
|
117
133
|
justifyContent: "end",
|
|
118
134
|
children: [
|
|
119
135
|
/*#__PURE__*/ (0, _jsxRuntime.jsx)(_material.Button, {
|
|
120
|
-
disabled: props.variableDefinitions === variableDefinitions,
|
|
136
|
+
disabled: props.variableDefinitions === variableDefinitions || !validation.isValid,
|
|
121
137
|
variant: "contained",
|
|
122
138
|
onClick: ()=>{
|
|
123
139
|
props.onChange(variableDefinitions);
|
|
@@ -141,6 +157,10 @@ function VariableEditor(props) {
|
|
|
141
157
|
/*#__PURE__*/ (0, _jsxRuntime.jsxs)(_material.Stack, {
|
|
142
158
|
spacing: 2,
|
|
143
159
|
children: [
|
|
160
|
+
!validation.isValid && validation.errors.map((error)=>/*#__PURE__*/ (0, _jsxRuntime.jsx)(_material.Alert, {
|
|
161
|
+
severity: "error",
|
|
162
|
+
children: error
|
|
163
|
+
}, error)),
|
|
144
164
|
/*#__PURE__*/ (0, _jsxRuntime.jsx)(_material.TableContainer, {
|
|
145
165
|
component: _material.Paper,
|
|
146
166
|
children: /*#__PURE__*/ (0, _jsxRuntime.jsxs)(_material.Table, {
|
|
@@ -19,20 +19,69 @@ Object.defineProperty(exports, "VariableEditForm", {
|
|
|
19
19
|
get: ()=>VariableEditForm
|
|
20
20
|
});
|
|
21
21
|
const _jsxRuntime = require("react/jsx-runtime");
|
|
22
|
-
const _react = /*#__PURE__*/
|
|
22
|
+
const _react = /*#__PURE__*/ _interopRequireWildcard(require("react"));
|
|
23
23
|
const _material = require("@mui/material");
|
|
24
24
|
const _useImmer = require("use-immer");
|
|
25
25
|
const _pluginSystem = require("@perses-dev/plugin-system");
|
|
26
26
|
const _variableEditorFormModel = require("./variable-editor-form-model");
|
|
27
|
-
function
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
function _getRequireWildcardCache(nodeInterop) {
|
|
28
|
+
if (typeof WeakMap !== "function") return null;
|
|
29
|
+
var cacheBabelInterop = new WeakMap();
|
|
30
|
+
var cacheNodeInterop = new WeakMap();
|
|
31
|
+
return (_getRequireWildcardCache = function(nodeInterop) {
|
|
32
|
+
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|
33
|
+
})(nodeInterop);
|
|
34
|
+
}
|
|
35
|
+
function _interopRequireWildcard(obj, nodeInterop) {
|
|
36
|
+
if (!nodeInterop && obj && obj.__esModule) {
|
|
37
|
+
return obj;
|
|
38
|
+
}
|
|
39
|
+
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
|
40
|
+
return {
|
|
41
|
+
default: obj
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
var cache = _getRequireWildcardCache(nodeInterop);
|
|
45
|
+
if (cache && cache.has(obj)) {
|
|
46
|
+
return cache.get(obj);
|
|
47
|
+
}
|
|
48
|
+
var newObj = {};
|
|
49
|
+
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|
50
|
+
for(var key in obj){
|
|
51
|
+
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
52
|
+
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
|
53
|
+
if (desc && (desc.get || desc.set)) {
|
|
54
|
+
Object.defineProperty(newObj, key, desc);
|
|
55
|
+
} else {
|
|
56
|
+
newObj[key] = obj[key];
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
newObj.default = obj;
|
|
61
|
+
if (cache) {
|
|
62
|
+
cache.set(obj, newObj);
|
|
63
|
+
}
|
|
64
|
+
return newObj;
|
|
31
65
|
}
|
|
32
66
|
const VARIABLE_TYPES = [
|
|
33
67
|
'ListVariable',
|
|
34
68
|
'TextVariable'
|
|
35
69
|
];
|
|
70
|
+
// TODO: Replace with proper validation library
|
|
71
|
+
function getValidation(state) {
|
|
72
|
+
/** Name validation */ let name = null;
|
|
73
|
+
if (!state.name) {
|
|
74
|
+
name = 'Name is required';
|
|
75
|
+
}
|
|
76
|
+
// name can only contain alphanumeric characters and underscores and no spaces
|
|
77
|
+
if (state.name && !/^[a-zA-Z0-9_-]+$/.test(state.name)) {
|
|
78
|
+
name = 'Name can only contain alphanumeric characters, underscores, and dashes';
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
name,
|
|
82
|
+
isValid: !name
|
|
83
|
+
};
|
|
84
|
+
}
|
|
36
85
|
const SectionHeader = ({ children })=>/*#__PURE__*/ (0, _jsxRuntime.jsx)(_material.Typography, {
|
|
37
86
|
pb: 2,
|
|
38
87
|
variant: "subtitle1",
|
|
@@ -40,6 +89,9 @@ const SectionHeader = ({ children })=>/*#__PURE__*/ (0, _jsxRuntime.jsx)(_mater
|
|
|
40
89
|
});
|
|
41
90
|
function VariableEditForm({ initialVariableDefinition , onChange , onCancel }) {
|
|
42
91
|
const [state, setState] = (0, _useImmer.useImmer)((0, _variableEditorFormModel.getInitialState)(initialVariableDefinition));
|
|
92
|
+
const validation = (0, _react.useMemo)(()=>getValidation(state), [
|
|
93
|
+
state
|
|
94
|
+
]);
|
|
43
95
|
return /*#__PURE__*/ (0, _jsxRuntime.jsxs)(_material.Box, {
|
|
44
96
|
children: [
|
|
45
97
|
/*#__PURE__*/ (0, _jsxRuntime.jsx)(SectionHeader, {
|
|
@@ -54,9 +106,12 @@ function VariableEditForm({ initialVariableDefinition , onChange , onCancel })
|
|
|
54
106
|
item: true,
|
|
55
107
|
xs: 6,
|
|
56
108
|
children: /*#__PURE__*/ (0, _jsxRuntime.jsx)(_material.TextField, {
|
|
109
|
+
required: true,
|
|
110
|
+
error: !!validation.name,
|
|
57
111
|
fullWidth: true,
|
|
58
112
|
label: "Name",
|
|
59
113
|
value: state.name,
|
|
114
|
+
helperText: validation.name,
|
|
60
115
|
onChange: (v)=>{
|
|
61
116
|
setState((draft)=>{
|
|
62
117
|
draft.name = v.target.value;
|
|
@@ -98,10 +153,10 @@ function VariableEditForm({ initialVariableDefinition , onChange , onCancel })
|
|
|
98
153
|
children: /*#__PURE__*/ (0, _jsxRuntime.jsx)(_material.TextField, {
|
|
99
154
|
fullWidth: true,
|
|
100
155
|
label: "Label",
|
|
101
|
-
value: state.
|
|
156
|
+
value: state.title,
|
|
102
157
|
onChange: (v)=>{
|
|
103
158
|
setState((draft)=>{
|
|
104
|
-
draft.
|
|
159
|
+
draft.title = v.target.value;
|
|
105
160
|
});
|
|
106
161
|
}
|
|
107
162
|
})
|
|
@@ -220,6 +275,7 @@ function VariableEditForm({ initialVariableDefinition , onChange , onCancel })
|
|
|
220
275
|
justifyContent: "end",
|
|
221
276
|
children: [
|
|
222
277
|
/*#__PURE__*/ (0, _jsxRuntime.jsx)(_material.Button, {
|
|
278
|
+
disabled: !validation.isValid,
|
|
223
279
|
variant: "contained",
|
|
224
280
|
onClick: ()=>{
|
|
225
281
|
onChange((0, _variableEditorFormModel.getVariableDefinitionFromState)(state));
|
|
@@ -47,7 +47,7 @@ function getInitialState(initialVariableDefinition) {
|
|
|
47
47
|
}
|
|
48
48
|
return {
|
|
49
49
|
name: initialVariableDefinition.spec.name,
|
|
50
|
-
|
|
50
|
+
title: (ref = initialVariableDefinition.spec.display) === null || ref === void 0 ? void 0 : ref.name,
|
|
51
51
|
kind: initialVariableDefinition.kind,
|
|
52
52
|
description: '',
|
|
53
53
|
listVariableFields,
|
|
@@ -55,11 +55,11 @@ function getInitialState(initialVariableDefinition) {
|
|
|
55
55
|
};
|
|
56
56
|
}
|
|
57
57
|
function getVariableDefinitionFromState(state) {
|
|
58
|
-
const { name ,
|
|
58
|
+
const { name , title , kind } = state;
|
|
59
59
|
const commonSpec = {
|
|
60
60
|
name,
|
|
61
61
|
display: {
|
|
62
|
-
|
|
62
|
+
name: title
|
|
63
63
|
}
|
|
64
64
|
};
|
|
65
65
|
if (kind === 'TextVariable') {
|