@perses-dev/plugin-system 0.39.0 → 0.40.1

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.
Files changed (253) hide show
  1. package/dist/cjs/components/CalculationSelector/CalculationSelector.js +6 -4
  2. package/dist/cjs/components/CalculationSelector/index.js +10 -8
  3. package/dist/cjs/components/DatasourceEditorForm/DatasourceEditorForm.js +381 -0
  4. package/dist/cjs/components/DatasourceEditorForm/index.js +30 -0
  5. package/dist/cjs/components/DatasourceSelect.js +119 -21
  6. package/dist/cjs/components/LegendOptionsEditor/LegendOptionsEditor.js +18 -16
  7. package/dist/cjs/components/LegendOptionsEditor/index.js +10 -8
  8. package/dist/cjs/components/OptionsEditorRadios/OptionsEditorRadios.js +23 -28
  9. package/dist/cjs/components/OptionsEditorRadios/index.js +10 -8
  10. package/dist/cjs/components/OptionsEditorTabPanel/OptionsEditorTabPanel.js +6 -4
  11. package/dist/cjs/components/OptionsEditorTabPanel/index.js +10 -8
  12. package/dist/cjs/components/OptionsEditorTabs/OptionsEditorTabs.js +10 -8
  13. package/dist/cjs/components/OptionsEditorTabs/index.js +10 -8
  14. package/dist/cjs/components/PanelSpecEditor/PanelSpecEditor.js +13 -11
  15. package/dist/cjs/components/PanelSpecEditor/index.js +10 -8
  16. package/dist/cjs/components/PluginEditor/PluginEditor.js +24 -31
  17. package/dist/cjs/components/PluginEditor/index.js +11 -9
  18. package/dist/cjs/components/PluginEditor/plugin-editor-api.js +5 -3
  19. package/dist/cjs/components/PluginKindSelect/PluginKindSelect.js +23 -12
  20. package/dist/cjs/components/PluginKindSelect/index.js +10 -8
  21. package/dist/cjs/components/PluginRegistry/PluginRegistry.js +11 -9
  22. package/dist/cjs/components/PluginRegistry/index.js +10 -8
  23. package/dist/cjs/components/PluginRegistry/plugin-indexes.js +6 -2
  24. package/dist/cjs/components/PluginSpecEditor/PluginSpecEditor.js +6 -4
  25. package/dist/cjs/components/PluginSpecEditor/index.js +10 -8
  26. package/dist/cjs/components/TimeSeriesQueryEditor/TimeSeriesQueryEditor.js +15 -13
  27. package/dist/cjs/components/TimeSeriesQueryEditor/TimeSeriesQueryInput.js +21 -19
  28. package/dist/cjs/components/TimeSeriesQueryEditor/index.js +10 -8
  29. package/dist/cjs/components/Variables/VariableEditorForm/VariableEditorForm.js +257 -166
  30. package/dist/cjs/components/Variables/VariableEditorForm/VariablePreview.js +32 -28
  31. package/dist/cjs/components/Variables/VariableEditorForm/index.js +11 -9
  32. package/dist/cjs/components/Variables/VariableEditorForm/variable-editor-form-model.js +28 -32
  33. package/dist/cjs/components/Variables/index.js +11 -9
  34. package/dist/cjs/components/Variables/variable-model.js +17 -9
  35. package/dist/cjs/components/index.js +22 -19
  36. package/dist/cjs/constants/index.js +10 -8
  37. package/dist/cjs/constants/user-interface-text.js +3 -1
  38. package/dist/cjs/index.js +16 -13
  39. package/dist/cjs/model/index.js +17 -15
  40. package/dist/cjs/model/legend.js +32 -20
  41. package/dist/cjs/model/panels.js +2 -2
  42. package/dist/cjs/model/plugin-base.js +2 -2
  43. package/dist/cjs/model/plugin-loading.js +3 -1
  44. package/dist/cjs/runtime/DataQueriesProvider/DataQueriesProvider.js +19 -11
  45. package/dist/cjs/runtime/DataQueriesProvider/index.js +11 -9
  46. package/dist/cjs/runtime/DataQueriesProvider/model.js +12 -8
  47. package/dist/cjs/runtime/TimeRangeProvider/TimeRangeProvider.js +19 -11
  48. package/dist/cjs/runtime/TimeRangeProvider/index.js +11 -9
  49. package/dist/cjs/runtime/TimeRangeProvider/query-params.js +36 -18
  50. package/dist/cjs/runtime/builtin-variables.js +81 -0
  51. package/dist/cjs/runtime/datasources.js +29 -11
  52. package/dist/cjs/runtime/index.js +16 -13
  53. package/dist/cjs/runtime/plugin-registry.js +41 -11
  54. package/dist/cjs/runtime/template-variables.js +42 -12
  55. package/dist/cjs/runtime/time-series-queries.js +39 -27
  56. package/dist/cjs/stories/shared-utils/decorators/WithDataQueries.js +7 -5
  57. package/dist/cjs/stories/shared-utils/decorators/WithPluginRegistry.js +16 -14
  58. package/dist/cjs/stories/shared-utils/decorators/WithPluginSystemBuiltinVariables.js +42 -0
  59. package/dist/cjs/stories/shared-utils/decorators/WithPluginSystemDatasourceStore.js +19 -13
  60. package/dist/cjs/stories/shared-utils/decorators/WithPluginSystemTemplateVariables.js +6 -4
  61. package/dist/cjs/stories/shared-utils/decorators/WithTimeRange.js +7 -5
  62. package/dist/cjs/stories/shared-utils/decorators/index.js +15 -12
  63. package/dist/cjs/stories/shared-utils/index.js +10 -8
  64. package/dist/cjs/test/index.js +11 -9
  65. package/dist/cjs/test/mock-data.js +3 -1
  66. package/dist/cjs/test/render.js +13 -11
  67. package/dist/cjs/test/test-plugins/bert/index.js +14 -10
  68. package/dist/cjs/test/test-plugins/ernie/index.js +13 -9
  69. package/dist/cjs/test/test-plugins/index.js +11 -9
  70. package/dist/cjs/test-utils/index.js +10 -8
  71. package/dist/cjs/test-utils/mock-plugin-registry.js +8 -4
  72. package/dist/cjs/utils/action.js +43 -0
  73. package/dist/cjs/utils/index.js +11 -8
  74. package/dist/cjs/utils/variables.js +26 -8
  75. package/dist/cjs/validation/datasource.js +30 -0
  76. package/dist/cjs/validation/index.js +32 -0
  77. package/dist/cjs/validation/resource.js +24 -0
  78. package/dist/cjs/validation/variable.js +29 -0
  79. package/dist/components/CalculationSelector/CalculationSelector.js.map +1 -1
  80. package/dist/components/CalculationSelector/index.js.map +1 -1
  81. package/dist/components/DatasourceEditorForm/DatasourceEditorForm.d.ts +15 -0
  82. package/dist/components/DatasourceEditorForm/DatasourceEditorForm.d.ts.map +1 -0
  83. package/dist/components/DatasourceEditorForm/DatasourceEditorForm.js +334 -0
  84. package/dist/components/DatasourceEditorForm/DatasourceEditorForm.js.map +1 -0
  85. package/dist/components/DatasourceEditorForm/index.d.ts +2 -0
  86. package/dist/components/DatasourceEditorForm/index.d.ts.map +1 -0
  87. package/dist/components/DatasourceEditorForm/index.js +15 -0
  88. package/dist/components/DatasourceEditorForm/index.js.map +1 -0
  89. package/dist/components/DatasourceSelect.d.ts +5 -0
  90. package/dist/components/DatasourceSelect.d.ts.map +1 -1
  91. package/dist/components/DatasourceSelect.js +102 -19
  92. package/dist/components/DatasourceSelect.js.map +1 -1
  93. package/dist/components/LegendOptionsEditor/LegendOptionsEditor.js +2 -2
  94. package/dist/components/LegendOptionsEditor/LegendOptionsEditor.js.map +1 -1
  95. package/dist/components/LegendOptionsEditor/index.js.map +1 -1
  96. package/dist/components/OptionsEditorRadios/OptionsEditorRadios.d.ts +2 -2
  97. package/dist/components/OptionsEditorRadios/OptionsEditorRadios.d.ts.map +1 -1
  98. package/dist/components/OptionsEditorRadios/OptionsEditorRadios.js +16 -23
  99. package/dist/components/OptionsEditorRadios/OptionsEditorRadios.js.map +1 -1
  100. package/dist/components/OptionsEditorRadios/index.js.map +1 -1
  101. package/dist/components/OptionsEditorTabPanel/OptionsEditorTabPanel.js.map +1 -1
  102. package/dist/components/OptionsEditorTabPanel/index.js.map +1 -1
  103. package/dist/components/OptionsEditorTabs/OptionsEditorTabs.js.map +1 -1
  104. package/dist/components/OptionsEditorTabs/index.js.map +1 -1
  105. package/dist/components/PanelSpecEditor/PanelSpecEditor.js +2 -2
  106. package/dist/components/PanelSpecEditor/PanelSpecEditor.js.map +1 -1
  107. package/dist/components/PanelSpecEditor/index.js.map +1 -1
  108. package/dist/components/PluginEditor/PluginEditor.js +15 -24
  109. package/dist/components/PluginEditor/PluginEditor.js.map +1 -1
  110. package/dist/components/PluginEditor/index.js.map +1 -1
  111. package/dist/components/PluginEditor/plugin-editor-api.d.ts +1 -1
  112. package/dist/components/PluginEditor/plugin-editor-api.js +2 -2
  113. package/dist/components/PluginEditor/plugin-editor-api.js.map +1 -1
  114. package/dist/components/PluginKindSelect/PluginKindSelect.d.ts +3 -3
  115. package/dist/components/PluginKindSelect/PluginKindSelect.d.ts.map +1 -1
  116. package/dist/components/PluginKindSelect/PluginKindSelect.js +21 -12
  117. package/dist/components/PluginKindSelect/PluginKindSelect.js.map +1 -1
  118. package/dist/components/PluginKindSelect/index.js.map +1 -1
  119. package/dist/components/PluginRegistry/PluginRegistry.js +3 -3
  120. package/dist/components/PluginRegistry/PluginRegistry.js.map +1 -1
  121. package/dist/components/PluginRegistry/index.js.map +1 -1
  122. package/dist/components/PluginRegistry/plugin-indexes.js.map +1 -1
  123. package/dist/components/PluginSpecEditor/PluginSpecEditor.js.map +1 -1
  124. package/dist/components/PluginSpecEditor/index.js.map +1 -1
  125. package/dist/components/TimeSeriesQueryEditor/TimeSeriesQueryEditor.js +4 -4
  126. package/dist/components/TimeSeriesQueryEditor/TimeSeriesQueryEditor.js.map +1 -1
  127. package/dist/components/TimeSeriesQueryEditor/TimeSeriesQueryInput.js +1 -1
  128. package/dist/components/TimeSeriesQueryEditor/TimeSeriesQueryInput.js.map +1 -1
  129. package/dist/components/TimeSeriesQueryEditor/index.js.map +1 -1
  130. package/dist/components/Variables/VariableEditorForm/VariableEditorForm.d.ts +10 -7
  131. package/dist/components/Variables/VariableEditorForm/VariableEditorForm.d.ts.map +1 -1
  132. package/dist/components/Variables/VariableEditorForm/VariableEditorForm.js +201 -112
  133. package/dist/components/Variables/VariableEditorForm/VariableEditorForm.js.map +1 -1
  134. package/dist/components/Variables/VariableEditorForm/VariablePreview.js.map +1 -1
  135. package/dist/components/Variables/VariableEditorForm/index.js.map +1 -1
  136. package/dist/components/Variables/VariableEditorForm/variable-editor-form-model.d.ts +5 -4
  137. package/dist/components/Variables/VariableEditorForm/variable-editor-form-model.d.ts.map +1 -1
  138. package/dist/components/Variables/VariableEditorForm/variable-editor-form-model.js +22 -30
  139. package/dist/components/Variables/VariableEditorForm/variable-editor-form-model.js.map +1 -1
  140. package/dist/components/Variables/index.js.map +1 -1
  141. package/dist/components/Variables/variable-model.js +3 -3
  142. package/dist/components/Variables/variable-model.js.map +1 -1
  143. package/dist/components/index.d.ts +1 -0
  144. package/dist/components/index.d.ts.map +1 -1
  145. package/dist/components/index.js +1 -0
  146. package/dist/components/index.js.map +1 -1
  147. package/dist/constants/index.js.map +1 -1
  148. package/dist/constants/user-interface-text.js.map +1 -1
  149. package/dist/index.d.ts +1 -0
  150. package/dist/index.d.ts.map +1 -1
  151. package/dist/index.js +1 -0
  152. package/dist/index.js.map +1 -1
  153. package/dist/model/datasource.d.ts +2 -1
  154. package/dist/model/datasource.d.ts.map +1 -1
  155. package/dist/model/datasource.js.map +1 -1
  156. package/dist/model/index.js.map +1 -1
  157. package/dist/model/legend.d.ts +1 -1
  158. package/dist/model/legend.d.ts.map +1 -1
  159. package/dist/model/legend.js +14 -14
  160. package/dist/model/legend.js.map +1 -1
  161. package/dist/model/panels.js.map +1 -1
  162. package/dist/model/plugin-base.js.map +1 -1
  163. package/dist/model/plugin-loading.js.map +1 -1
  164. package/dist/runtime/DataQueriesProvider/DataQueriesProvider.js +4 -4
  165. package/dist/runtime/DataQueriesProvider/DataQueriesProvider.js.map +1 -1
  166. package/dist/runtime/DataQueriesProvider/index.js.map +1 -1
  167. package/dist/runtime/DataQueriesProvider/model.d.ts +3 -2
  168. package/dist/runtime/DataQueriesProvider/model.d.ts.map +1 -1
  169. package/dist/runtime/DataQueriesProvider/model.js +4 -4
  170. package/dist/runtime/DataQueriesProvider/model.js.map +1 -1
  171. package/dist/runtime/TimeRangeProvider/TimeRangeProvider.js.map +1 -1
  172. package/dist/runtime/TimeRangeProvider/index.js.map +1 -1
  173. package/dist/runtime/TimeRangeProvider/query-params.js +1 -1
  174. package/dist/runtime/TimeRangeProvider/query-params.js.map +1 -1
  175. package/dist/runtime/builtin-variables.d.ts +11 -0
  176. package/dist/runtime/builtin-variables.d.ts.map +1 -0
  177. package/dist/runtime/builtin-variables.js +59 -0
  178. package/dist/runtime/builtin-variables.js.map +1 -0
  179. package/dist/runtime/datasources.d.ts +14 -6
  180. package/dist/runtime/datasources.d.ts.map +1 -1
  181. package/dist/runtime/datasources.js +13 -6
  182. package/dist/runtime/datasources.js.map +1 -1
  183. package/dist/runtime/index.d.ts +1 -0
  184. package/dist/runtime/index.d.ts.map +1 -1
  185. package/dist/runtime/index.js +1 -0
  186. package/dist/runtime/index.js.map +1 -1
  187. package/dist/runtime/plugin-registry.d.ts +2 -0
  188. package/dist/runtime/plugin-registry.d.ts.map +1 -1
  189. package/dist/runtime/plugin-registry.js +19 -2
  190. package/dist/runtime/plugin-registry.js.map +1 -1
  191. package/dist/runtime/template-variables.d.ts +2 -1
  192. package/dist/runtime/template-variables.d.ts.map +1 -1
  193. package/dist/runtime/template-variables.js +27 -8
  194. package/dist/runtime/template-variables.js.map +1 -1
  195. package/dist/runtime/time-series-queries.d.ts +3 -3
  196. package/dist/runtime/time-series-queries.d.ts.map +1 -1
  197. package/dist/runtime/time-series-queries.js +14 -12
  198. package/dist/runtime/time-series-queries.js.map +1 -1
  199. package/dist/stories/shared-utils/decorators/WithDataQueries.js.map +1 -1
  200. package/dist/stories/shared-utils/decorators/WithPluginRegistry.js.map +1 -1
  201. package/dist/stories/shared-utils/decorators/WithPluginSystemBuiltinVariables.d.ts +13 -0
  202. package/dist/stories/shared-utils/decorators/WithPluginSystemBuiltinVariables.d.ts.map +1 -0
  203. package/dist/stories/shared-utils/decorators/WithPluginSystemBuiltinVariables.js +39 -0
  204. package/dist/stories/shared-utils/decorators/WithPluginSystemBuiltinVariables.js.map +1 -0
  205. package/dist/stories/shared-utils/decorators/WithPluginSystemDatasourceStore.d.ts.map +1 -1
  206. package/dist/stories/shared-utils/decorators/WithPluginSystemDatasourceStore.js +11 -7
  207. package/dist/stories/shared-utils/decorators/WithPluginSystemDatasourceStore.js.map +1 -1
  208. package/dist/stories/shared-utils/decorators/WithPluginSystemTemplateVariables.js.map +1 -1
  209. package/dist/stories/shared-utils/decorators/WithTimeRange.js.map +1 -1
  210. package/dist/stories/shared-utils/decorators/index.d.ts +1 -0
  211. package/dist/stories/shared-utils/decorators/index.d.ts.map +1 -1
  212. package/dist/stories/shared-utils/decorators/index.js +1 -0
  213. package/dist/stories/shared-utils/decorators/index.js.map +1 -1
  214. package/dist/stories/shared-utils/index.js.map +1 -1
  215. package/dist/test/index.js.map +1 -1
  216. package/dist/test/mock-data.js.map +1 -1
  217. package/dist/test/render.js +2 -2
  218. package/dist/test/render.js.map +1 -1
  219. package/dist/test/setup-tests.js.map +1 -1
  220. package/dist/test/test-plugins/bert/index.js.map +1 -1
  221. package/dist/test/test-plugins/ernie/index.js.map +1 -1
  222. package/dist/test/test-plugins/index.js.map +1 -1
  223. package/dist/test-utils/index.js.map +1 -1
  224. package/dist/test-utils/mock-plugin-registry.js +2 -2
  225. package/dist/test-utils/mock-plugin-registry.js.map +1 -1
  226. package/dist/utils/action.d.ts +4 -0
  227. package/dist/utils/action.d.ts.map +1 -0
  228. package/dist/utils/action.js +27 -0
  229. package/dist/utils/action.js.map +1 -0
  230. package/dist/utils/index.d.ts +1 -0
  231. package/dist/utils/index.d.ts.map +1 -1
  232. package/dist/utils/index.js +1 -0
  233. package/dist/utils/index.js.map +1 -1
  234. package/dist/utils/variables.d.ts.map +1 -1
  235. package/dist/utils/variables.js +17 -5
  236. package/dist/utils/variables.js.map +1 -1
  237. package/dist/validation/datasource.d.ts +19 -0
  238. package/dist/validation/datasource.d.ts.map +1 -0
  239. package/dist/validation/datasource.js +22 -0
  240. package/dist/validation/datasource.js.map +1 -0
  241. package/dist/validation/index.d.ts +4 -0
  242. package/dist/validation/index.d.ts.map +1 -0
  243. package/dist/validation/index.js +17 -0
  244. package/dist/validation/index.js.map +1 -0
  245. package/dist/validation/resource.d.ts +3 -0
  246. package/dist/validation/resource.d.ts.map +1 -0
  247. package/dist/validation/resource.js +16 -0
  248. package/dist/validation/resource.js.map +1 -0
  249. package/dist/validation/variable.d.ts +19 -0
  250. package/dist/validation/variable.d.ts.map +1 -0
  251. package/dist/validation/variable.js +21 -0
  252. package/dist/validation/variable.js.map +1 -0
  253. package/package.json +8 -6
@@ -0,0 +1,334 @@
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 { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
14
+ import { useImmer } from 'use-immer';
15
+ import { Box, Button, Divider, FormControlLabel, Grid, Stack, Switch, TextField, Typography } from '@mui/material';
16
+ import React, { useCallback, useState } from 'react';
17
+ import { DiscardChangesConfirmationDialog } from '@perses-dev/components';
18
+ import { Controller, FormProvider, useForm } from 'react-hook-form';
19
+ import { zodResolver } from '@hookform/resolvers/zod';
20
+ import { PluginEditor } from '../PluginEditor';
21
+ import { getSubmitText, getTitleAction } from '../../utils';
22
+ import { datasourceEditValidationSchema } from '../../validation';
23
+ /**
24
+ * This preprocessing ensures that we always have a defined object for the `display` property
25
+ * @param datasource
26
+ */ function getInitialState(datasource) {
27
+ var _datasource_spec_display, _datasource_spec_display1;
28
+ var _datasource_spec_display_name, _datasource_spec_display_description;
29
+ const patchedDisplay = {
30
+ name: (_datasource_spec_display_name = (_datasource_spec_display = datasource.spec.display) === null || _datasource_spec_display === void 0 ? void 0 : _datasource_spec_display.name) !== null && _datasource_spec_display_name !== void 0 ? _datasource_spec_display_name : '',
31
+ description: (_datasource_spec_display_description = (_datasource_spec_display1 = datasource.spec.display) === null || _datasource_spec_display1 === void 0 ? void 0 : _datasource_spec_display1.description) !== null && _datasource_spec_display_description !== void 0 ? _datasource_spec_display_description : ''
32
+ };
33
+ return {
34
+ ...datasource,
35
+ spec: {
36
+ ...datasource.spec,
37
+ display: patchedDisplay
38
+ }
39
+ };
40
+ }
41
+ export function DatasourceEditorForm(props) {
42
+ var _state_spec_display, _state_spec_display1;
43
+ const { initialDatasource , initialAction , isDraft , isReadonly , onSave , onClose , onDelete } = props;
44
+ const patchedInitialDatasource = getInitialState(initialDatasource);
45
+ const [state, setState] = useImmer(patchedInitialDatasource);
46
+ const [isDiscardDialogOpened, setDiscardDialogOpened] = useState(false);
47
+ const [action, setAction] = useState(initialAction);
48
+ const titleAction = getTitleAction(action, isDraft);
49
+ const submitText = getSubmitText(action, isDraft);
50
+ const form = useForm({
51
+ resolver: zodResolver(datasourceEditValidationSchema),
52
+ mode: 'onBlur',
53
+ defaultValues: {
54
+ name: state.metadata.name,
55
+ title: (_state_spec_display = state.spec.display) === null || _state_spec_display === void 0 ? void 0 : _state_spec_display.name,
56
+ description: (_state_spec_display1 = state.spec.display) === null || _state_spec_display1 === void 0 ? void 0 : _state_spec_display1.description,
57
+ default: state.spec.default
58
+ }
59
+ });
60
+ const processForm = ()=>{
61
+ onSave(state);
62
+ };
63
+ // When user click on cancel, several possibilities:
64
+ // - create action: ask for discard approval
65
+ // - update action: ask for discard approval if changed
66
+ // - read action: don´t ask for discard approval
67
+ const handleCancel = useCallback(()=>{
68
+ if (JSON.stringify(patchedInitialDatasource) !== JSON.stringify(state)) {
69
+ setDiscardDialogOpened(true);
70
+ } else {
71
+ onClose();
72
+ }
73
+ }, [
74
+ state,
75
+ patchedInitialDatasource,
76
+ setDiscardDialogOpened,
77
+ onClose
78
+ ]);
79
+ return /*#__PURE__*/ _jsxs(FormProvider, {
80
+ ...form,
81
+ children: [
82
+ /*#__PURE__*/ _jsxs(Box, {
83
+ sx: {
84
+ display: 'flex',
85
+ alignItems: 'center',
86
+ padding: (theme)=>theme.spacing(1, 2),
87
+ borderBottom: (theme)=>`1px solid ${theme.palette.divider}`
88
+ },
89
+ children: [
90
+ /*#__PURE__*/ _jsxs(Typography, {
91
+ variant: "h2",
92
+ children: [
93
+ titleAction,
94
+ " Datasource"
95
+ ]
96
+ }),
97
+ /*#__PURE__*/ _jsx(Stack, {
98
+ direction: "row",
99
+ spacing: 1,
100
+ sx: {
101
+ marginLeft: 'auto'
102
+ },
103
+ children: action === 'read' ? /*#__PURE__*/ _jsxs(_Fragment, {
104
+ children: [
105
+ /*#__PURE__*/ _jsx(Button, {
106
+ disabled: isReadonly,
107
+ variant: "contained",
108
+ onClick: ()=>setAction('update'),
109
+ children: "Edit"
110
+ }),
111
+ /*#__PURE__*/ _jsx(Button, {
112
+ color: "error",
113
+ disabled: isReadonly,
114
+ variant: "outlined",
115
+ onClick: onDelete,
116
+ children: "Delete"
117
+ }),
118
+ /*#__PURE__*/ _jsx(Divider, {
119
+ orientation: "vertical",
120
+ flexItem: true,
121
+ sx: (theme)=>({
122
+ borderColor: theme.palette.grey['500'],
123
+ '&.MuiDivider-root': {
124
+ marginLeft: 2,
125
+ marginRight: 1
126
+ }
127
+ })
128
+ }),
129
+ /*#__PURE__*/ _jsx(Button, {
130
+ color: "secondary",
131
+ variant: "outlined",
132
+ onClick: onClose,
133
+ children: "Close"
134
+ })
135
+ ]
136
+ }) : /*#__PURE__*/ _jsxs(_Fragment, {
137
+ children: [
138
+ /*#__PURE__*/ _jsx(Button, {
139
+ variant: "contained",
140
+ disabled: !form.formState.isValid,
141
+ onClick: form.handleSubmit(processForm),
142
+ children: submitText
143
+ }),
144
+ /*#__PURE__*/ _jsx(Button, {
145
+ color: "secondary",
146
+ variant: "outlined",
147
+ onClick: handleCancel,
148
+ children: "Cancel"
149
+ })
150
+ ]
151
+ })
152
+ })
153
+ ]
154
+ }),
155
+ /*#__PURE__*/ _jsxs(Box, {
156
+ padding: 2,
157
+ sx: {
158
+ overflowY: 'scroll'
159
+ },
160
+ children: [
161
+ /*#__PURE__*/ _jsxs(Grid, {
162
+ container: true,
163
+ spacing: 2,
164
+ mb: 2,
165
+ children: [
166
+ /*#__PURE__*/ _jsx(Grid, {
167
+ item: true,
168
+ xs: 4,
169
+ children: /*#__PURE__*/ _jsx(Controller, {
170
+ name: "name",
171
+ render: ({ field , fieldState })=>{
172
+ var _fieldState_error;
173
+ /*#__PURE__*/ return _jsx(TextField, {
174
+ ...field,
175
+ required: true,
176
+ fullWidth: true,
177
+ name: "name",
178
+ label: "Name",
179
+ InputLabelProps: {
180
+ shrink: action === 'read' ? true : undefined
181
+ },
182
+ InputProps: {
183
+ disabled: action === 'update',
184
+ readOnly: action === 'read'
185
+ },
186
+ error: !!fieldState.error,
187
+ helperText: (_fieldState_error = fieldState.error) === null || _fieldState_error === void 0 ? void 0 : _fieldState_error.message,
188
+ onChange: (event)=>{
189
+ field.onChange(event);
190
+ setState((draft)=>{
191
+ draft.metadata.name = event.target.value;
192
+ });
193
+ }
194
+ });
195
+ }
196
+ })
197
+ }),
198
+ /*#__PURE__*/ _jsx(Grid, {
199
+ item: true,
200
+ xs: 8,
201
+ children: /*#__PURE__*/ _jsx(Controller, {
202
+ name: "title",
203
+ render: ({ field , fieldState })=>{
204
+ var _fieldState_error;
205
+ /*#__PURE__*/ return _jsx(TextField, {
206
+ ...field,
207
+ fullWidth: true,
208
+ name: "title",
209
+ label: "Display Label",
210
+ InputLabelProps: {
211
+ shrink: action === 'read' ? true : undefined
212
+ },
213
+ InputProps: {
214
+ readOnly: action === 'read'
215
+ },
216
+ error: !!fieldState.error,
217
+ helperText: (_fieldState_error = fieldState.error) === null || _fieldState_error === void 0 ? void 0 : _fieldState_error.message,
218
+ onChange: (event)=>{
219
+ setState((draft)=>{
220
+ field.onChange(event);
221
+ if (draft.spec.display) {
222
+ draft.spec.display.name = event.target.value;
223
+ }
224
+ });
225
+ }
226
+ });
227
+ }
228
+ })
229
+ }),
230
+ /*#__PURE__*/ _jsx(Grid, {
231
+ item: true,
232
+ xs: 12,
233
+ children: /*#__PURE__*/ _jsx(Controller, {
234
+ name: "description",
235
+ render: ({ field , fieldState })=>{
236
+ var _fieldState_error;
237
+ /*#__PURE__*/ return _jsx(TextField, {
238
+ ...field,
239
+ fullWidth: true,
240
+ name: "description",
241
+ label: "Description",
242
+ InputLabelProps: {
243
+ shrink: action === 'read' ? true : undefined
244
+ },
245
+ InputProps: {
246
+ readOnly: action === 'read'
247
+ },
248
+ error: !!fieldState.error,
249
+ helperText: (_fieldState_error = fieldState.error) === null || _fieldState_error === void 0 ? void 0 : _fieldState_error.message,
250
+ onChange: (event)=>{
251
+ field.onChange(event);
252
+ setState((draft)=>{
253
+ if (draft.spec.display) {
254
+ draft.spec.display.description = event.target.value;
255
+ }
256
+ });
257
+ }
258
+ });
259
+ }
260
+ })
261
+ }),
262
+ /*#__PURE__*/ _jsx(Grid, {
263
+ item: true,
264
+ xs: 6,
265
+ sx: {
266
+ paddingTop: '5px !important'
267
+ },
268
+ children: /*#__PURE__*/ _jsxs(Stack, {
269
+ children: [
270
+ /*#__PURE__*/ _jsx(Controller, {
271
+ name: "default",
272
+ render: ({ field })=>/*#__PURE__*/ _jsx(FormControlLabel, {
273
+ ...field,
274
+ control: /*#__PURE__*/ _jsx(Switch, {
275
+ checked: state.spec.default,
276
+ readOnly: action === 'read',
277
+ onChange: (event)=>{
278
+ if (action === 'read') return; // ReadOnly prop is not blocking user interaction...
279
+ field.onChange(event);
280
+ setState((draft)=>{
281
+ draft.spec.default = event.target.checked;
282
+ });
283
+ }
284
+ }),
285
+ label: "Set as default"
286
+ })
287
+ }),
288
+ /*#__PURE__*/ _jsxs(Typography, {
289
+ variant: "caption",
290
+ children: [
291
+ "Whether this datasource should be the default ",
292
+ state.spec.plugin.kind,
293
+ " to be used"
294
+ ]
295
+ })
296
+ ]
297
+ })
298
+ })
299
+ ]
300
+ }),
301
+ /*#__PURE__*/ _jsx(Divider, {}),
302
+ /*#__PURE__*/ _jsx(Typography, {
303
+ py: 1,
304
+ variant: "h3",
305
+ children: "Plugin Options"
306
+ }),
307
+ /*#__PURE__*/ _jsx(PluginEditor, {
308
+ width: "100%",
309
+ pluginType: "Datasource",
310
+ pluginKindLabel: "Source",
311
+ value: state.spec.plugin,
312
+ isReadonly: action === 'read',
313
+ onChange: (v)=>{
314
+ setState((draft)=>{
315
+ draft.spec.plugin = v;
316
+ });
317
+ }
318
+ })
319
+ ]
320
+ }),
321
+ /*#__PURE__*/ _jsx(DiscardChangesConfirmationDialog, {
322
+ description: "Are you sure you want to discard your changes? Changes cannot be recovered.",
323
+ isOpen: isDiscardDialogOpened,
324
+ onCancel: ()=>setDiscardDialogOpened(false),
325
+ onDiscardChanges: ()=>{
326
+ setDiscardDialogOpened(false);
327
+ onClose();
328
+ }
329
+ })
330
+ ]
331
+ });
332
+ }
333
+
334
+ //# sourceMappingURL=DatasourceEditorForm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/DatasourceEditorForm/DatasourceEditorForm.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 { useImmer } from 'use-immer';\nimport { Display, Datasource } from '@perses-dev/core';\nimport { Box, Button, Divider, FormControlLabel, Grid, Stack, Switch, TextField, Typography } from '@mui/material';\nimport React, { Dispatch, DispatchWithoutAction, useCallback, useState } from 'react';\nimport { DiscardChangesConfirmationDialog } from '@perses-dev/components';\nimport { Controller, FormProvider, SubmitHandler, useForm } from 'react-hook-form';\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport { PluginEditor } from '../PluginEditor';\nimport { Action, getSubmitText, getTitleAction } from '../../utils';\nimport { datasourceEditValidationSchema, DatasourceEditValidationType } from '../../validation';\n\n/**\n * This preprocessing ensures that we always have a defined object for the `display` property\n * @param datasource\n */\nfunction getInitialState<T extends Datasource>(datasource: T): T {\n const patchedDisplay: Display = {\n name: datasource.spec.display?.name ?? '',\n description: datasource.spec.display?.description ?? '',\n };\n\n return {\n ...datasource,\n spec: {\n ...datasource.spec,\n display: patchedDisplay,\n },\n };\n}\n\ninterface DatasourceEditorFormProps<T extends Datasource> {\n initialDatasource: T;\n initialAction: Action;\n isDraft: boolean;\n isReadonly?: boolean;\n onSave: Dispatch<T>;\n onClose: DispatchWithoutAction;\n onDelete?: DispatchWithoutAction;\n}\n\nexport function DatasourceEditorForm<T extends Datasource>(props: DatasourceEditorFormProps<T>) {\n const { initialDatasource, initialAction, isDraft, isReadonly, onSave, onClose, onDelete } = props;\n\n const patchedInitialDatasource = getInitialState(initialDatasource);\n const [state, setState] = useImmer(patchedInitialDatasource);\n const [isDiscardDialogOpened, setDiscardDialogOpened] = useState<boolean>(false);\n const [action, setAction] = useState(initialAction);\n const titleAction = getTitleAction(action, isDraft);\n const submitText = getSubmitText(action, isDraft);\n\n const form = useForm<DatasourceEditValidationType>({\n resolver: zodResolver(datasourceEditValidationSchema),\n mode: 'onBlur',\n defaultValues: {\n name: state.metadata.name,\n title: state.spec.display?.name,\n description: state.spec.display?.description,\n default: state.spec.default,\n },\n });\n\n const processForm: SubmitHandler<DatasourceEditValidationType> = () => {\n onSave(state);\n };\n\n // When user click on cancel, several possibilities:\n // - create action: ask for discard approval\n // - update action: ask for discard approval if changed\n // - read action: don´t ask for discard approval\n const handleCancel = useCallback(() => {\n if (JSON.stringify(patchedInitialDatasource) !== JSON.stringify(state)) {\n setDiscardDialogOpened(true);\n } else {\n onClose();\n }\n }, [state, patchedInitialDatasource, setDiscardDialogOpened, onClose]);\n\n return (\n <FormProvider {...form}>\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n padding: (theme) => theme.spacing(1, 2),\n borderBottom: (theme) => `1px solid ${theme.palette.divider}`,\n }}\n >\n <Typography variant=\"h2\">{titleAction} Datasource</Typography>\n <Stack direction=\"row\" spacing={1} sx={{ marginLeft: 'auto' }}>\n {action === 'read' ? (\n <>\n <Button disabled={isReadonly} variant=\"contained\" onClick={() => setAction('update')}>\n Edit\n </Button>\n <Button color=\"error\" disabled={isReadonly} variant=\"outlined\" onClick={onDelete}>\n Delete\n </Button>\n <Divider\n orientation=\"vertical\"\n flexItem\n sx={(theme) => ({\n borderColor: theme.palette.grey['500'],\n '&.MuiDivider-root': {\n marginLeft: 2,\n marginRight: 1,\n },\n })}\n />\n <Button color=\"secondary\" variant=\"outlined\" onClick={onClose}>\n Close\n </Button>\n </>\n ) : (\n <>\n <Button variant=\"contained\" disabled={!form.formState.isValid} onClick={form.handleSubmit(processForm)}>\n {submitText}\n </Button>\n <Button color=\"secondary\" variant=\"outlined\" onClick={handleCancel}>\n Cancel\n </Button>\n </>\n )}\n </Stack>\n </Box>\n <Box padding={2} sx={{ overflowY: 'scroll' }}>\n <Grid container spacing={2} mb={2}>\n <Grid item xs={4}>\n <Controller\n name=\"name\"\n render={({ field, fieldState }) => (\n <TextField\n {...field}\n required\n fullWidth\n name=\"name\"\n label=\"Name\"\n InputLabelProps={{ shrink: action === 'read' ? true : undefined }}\n InputProps={{\n disabled: action === 'update',\n readOnly: action === 'read',\n }}\n error={!!fieldState.error}\n helperText={fieldState.error?.message}\n onChange={(event) => {\n field.onChange(event);\n setState((draft) => {\n draft.metadata.name = event.target.value;\n });\n }}\n />\n )}\n />\n </Grid>\n <Grid item xs={8}>\n <Controller\n name=\"title\"\n render={({ field, fieldState }) => (\n <TextField\n {...field}\n fullWidth\n name=\"title\"\n label=\"Display Label\"\n InputLabelProps={{ shrink: action === 'read' ? true : undefined }}\n InputProps={{\n readOnly: action === 'read',\n }}\n error={!!fieldState.error}\n helperText={fieldState.error?.message}\n onChange={(event) => {\n setState((draft) => {\n field.onChange(event);\n if (draft.spec.display) {\n draft.spec.display.name = event.target.value;\n }\n });\n }}\n />\n )}\n />\n </Grid>\n <Grid item xs={12}>\n <Controller\n name=\"description\"\n render={({ field, fieldState }) => (\n <TextField\n {...field}\n fullWidth\n name=\"description\"\n label=\"Description\"\n InputLabelProps={{ shrink: action === 'read' ? true : undefined }}\n InputProps={{\n readOnly: action === 'read',\n }}\n error={!!fieldState.error}\n helperText={fieldState.error?.message}\n onChange={(event) => {\n field.onChange(event);\n setState((draft) => {\n if (draft.spec.display) {\n draft.spec.display.description = event.target.value;\n }\n });\n }}\n />\n )}\n />\n </Grid>\n <Grid item xs={6} sx={{ paddingTop: '5px !important' }}>\n <Stack>\n <Controller\n name=\"default\"\n render={({ field }) => (\n <FormControlLabel\n {...field}\n control={\n <Switch\n checked={state.spec.default}\n readOnly={action === 'read'}\n onChange={(event) => {\n if (action === 'read') return; // ReadOnly prop is not blocking user interaction...\n field.onChange(event);\n setState((draft) => {\n draft.spec.default = event.target.checked;\n });\n }}\n />\n }\n label=\"Set as default\"\n />\n )}\n />\n <Typography variant=\"caption\">\n Whether this datasource should be the default {state.spec.plugin.kind} to be used\n </Typography>\n </Stack>\n </Grid>\n </Grid>\n <Divider />\n <Typography py={1} variant=\"h3\">\n Plugin Options\n </Typography>\n <PluginEditor\n width=\"100%\"\n pluginType=\"Datasource\"\n pluginKindLabel=\"Source\"\n value={state.spec.plugin}\n isReadonly={action === 'read'}\n onChange={(v) => {\n setState((draft) => {\n draft.spec.plugin = v;\n });\n }}\n />\n </Box>\n <DiscardChangesConfirmationDialog\n description=\"Are you sure you want to discard your changes? Changes cannot be recovered.\"\n isOpen={isDiscardDialogOpened}\n onCancel={() => setDiscardDialogOpened(false)}\n onDiscardChanges={() => {\n setDiscardDialogOpened(false);\n onClose();\n }}\n />\n </FormProvider>\n );\n}\n"],"names":["useImmer","Box","Button","Divider","FormControlLabel","Grid","Stack","Switch","TextField","Typography","React","useCallback","useState","DiscardChangesConfirmationDialog","Controller","FormProvider","useForm","zodResolver","PluginEditor","getSubmitText","getTitleAction","datasourceEditValidationSchema","getInitialState","datasource","patchedDisplay","name","spec","display","description","DatasourceEditorForm","props","state","initialDatasource","initialAction","isDraft","isReadonly","onSave","onClose","onDelete","patchedInitialDatasource","setState","isDiscardDialogOpened","setDiscardDialogOpened","action","setAction","titleAction","submitText","form","resolver","mode","defaultValues","metadata","title","default","processForm","handleCancel","JSON","stringify","sx","alignItems","padding","theme","spacing","borderBottom","palette","divider","variant","direction","marginLeft","disabled","onClick","color","orientation","flexItem","borderColor","grey","marginRight","formState","isValid","handleSubmit","overflowY","container","mb","item","xs","render","field","fieldState","required","fullWidth","label","InputLabelProps","shrink","undefined","InputProps","readOnly","error","helperText","message","onChange","event","draft","target","value","paddingTop","control","checked","plugin","kind","py","width","pluginType","pluginKindLabel","v","isOpen","onCancel","onDiscardChanges"],"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,QAAQ,QAAQ,YAAY;AAErC,SAASC,GAAG,EAAEC,MAAM,EAAEC,OAAO,EAAEC,gBAAgB,EAAEC,IAAI,EAAEC,KAAK,EAAEC,MAAM,EAAEC,SAAS,EAAEC,UAAU,QAAQ,gBAAgB;AACnH,OAAOC,SAA0CC,WAAW,EAAEC,QAAQ,QAAQ,QAAQ;AACtF,SAASC,gCAAgC,QAAQ,yBAAyB;AAC1E,SAASC,UAAU,EAAEC,YAAY,EAAiBC,OAAO,QAAQ,kBAAkB;AACnF,SAASC,WAAW,QAAQ,0BAA0B;AACtD,SAASC,YAAY,QAAQ,kBAAkB;AAC/C,SAAiBC,aAAa,EAAEC,cAAc,QAAQ,cAAc;AACpE,SAASC,8BAA8B,QAAsC,mBAAmB;AAEhG;;;CAGC,GACD,SAASC,gBAAsCC,UAAa;QAElDA,0BACOA;QADPA,+BACOA;IAFf,MAAMC,iBAA0B;QAC9BC,MAAMF,CAAAA,gCAAAA,CAAAA,2BAAAA,WAAWG,KAAKC,qBAAhBJ,sCAAAA,KAAAA,IAAAA,yBAAyBE,kBAAzBF,2CAAAA,gCAAiC;QACvCK,aAAaL,CAAAA,uCAAAA,CAAAA,4BAAAA,WAAWG,KAAKC,qBAAhBJ,uCAAAA,KAAAA,IAAAA,0BAAyBK,yBAAzBL,kDAAAA,uCAAwC;IACvD;IAEA,OAAO;QACL,GAAGA,UAAU;QACbG,MAAM;YACJ,GAAGH,WAAWG,IAAI;YAClBC,SAASH;QACX;IACF;AACF;AAYA,OAAO,SAASK,qBAA2CC,KAAmC;QAejFC,qBACMA;IAfjB,MAAM,EAAEC,kBAAiB,EAAEC,cAAa,EAAEC,QAAO,EAAEC,WAAU,EAAEC,OAAM,EAAEC,QAAO,EAAEC,SAAQ,EAAE,GAAGR;IAE7F,MAAMS,2BAA2BjB,gBAAgBU;IACjD,MAAM,CAACD,OAAOS,SAAS,GAAGxC,SAASuC;IACnC,MAAM,CAACE,uBAAuBC,uBAAuB,GAAG9B,SAAkB;IAC1E,MAAM,CAAC+B,QAAQC,UAAU,GAAGhC,SAASqB;IACrC,MAAMY,cAAczB,eAAeuB,QAAQT;IAC3C,MAAMY,aAAa3B,cAAcwB,QAAQT;IAEzC,MAAMa,OAAO/B,QAAsC;QACjDgC,UAAU/B,YAAYI;QACtB4B,MAAM;QACNC,eAAe;YACbzB,MAAMM,MAAMoB,SAAS1B;YACrB2B,OAAOrB,CAAAA,sBAAAA,MAAML,KAAKC,qBAAXI,iCAAAA,KAAAA,IAAAA,oBAAoBN;YAC3BG,aAAaG,CAAAA,uBAAAA,MAAML,KAAKC,qBAAXI,kCAAAA,KAAAA,IAAAA,qBAAoBH;YACjCyB,SAAStB,MAAML,KAAK2B;QACtB;IACF;IAEA,MAAMC,cAA2D;QAC/DlB,OAAOL;IACT;IAEA,oDAAoD;IACpD,4CAA4C;IAC5C,uDAAuD;IACvD,gDAAgD;IAChD,MAAMwB,eAAe5C,YAAY;QAC/B,IAAI6C,KAAKC,UAAUlB,8BAA8BiB,KAAKC,UAAU1B,QAAQ;YACtEW,uBAAuB;QACzB,OAAO;YACLL;QACF;IACF,GAAG;QAACN;QAAOQ;QAA0BG;QAAwBL;KAAQ;IAErE,qBACE,MAACtB;QAAc,GAAGgC,IAAI;;0BACpB,MAAC9C;gBACCyD,IAAI;oBACF/B,SAAS;oBACTgC,YAAY;oBACZC,SAAS,CAACC,QAAUA,MAAMC,QAAQ,GAAG;oBACrCC,cAAc,CAACF,QAAU,CAAC,UAAU,EAAEA,MAAMG,QAAQC,QAAQ,CAAC;gBAC/D;;kCAEA,MAACxD;wBAAWyD,SAAQ;;4BAAMrB;4BAAY;;;kCACtC,KAACvC;wBAAM6D,WAAU;wBAAML,SAAS;wBAAGJ,IAAI;4BAAEU,YAAY;wBAAO;kCACzDzB,WAAW,uBACV;;8CACE,KAACzC;oCAAOmE,UAAUlC;oCAAY+B,SAAQ;oCAAYI,SAAS,IAAM1B,UAAU;8CAAW;;8CAGtF,KAAC1C;oCAAOqE,OAAM;oCAAQF,UAAUlC;oCAAY+B,SAAQ;oCAAWI,SAAShC;8CAAU;;8CAGlF,KAACnC;oCACCqE,aAAY;oCACZC,QAAQ;oCACRf,IAAI,CAACG,QAAW,CAAA;4CACda,aAAab,MAAMG,QAAQW,IAAI,CAAC,MAAM;4CACtC,qBAAqB;gDACnBP,YAAY;gDACZQ,aAAa;4CACf;wCACF,CAAA;;8CAEF,KAAC1E;oCAAOqE,OAAM;oCAAYL,SAAQ;oCAAWI,SAASjC;8CAAS;;;2CAKjE;;8CACE,KAACnC;oCAAOgE,SAAQ;oCAAYG,UAAU,CAACtB,KAAK8B,UAAUC;oCAASR,SAASvB,KAAKgC,aAAazB;8CACvFR;;8CAEH,KAAC5C;oCAAOqE,OAAM;oCAAYL,SAAQ;oCAAWI,SAASf;8CAAc;;;;;;;0BAO5E,MAACtD;gBAAI2D,SAAS;gBAAGF,IAAI;oBAAEsB,WAAW;gBAAS;;kCACzC,MAAC3E;wBAAK4E,SAAS;wBAACnB,SAAS;wBAAGoB,IAAI;;0CAC9B,KAAC7E;gCAAK8E,IAAI;gCAACC,IAAI;0CACb,cAAA,KAACtE;oCACCW,MAAK;oCACL4D,QAAQ,CAAC,EAAEC,MAAK,EAAEC,WAAU,EAAE;4CAadA;sDAZd,OAAA,KAAC/E;4CACE,GAAG8E,KAAK;4CACTE,QAAQ;4CACRC,SAAS;4CACThE,MAAK;4CACLiE,OAAM;4CACNC,iBAAiB;gDAAEC,QAAQjD,WAAW,SAAS,OAAOkD;4CAAU;4CAChEC,YAAY;gDACVzB,UAAU1B,WAAW;gDACrBoD,UAAUpD,WAAW;4CACvB;4CACAqD,OAAO,CAAC,CAACT,WAAWS;4CACpBC,YAAYV,CAAAA,oBAAAA,WAAWS,mBAAXT,+BAAAA,KAAAA,IAAAA,kBAAkBW;4CAC9BC,UAAU,CAACC;gDACTd,MAAMa,SAASC;gDACf5D,SAAS,CAAC6D;oDACRA,MAAMlD,SAAS1B,OAAO2E,MAAME,OAAOC;gDACrC;4CACF;;;;;0CAKR,KAAClG;gCAAK8E,IAAI;gCAACC,IAAI;0CACb,cAAA,KAACtE;oCACCW,MAAK;oCACL4D,QAAQ,CAAC,EAAEC,MAAK,EAAEC,WAAU,EAAE;4CAWdA;sDAVd,OAAA,KAAC/E;4CACE,GAAG8E,KAAK;4CACTG,SAAS;4CACThE,MAAK;4CACLiE,OAAM;4CACNC,iBAAiB;gDAAEC,QAAQjD,WAAW,SAAS,OAAOkD;4CAAU;4CAChEC,YAAY;gDACVC,UAAUpD,WAAW;4CACvB;4CACAqD,OAAO,CAAC,CAACT,WAAWS;4CACpBC,YAAYV,CAAAA,oBAAAA,WAAWS,mBAAXT,+BAAAA,KAAAA,IAAAA,kBAAkBW;4CAC9BC,UAAU,CAACC;gDACT5D,SAAS,CAAC6D;oDACRf,MAAMa,SAASC;oDACf,IAAIC,MAAM3E,KAAKC,SAAS;wDACtB0E,MAAM3E,KAAKC,QAAQF,OAAO2E,MAAME,OAAOC;oDACzC;gDACF;4CACF;;;;;0CAKR,KAAClG;gCAAK8E,IAAI;gCAACC,IAAI;0CACb,cAAA,KAACtE;oCACCW,MAAK;oCACL4D,QAAQ,CAAC,EAAEC,MAAK,EAAEC,WAAU,EAAE;4CAWdA;sDAVd,OAAA,KAAC/E;4CACE,GAAG8E,KAAK;4CACTG,SAAS;4CACThE,MAAK;4CACLiE,OAAM;4CACNC,iBAAiB;gDAAEC,QAAQjD,WAAW,SAAS,OAAOkD;4CAAU;4CAChEC,YAAY;gDACVC,UAAUpD,WAAW;4CACvB;4CACAqD,OAAO,CAAC,CAACT,WAAWS;4CACpBC,YAAYV,CAAAA,oBAAAA,WAAWS,mBAAXT,+BAAAA,KAAAA,IAAAA,kBAAkBW;4CAC9BC,UAAU,CAACC;gDACTd,MAAMa,SAASC;gDACf5D,SAAS,CAAC6D;oDACR,IAAIA,MAAM3E,KAAKC,SAAS;wDACtB0E,MAAM3E,KAAKC,QAAQC,cAAcwE,MAAME,OAAOC;oDAChD;gDACF;4CACF;;;;;0CAKR,KAAClG;gCAAK8E,IAAI;gCAACC,IAAI;gCAAG1B,IAAI;oCAAE8C,YAAY;gCAAiB;0CACnD,cAAA,MAAClG;;sDACC,KAACQ;4CACCW,MAAK;4CACL4D,QAAQ,CAAC,EAAEC,MAAK,EAAE,iBAChB,KAAClF;oDACE,GAAGkF,KAAK;oDACTmB,uBACE,KAAClG;wDACCmG,SAAS3E,MAAML,KAAK2B;wDACpB0C,UAAUpD,WAAW;wDACrBwD,UAAU,CAACC;4DACT,IAAIzD,WAAW,QAAQ,QAAQ,oDAAoD;4DACnF2C,MAAMa,SAASC;4DACf5D,SAAS,CAAC6D;gEACRA,MAAM3E,KAAK2B,UAAU+C,MAAME,OAAOI;4DACpC;wDACF;;oDAGJhB,OAAM;;;sDAIZ,MAACjF;4CAAWyD,SAAQ;;gDAAU;gDACmBnC,MAAML,KAAKiF,OAAOC;gDAAK;;;;;;;;kCAK9E,KAACzG;kCACD,KAACM;wBAAWoG,IAAI;wBAAG3C,SAAQ;kCAAK;;kCAGhC,KAAChD;wBACC4F,OAAM;wBACNC,YAAW;wBACXC,iBAAgB;wBAChBT,OAAOxE,MAAML,KAAKiF;wBAClBxE,YAAYQ,WAAW;wBACvBwD,UAAU,CAACc;4BACTzE,SAAS,CAAC6D;gCACRA,MAAM3E,KAAKiF,SAASM;4BACtB;wBACF;;;;0BAGJ,KAACpG;gBACCe,aAAY;gBACZsF,QAAQzE;gBACR0E,UAAU,IAAMzE,uBAAuB;gBACvC0E,kBAAkB;oBAChB1E,uBAAuB;oBACvBL;gBACF;;;;AAIR"}
@@ -0,0 +1,2 @@
1
+ export * from './DatasourceEditorForm';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/DatasourceEditorForm/index.ts"],"names":[],"mappings":"AAaA,cAAc,wBAAwB,CAAC"}
@@ -0,0 +1,15 @@
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
+ export * from './DatasourceEditorForm';
14
+
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/DatasourceEditorForm/index.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\nexport * from './DatasourceEditorForm';\n"],"names":[],"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,cAAc,yBAAyB"}
@@ -12,5 +12,10 @@ export interface DatasourceSelectProps extends Omit<SelectProps<string>, Omitted
12
12
  * the input deal with a `DatasourceSelector`.
13
13
  */
14
14
  export declare function DatasourceSelect(props: DatasourceSelectProps): JSX.Element;
15
+ export declare function DatasourceName(props: {
16
+ name: string;
17
+ overridden?: boolean;
18
+ overriding?: boolean;
19
+ }): JSX.Element;
15
20
  export {};
16
21
  //# sourceMappingURL=DatasourceSelect.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DatasourceSelect.d.ts","sourceRoot":"","sources":["../../src/components/DatasourceSelect.tsx"],"names":[],"mappings":";AAaA,OAAO,EAAU,WAAW,EAAY,MAAM,eAAe,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAMtD,aAAK,eAAe,GAAG,UAAU,GAAG,OAAO,GAAG,UAAU,CAAC;AAEzD,MAAM,WAAW,qBAAsB,SAAQ,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,eAAe,CAAC;IACvF,KAAK,EAAE,kBAAkB,CAAC;IAC1B,QAAQ,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAC7C,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,eA6B5D"}
1
+ {"version":3,"file":"DatasourceSelect.d.ts","sourceRoot":"","sources":["../../src/components/DatasourceSelect.tsx"],"names":[],"mappings":";AAcA,OAAO,EAAU,WAAW,EAAiE,MAAM,eAAe,CAAC;AACnH,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAMtD,aAAK,eAAe,GAAG,UAAU,GAAG,OAAO,GAAG,UAAU,CAAC;AAEzD,MAAM,WAAW,qBAAsB,SAAQ,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,eAAe,CAAC;IACvF,KAAK,EAAE,kBAAkB,CAAC;IAC1B,QAAQ,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAC7C,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,eAsF5D;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE,eAajG"}
@@ -10,62 +10,145 @@
10
10
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
11
  // See the License for the specific language governing permissions and
12
12
  // limitations under the License.
13
- import { jsx as _jsx } from "react/jsx-runtime";
14
- import { Select, MenuItem } from '@mui/material';
13
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
14
+ import OpenInNewIcon from 'mdi-material-ui/OpenInNew';
15
+ import { Select, MenuItem, Stack, Divider, ListItemText, Chip, IconButton, Box } from '@mui/material';
15
16
  import { useMemo } from 'react';
16
- import { useListDatasources } from '../runtime';
17
+ import { useListDatasourceSelectItems } from '../runtime';
17
18
  /**
18
19
  * Displays a MUI input for selecting a Datasource of a particular kind. Note: The 'value' and `onChange` handler for
19
20
  * the input deal with a `DatasourceSelector`.
20
21
  */ export function DatasourceSelect(props) {
21
22
  const { datasourcePluginKind , value , onChange , ...others } = props;
22
- const { data , isLoading } = useListDatasources(datasourcePluginKind);
23
- // Convert the datasource list into menu items with name/value strings that the Select input can work with
23
+ const { data , isLoading } = useListDatasourceSelectItems(datasourcePluginKind);
24
+ // Rebuild the group of the value if not provided
25
+ const defaultValue = useMemo(()=>{
26
+ var _flatMap_find;
27
+ const group = (_flatMap_find = (data !== null && data !== void 0 ? data : []).flatMap((itemGroup)=>itemGroup.items).find((item)=>{
28
+ return value.kind === item.selector.kind && value.name === item.selector.name && !item.overridden;
29
+ })) === null || _flatMap_find === void 0 ? void 0 : _flatMap_find.selector.group;
30
+ return {
31
+ ...value,
32
+ group
33
+ };
34
+ }, [
35
+ value,
36
+ data
37
+ ]);
38
+ // Convert the datasource list into menu items with name/group?/value strings that the Select input can work with
24
39
  const menuItems = useMemo(()=>{
25
- if (data === undefined) return [];
26
- return data.map((ds)=>({
27
- name: ds.name,
28
- value: selectorToOptionValue(ds.selector)
40
+ return (data !== null && data !== void 0 ? data : []).map((itemGroup)=>({
41
+ group: itemGroup.group,
42
+ editLink: itemGroup.editLink,
43
+ items: itemGroup.items.map((item)=>({
44
+ name: item.name,
45
+ overriding: item.overriding,
46
+ overridden: item.overridden,
47
+ group: item.selector.group,
48
+ value: selectorToOptionValue(item.selector)
49
+ }))
29
50
  }));
30
51
  }, [
31
52
  data
32
53
  ]);
33
54
  // While loading available values, just use an empty string so MUI select doesn't warn about values out of range
34
- const optionValue = isLoading ? '' : selectorToOptionValue(value);
55
+ const optionValue = isLoading ? '' : selectorToOptionValue(defaultValue);
35
56
  // When the user makes a selection, convert the string option value back to a DatasourceSelector
36
57
  const handleChange = (e)=>{
37
58
  const next = optionValueToSelector(e.target.value);
38
59
  onChange(next);
39
60
  };
40
- // TODO: Does this need a loading indicator of some kind?
61
+ // We use a fake action event when we click on the action of the chip (hijack the "delete" feature).
62
+ // This is because the href link action is on the `deleteIcon` property already, but the `onDelete` property
63
+ // controls its visibility.
64
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
65
+ const fakeActionEvent = ()=>{};
66
+ // TODO:
67
+ // - Does this need a loading indicator of some kind?
68
+ // - The group's edit link is not clickable once selected.
69
+ // - The group's edit link is disabled if datasource is overridden.
70
+ // Ref: https://github.com/mui/material-ui/issues/36572
41
71
  return /*#__PURE__*/ _jsx(Select, {
42
72
  ...others,
43
73
  value: optionValue,
44
74
  onChange: handleChange,
45
- children: menuItems.map((menuItem)=>/*#__PURE__*/ _jsx(MenuItem, {
46
- value: menuItem.value,
47
- children: menuItem.name
48
- }, menuItem.value))
75
+ children: menuItems.map((menuItemGroup)=>[
76
+ /*#__PURE__*/ _jsx(Divider, {}, `${menuItemGroup.group}-divider`),
77
+ ...menuItemGroup.items.map((menuItem)=>/*#__PURE__*/ _jsx(MenuItem, {
78
+ value: menuItem.value,
79
+ disabled: menuItem.overridden,
80
+ children: /*#__PURE__*/ _jsxs(Stack, {
81
+ direction: "row",
82
+ alignItems: "center",
83
+ justifyContent: "space-between",
84
+ width: "100%",
85
+ children: [
86
+ /*#__PURE__*/ _jsx(ListItemText, {
87
+ children: /*#__PURE__*/ _jsx(DatasourceName, {
88
+ name: menuItem.name,
89
+ overridden: menuItem.overridden,
90
+ overriding: menuItem.overriding
91
+ })
92
+ }),
93
+ /*#__PURE__*/ _jsx(ListItemText, {
94
+ style: {
95
+ textAlign: 'right'
96
+ },
97
+ children: menuItemGroup.group && menuItemGroup.group.length > 0 && /*#__PURE__*/ _jsx(Chip, {
98
+ disabled: false,
99
+ label: menuItemGroup.group,
100
+ size: "small",
101
+ onDelete: menuItemGroup.editLink ? fakeActionEvent : undefined,
102
+ deleteIcon: menuItemGroup.editLink ? /*#__PURE__*/ _jsx(IconButton, {
103
+ href: menuItemGroup.editLink,
104
+ target: "_blank",
105
+ children: /*#__PURE__*/ _jsx(OpenInNewIcon, {
106
+ fontSize: "small"
107
+ })
108
+ }) : undefined
109
+ })
110
+ })
111
+ ]
112
+ })
113
+ }, menuItem.value))
114
+ ])
115
+ });
116
+ }
117
+ export function DatasourceName(props) {
118
+ const { name , overridden , overriding } = props;
119
+ return /*#__PURE__*/ _jsxs(_Fragment, {
120
+ children: [
121
+ `${name} `,
122
+ !overridden && overriding && /*#__PURE__*/ _jsx(Box, {
123
+ display: "inline",
124
+ fontWeight: "normal",
125
+ color: (theme)=>theme.palette.primary.main,
126
+ children: "(overriding)"
127
+ }),
128
+ overridden && '(overridden)'
129
+ ]
49
130
  });
50
131
  }
51
132
  // Delimiter used to stringify/parse option values
52
133
  const OPTION_VALUE_DELIMITER = '_____';
53
134
  // Given a DatasourceSelector, returns a string value like `{kind}_____{name}` that can be used as a Select input value
54
135
  function selectorToOptionValue(selector) {
55
- var _name;
136
+ var _selector_group, _selector_name;
56
137
  return [
57
138
  selector.kind,
58
- (_name = selector.name) !== null && _name !== void 0 ? _name : ''
139
+ (_selector_group = selector.group) !== null && _selector_group !== void 0 ? _selector_group : '',
140
+ (_selector_name = selector.name) !== null && _selector_name !== void 0 ? _selector_name : ''
59
141
  ].join(OPTION_VALUE_DELIMITER);
60
142
  }
61
143
  // Given an option value name like `{kind}_____{name}`, returns a DatasourceSelector
62
144
  function optionValueToSelector(optionValue) {
63
- const [kind, name] = optionValue.split(OPTION_VALUE_DELIMITER);
64
- if (kind === undefined || name === undefined) {
145
+ const [kind, group, name] = optionValue.split(OPTION_VALUE_DELIMITER);
146
+ if (kind === undefined || group === undefined || name === undefined) {
65
147
  throw new Error('Invalid optionValue string');
66
148
  }
67
149
  return {
68
150
  kind,
151
+ group: group === '' ? undefined : group,
69
152
  name: name === '' ? undefined : name
70
153
  };
71
154
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/DatasourceSelect.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 { Select, SelectProps, MenuItem } from '@mui/material';\nimport { DatasourceSelector } from '@perses-dev/core';\nimport { useMemo } from 'react';\nimport { useListDatasources } from '../runtime';\n\n// Props on MUI Select that we don't want people to pass because we're either redefining them or providing them in\n// this component\ntype OmittedMuiProps = 'children' | 'value' | 'onChange';\n\nexport interface DatasourceSelectProps extends Omit<SelectProps<string>, OmittedMuiProps> {\n value: DatasourceSelector;\n onChange: (next: DatasourceSelector) => void;\n datasourcePluginKind: string;\n}\n\n/**\n * Displays a MUI input for selecting a Datasource of a particular kind. Note: The 'value' and `onChange` handler for\n * the input deal with a `DatasourceSelector`.\n */\nexport function DatasourceSelect(props: DatasourceSelectProps) {\n const { datasourcePluginKind, value, onChange, ...others } = props;\n const { data, isLoading } = useListDatasources(datasourcePluginKind);\n\n // Convert the datasource list into menu items with name/value strings that the Select input can work with\n const menuItems = useMemo(() => {\n if (data === undefined) return [];\n return data.map((ds) => ({ name: ds.name, value: selectorToOptionValue(ds.selector) }));\n }, [data]);\n\n // While loading available values, just use an empty string so MUI select doesn't warn about values out of range\n const optionValue = isLoading ? '' : selectorToOptionValue(value);\n\n // When the user makes a selection, convert the string option value back to a DatasourceSelector\n const handleChange: SelectProps<string>['onChange'] = (e) => {\n const next = optionValueToSelector(e.target.value);\n onChange(next);\n };\n\n // TODO: Does this need a loading indicator of some kind?\n return (\n <Select {...others} value={optionValue} onChange={handleChange}>\n {menuItems.map((menuItem) => (\n <MenuItem key={menuItem.value} value={menuItem.value}>\n {menuItem.name}\n </MenuItem>\n ))}\n </Select>\n );\n}\n\n// Delimiter used to stringify/parse option values\nconst OPTION_VALUE_DELIMITER = '_____';\n\n// Given a DatasourceSelector, returns a string value like `{kind}_____{name}` that can be used as a Select input value\nfunction selectorToOptionValue(selector: DatasourceSelector): string {\n return [selector.kind, selector.name ?? ''].join(OPTION_VALUE_DELIMITER);\n}\n\n// Given an option value name like `{kind}_____{name}`, returns a DatasourceSelector\nfunction optionValueToSelector(optionValue: string): DatasourceSelector {\n const [kind, name] = optionValue.split(OPTION_VALUE_DELIMITER);\n if (kind === undefined || name === undefined) {\n throw new Error('Invalid optionValue string');\n }\n return {\n kind,\n name: name === '' ? undefined : name,\n };\n}\n"],"names":["Select","MenuItem","useMemo","useListDatasources","DatasourceSelect","props","datasourcePluginKind","value","onChange","others","data","isLoading","menuItems","undefined","map","ds","name","selectorToOptionValue","selector","optionValue","handleChange","e","next","optionValueToSelector","target","menuItem","OPTION_VALUE_DELIMITER","kind","join","split","Error"],"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;AAAA,SAASA,MAAM,EAAeC,QAAQ,QAAQ,eAAe,CAAC;AAE9D,SAASC,OAAO,QAAQ,OAAO,CAAC;AAChC,SAASC,kBAAkB,QAAQ,YAAY,CAAC;AAYhD;;;CAGC,GACD,OAAO,SAASC,gBAAgB,CAACC,KAA4B,EAAE;IAC7D,MAAM,EAAEC,oBAAoB,CAAA,EAAEC,KAAK,CAAA,EAAEC,QAAQ,CAAA,EAAE,GAAGC,MAAM,EAAE,GAAGJ,KAAK,AAAC;IACnE,MAAM,EAAEK,IAAI,CAAA,EAAEC,SAAS,CAAA,EAAE,GAAGR,kBAAkB,CAACG,oBAAoB,CAAC,AAAC;IAErE,0GAA0G;IAC1G,MAAMM,SAAS,GAAGV,OAAO,CAAC,IAAM;QAC9B,IAAIQ,IAAI,KAAKG,SAAS,EAAE,OAAO,EAAE,CAAC;QAClC,OAAOH,IAAI,CAACI,GAAG,CAAC,CAACC,EAAE,GAAM,CAAA;gBAAEC,IAAI,EAAED,EAAE,CAACC,IAAI;gBAAET,KAAK,EAAEU,qBAAqB,CAACF,EAAE,CAACG,QAAQ,CAAC;aAAE,CAAA,AAAC,CAAC,CAAC;IAC1F,CAAC,EAAE;QAACR,IAAI;KAAC,CAAC,AAAC;IAEX,gHAAgH;IAChH,MAAMS,WAAW,GAAGR,SAAS,GAAG,EAAE,GAAGM,qBAAqB,CAACV,KAAK,CAAC,AAAC;IAElE,gGAAgG;IAChG,MAAMa,YAAY,GAAoC,CAACC,CAAC,GAAK;QAC3D,MAAMC,IAAI,GAAGC,qBAAqB,CAACF,CAAC,CAACG,MAAM,CAACjB,KAAK,CAAC,AAAC;QACnDC,QAAQ,CAACc,IAAI,CAAC,CAAC;IACjB,CAAC,AAAC;IAEF,yDAAyD;IACzD,qBACE,KAACtB,MAAM;QAAE,GAAGS,MAAM;QAAEF,KAAK,EAAEY,WAAW;QAAEX,QAAQ,EAAEY,YAAY;kBAC3DR,SAAS,CAACE,GAAG,CAAC,CAACW,QAAQ,iBACtB,KAACxB,QAAQ;gBAAsBM,KAAK,EAAEkB,QAAQ,CAAClB,KAAK;0BACjDkB,QAAQ,CAACT,IAAI;eADDS,QAAQ,CAAClB,KAAK,CAElB,AACZ,CAAC;MACK,CACT;AACJ,CAAC;AAED,kDAAkD;AAClD,MAAMmB,sBAAsB,GAAG,OAAO,AAAC;AAEvC,uHAAuH;AACvH,SAAST,qBAAqB,CAACC,QAA4B,EAAU;QAC5CA,KAAa;IAApC,OAAO;QAACA,QAAQ,CAACS,IAAI;QAAET,CAAAA,KAAa,GAAbA,QAAQ,CAACF,IAAI,cAAbE,KAAa,cAAbA,KAAa,GAAI,EAAE;KAAC,CAACU,IAAI,CAACF,sBAAsB,CAAC,CAAC;AAC3E,CAAC;AAED,oFAAoF;AACpF,SAASH,qBAAqB,CAACJ,WAAmB,EAAsB;IACtE,MAAM,CAACQ,IAAI,EAAEX,IAAI,CAAC,GAAGG,WAAW,CAACU,KAAK,CAACH,sBAAsB,CAAC,AAAC;IAC/D,IAAIC,IAAI,KAAKd,SAAS,IAAIG,IAAI,KAAKH,SAAS,EAAE;QAC5C,MAAM,IAAIiB,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAChD,CAAC;IACD,OAAO;QACLH,IAAI;QACJX,IAAI,EAAEA,IAAI,KAAK,EAAE,GAAGH,SAAS,GAAGG,IAAI;KACrC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"sources":["../../src/components/DatasourceSelect.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 OpenInNewIcon from 'mdi-material-ui/OpenInNew';\nimport { Select, SelectProps, MenuItem, Stack, Divider, ListItemText, Chip, IconButton, Box } from '@mui/material';\nimport { DatasourceSelector } from '@perses-dev/core';\nimport { useMemo } from 'react';\nimport { useListDatasourceSelectItems } from '../runtime';\n\n// Props on MUI Select that we don't want people to pass because we're either redefining them or providing them in\n// this component\ntype OmittedMuiProps = 'children' | 'value' | 'onChange';\n\nexport interface DatasourceSelectProps extends Omit<SelectProps<string>, OmittedMuiProps> {\n value: DatasourceSelector;\n onChange: (next: DatasourceSelector) => void;\n datasourcePluginKind: string;\n}\n\n/**\n * Displays a MUI input for selecting a Datasource of a particular kind. Note: The 'value' and `onChange` handler for\n * the input deal with a `DatasourceSelector`.\n */\nexport function DatasourceSelect(props: DatasourceSelectProps) {\n const { datasourcePluginKind, value, onChange, ...others } = props;\n const { data, isLoading } = useListDatasourceSelectItems(datasourcePluginKind);\n\n // Rebuild the group of the value if not provided\n const defaultValue = useMemo(() => {\n const group = (data ?? [])\n .flatMap((itemGroup) => itemGroup.items)\n .find((item) => {\n return value.kind === item.selector.kind && value.name === item.selector.name && !item.overridden;\n })?.selector.group;\n return { ...value, group };\n }, [value, data]);\n\n // Convert the datasource list into menu items with name/group?/value strings that the Select input can work with\n const menuItems = useMemo(() => {\n return (data ?? []).map((itemGroup) => ({\n group: itemGroup.group,\n editLink: itemGroup.editLink,\n items: itemGroup.items.map((item) => ({\n name: item.name,\n overriding: item.overriding,\n overridden: item.overridden,\n group: item.selector.group,\n value: selectorToOptionValue(item.selector),\n })),\n }));\n }, [data]);\n\n // While loading available values, just use an empty string so MUI select doesn't warn about values out of range\n const optionValue = isLoading ? '' : selectorToOptionValue(defaultValue);\n\n // When the user makes a selection, convert the string option value back to a DatasourceSelector\n const handleChange: SelectProps<string>['onChange'] = (e) => {\n const next = optionValueToSelector(e.target.value);\n onChange(next);\n };\n\n // We use a fake action event when we click on the action of the chip (hijack the \"delete\" feature).\n // This is because the href link action is on the `deleteIcon` property already, but the `onDelete` property\n // controls its visibility.\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n const fakeActionEvent = () => {};\n\n // TODO:\n // - Does this need a loading indicator of some kind?\n // - The group's edit link is not clickable once selected.\n // - The group's edit link is disabled if datasource is overridden.\n // Ref: https://github.com/mui/material-ui/issues/36572\n return (\n <Select {...others} value={optionValue} onChange={handleChange}>\n {menuItems.map((menuItemGroup) => [\n <Divider key={`${menuItemGroup.group}-divider`} />,\n ...menuItemGroup.items.map((menuItem) => (\n <MenuItem key={menuItem.value} value={menuItem.value} disabled={menuItem.overridden}>\n <Stack direction=\"row\" alignItems=\"center\" justifyContent=\"space-between\" width=\"100%\">\n <ListItemText>\n <DatasourceName\n name={menuItem.name}\n overridden={menuItem.overridden}\n overriding={menuItem.overriding}\n />\n </ListItemText>\n <ListItemText style={{ textAlign: 'right' }}>\n {menuItemGroup.group && menuItemGroup.group.length > 0 && (\n <Chip\n disabled={false}\n label={menuItemGroup.group}\n size=\"small\"\n onDelete={menuItemGroup.editLink ? fakeActionEvent : undefined}\n deleteIcon={\n menuItemGroup.editLink ? (\n <IconButton href={menuItemGroup.editLink} target=\"_blank\">\n <OpenInNewIcon fontSize=\"small\" />\n </IconButton>\n ) : undefined\n }\n />\n )}\n </ListItemText>\n </Stack>\n </MenuItem>\n )),\n ])}\n </Select>\n );\n}\n\nexport function DatasourceName(props: { name: string; overridden?: boolean; overriding?: boolean }) {\n const { name, overridden, overriding } = props;\n return (\n <>\n {`${name} `}\n {!overridden && overriding && (\n <Box display=\"inline\" fontWeight=\"normal\" color={(theme) => theme.palette.primary.main}>\n (overriding)\n </Box>\n )}\n {overridden && '(overridden)'}\n </>\n );\n}\n\n// Delimiter used to stringify/parse option values\nconst OPTION_VALUE_DELIMITER = '_____';\n\n// Given a DatasourceSelector, returns a string value like `{kind}_____{name}` that can be used as a Select input value\nfunction selectorToOptionValue(selector: DatasourceSelector): string {\n return [selector.kind, selector.group ?? '', selector.name ?? ''].join(OPTION_VALUE_DELIMITER);\n}\n\n// Given an option value name like `{kind}_____{name}`, returns a DatasourceSelector\nfunction optionValueToSelector(optionValue: string): DatasourceSelector {\n const [kind, group, name] = optionValue.split(OPTION_VALUE_DELIMITER);\n if (kind === undefined || group === undefined || name === undefined) {\n throw new Error('Invalid optionValue string');\n }\n return {\n kind,\n group: group === '' ? undefined : group,\n name: name === '' ? undefined : name,\n };\n}\n"],"names":["OpenInNewIcon","Select","MenuItem","Stack","Divider","ListItemText","Chip","IconButton","Box","useMemo","useListDatasourceSelectItems","DatasourceSelect","props","datasourcePluginKind","value","onChange","others","data","isLoading","defaultValue","group","flatMap","itemGroup","items","find","item","kind","selector","name","overridden","menuItems","map","editLink","overriding","selectorToOptionValue","optionValue","handleChange","e","next","optionValueToSelector","target","fakeActionEvent","menuItemGroup","menuItem","disabled","direction","alignItems","justifyContent","width","DatasourceName","style","textAlign","length","label","size","onDelete","undefined","deleteIcon","href","fontSize","display","fontWeight","color","theme","palette","primary","main","OPTION_VALUE_DELIMITER","join","split","Error"],"mappings":"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"}