@perses-dev/dashboards 0.4.0 → 0.5.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.
Files changed (45) hide show
  1. package/dist/cjs/components/GridLayout/GridItemContent.js +1 -1
  2. package/dist/cjs/components/GridLayout/GridLayout.js +5 -5
  3. package/dist/cjs/components/{Panel.js → Panel/Panel.js} +11 -6
  4. package/dist/cjs/components/Panel/Panel.test.js +42 -0
  5. package/dist/cjs/components/{VariableOptionsDrawer.js → VariableOptionsDrawer/VariableOptionsDrawer.js} +2 -2
  6. package/dist/cjs/components/VariableOptionsDrawer/VariableOptionsDrawer.test.js +81 -0
  7. package/dist/cjs/components/index.js +2 -2
  8. package/dist/cjs/test/index.js +30 -0
  9. package/dist/cjs/test/plugin-registry.js +48 -0
  10. package/dist/cjs/test/render.js +26 -0
  11. package/dist/cjs/test/setup-tests.js +18 -0
  12. package/dist/components/GridLayout/GridItemContent.js +1 -1
  13. package/dist/components/GridLayout/GridLayout.js +1 -1
  14. package/dist/components/{Panel.d.ts → Panel/Panel.d.ts} +1 -1
  15. package/dist/components/Panel/Panel.d.ts.map +1 -0
  16. package/dist/components/Panel/Panel.js +1 -0
  17. package/dist/components/Panel/Panel.test.d.ts +2 -0
  18. package/dist/components/Panel/Panel.test.d.ts.map +1 -0
  19. package/dist/components/Panel/Panel.test.js +1 -0
  20. package/dist/components/{VariableOptionsDrawer.d.ts → VariableOptionsDrawer/VariableOptionsDrawer.d.ts} +0 -0
  21. package/dist/components/VariableOptionsDrawer/VariableOptionsDrawer.d.ts.map +1 -0
  22. package/dist/components/VariableOptionsDrawer/VariableOptionsDrawer.js +1 -0
  23. package/dist/components/VariableOptionsDrawer/VariableOptionsDrawer.test.d.ts +2 -0
  24. package/dist/components/VariableOptionsDrawer/VariableOptionsDrawer.test.d.ts.map +1 -0
  25. package/dist/components/VariableOptionsDrawer/VariableOptionsDrawer.test.js +1 -0
  26. package/dist/components/index.d.ts +2 -2
  27. package/dist/components/index.d.ts.map +1 -1
  28. package/dist/components/index.js +1 -1
  29. package/dist/test/index.d.ts +3 -0
  30. package/dist/test/index.d.ts.map +1 -0
  31. package/dist/test/index.js +1 -0
  32. package/dist/test/plugin-registry.d.ts +11 -0
  33. package/dist/test/plugin-registry.d.ts.map +1 -0
  34. package/dist/test/plugin-registry.js +1 -0
  35. package/dist/test/render.d.ts +7 -0
  36. package/dist/test/render.d.ts.map +1 -0
  37. package/dist/test/render.js +1 -0
  38. package/dist/test/setup-tests.d.ts +2 -0
  39. package/dist/test/setup-tests.d.ts.map +1 -0
  40. package/dist/test/setup-tests.js +1 -0
  41. package/package.json +8 -7
  42. package/dist/components/Panel.d.ts.map +0 -1
  43. package/dist/components/Panel.js +0 -1
  44. package/dist/components/VariableOptionsDrawer.d.ts.map +0 -1
  45. package/dist/components/VariableOptionsDrawer.js +0 -1
@@ -16,7 +16,7 @@ const jsx_runtime_1 = require("react/jsx-runtime");
16
16
  // limitations under the License.
17
17
  const components_1 = require("@perses-dev/components");
18
18
  const core_1 = require("@perses-dev/core");
19
- const Panel_1 = require("../Panel");
19
+ const Panel_1 = require("../Panel/Panel");
20
20
  /**
21
21
  * Resolves the reference to panel content in a GridItemDefinition and renders the panel.
22
22
  */
@@ -22,12 +22,12 @@ const COLUMNS = 24;
22
22
  * Layout component that arranges children in a Grid based on the definition.
23
23
  */
24
24
  function GridLayout(props) {
25
- var _a, _b;
26
- const { definition: { display, items }, renderGridItemContent, ...others } = props;
27
- const [isOpen, setIsOpen] = (0, react_1.useState)((_b = (_a = display === null || display === void 0 ? void 0 : display.collapse) === null || _a === void 0 ? void 0 : _a.open) !== null && _b !== void 0 ? _b : true);
25
+ var _a, _b, _c;
26
+ const { definition: { spec }, renderGridItemContent, ...others } = props;
27
+ const [isOpen, setIsOpen] = (0, react_1.useState)((_c = (_b = (_a = spec.display) === null || _a === void 0 ? void 0 : _a.collapse) === null || _b === void 0 ? void 0 : _b.open) !== null && _c !== void 0 ? _c : true);
28
28
  const gridItems = [];
29
29
  let mobileRowStart = 1;
30
- items.forEach((item, idx) => {
30
+ spec.items.forEach((item, idx) => {
31
31
  // Try to maintain the chart's aspect ratio on mobile
32
32
  const widthScale = COLUMNS / item.width;
33
33
  const mobileRows = Math.floor(item.height * widthScale);
@@ -43,7 +43,7 @@ function GridLayout(props) {
43
43
  }, children: renderGridItemContent(item) }, idx));
44
44
  mobileRowStart += mobileRows;
45
45
  });
46
- return ((0, jsx_runtime_1.jsxs)(material_1.Box, { ...others, component: "section", sx: { '& + &': { marginTop: (theme) => theme.spacing(1) } }, children: [display !== undefined && ((0, jsx_runtime_1.jsx)(GridTitle_1.GridTitle, { title: display.title, collapse: display.collapse === undefined
46
+ return ((0, jsx_runtime_1.jsxs)(material_1.Box, { ...others, component: "section", sx: { '& + &': { marginTop: (theme) => theme.spacing(1) } }, children: [spec.display !== undefined && ((0, jsx_runtime_1.jsx)(GridTitle_1.GridTitle, { title: spec.display.title, collapse: spec.display.collapse === undefined
47
47
  ? undefined
48
48
  : { isOpen, onToggleOpen: () => setIsOpen((current) => !current) } })), (0, jsx_runtime_1.jsx)(material_1.Collapse, { in: isOpen, unmountOnExit: true, children: (0, jsx_runtime_1.jsx)(material_1.Box, { sx: {
49
49
  display: 'grid',
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.Panel = void 0;
7
7
  const jsx_runtime_1 = require("react/jsx-runtime");
8
- // Copyright 2021 The Perses Authors
8
+ // Copyright 2022 The Perses Authors
9
9
  // Licensed under the Apache License, Version 2.0 (the "License");
10
10
  // you may not use this file except in compliance with the License.
11
11
  // You may obtain a copy of the License at
@@ -18,9 +18,10 @@ const jsx_runtime_1 = require("react/jsx-runtime");
18
18
  // See the License for the specific language governing permissions and
19
19
  // limitations under the License.
20
20
  const react_1 = require("react");
21
- const material_1 = require("@mui/material");
22
21
  const plugin_system_1 = require("@perses-dev/plugin-system");
23
22
  const components_1 = require("@perses-dev/components");
23
+ const material_1 = require("@mui/material");
24
+ const InformationOutline_1 = __importDefault(require("mdi-material-ui/InformationOutline"));
24
25
  const use_resize_observer_1 = __importDefault(require("use-resize-observer"));
25
26
  /**
26
27
  * Renders a PanelDefinition's content inside of a Card.
@@ -28,23 +29,27 @@ const use_resize_observer_1 = __importDefault(require("use-resize-observer"));
28
29
  function Panel(props) {
29
30
  const { definition, ...others } = props;
30
31
  const [contentElement, setContentElement] = (0, react_1.useState)(null);
31
- const isStatsChart = definition.kind === 'StatChart';
32
- const panelPadding = isStatsChart ? 0 : 2;
33
32
  const { width, height } = (0, use_resize_observer_1.default)({ ref: contentElement });
34
33
  const contentDimensions = (0, react_1.useMemo)(() => {
35
34
  if (width === undefined || height === undefined)
36
35
  return undefined;
37
36
  return { width, height };
38
37
  }, [width, height]);
38
+ // TODO: adjust padding for small panels, consistent way to determine isLargePanel here and in StatChart
39
+ const panelPadding = 1.5;
39
40
  return ((0, jsx_runtime_1.jsxs)(material_1.Card, { sx: {
40
41
  ...others.sx,
41
42
  width: '100%',
42
43
  height: '100%',
43
44
  display: 'flex',
44
45
  flexFlow: 'column nowrap',
45
- }, variant: "outlined", ...others, children: [(0, jsx_runtime_1.jsx)(material_1.CardHeader, { title: (0, jsx_runtime_1.jsx)(material_1.Typography, { component: "h2", variant: "body2", fontWeight: (theme) => theme.typography.fontWeightMedium, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", children: definition.display.name }), sx: {
46
+ }, variant: "outlined", ...others, children: [(0, jsx_runtime_1.jsx)(material_1.CardHeader, { title: (0, jsx_runtime_1.jsxs)(material_1.Box, { sx: {
47
+ display: 'flex',
48
+ alignItems: 'center',
49
+ }, children: [(0, jsx_runtime_1.jsx)(material_1.Typography, { component: "h2", variant: "body2", fontWeight: (theme) => theme.typography.fontWeightMedium, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", children: definition.display.name }), definition.display.description && ((0, jsx_runtime_1.jsx)(components_1.InfoTooltip, { id: "info-tooltip", description: definition.display.description, placement: components_1.TooltipPlacement.Right, children: (0, jsx_runtime_1.jsx)(InformationOutline_1.default, { "aria-describedby": "info-tooltip", "aria-hidden": false, sx: { fontSize: '1rem', position: 'relative', left: '4px', cursor: 'pointer' } }) }))] }), sx: {
46
50
  display: 'block',
47
- padding: (theme) => theme.spacing(1, 2),
51
+ padding: (theme) => theme.spacing(1, panelPadding),
52
+ borderBottom: (theme) => `solid 1px ${theme.palette.divider}`,
48
53
  } }), (0, jsx_runtime_1.jsx)(material_1.CardContent, { sx: {
49
54
  position: 'relative',
50
55
  overflow: 'hidden',
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const jsx_runtime_1 = require("react/jsx-runtime");
4
+ const plugin_system_1 = require("@perses-dev/plugin-system");
5
+ const react_1 = require("@testing-library/react");
6
+ const test_1 = require("../../test");
7
+ const Panel_1 = require("./Panel");
8
+ const FAKE_PANEL_PLUGIN = {
9
+ pluginType: 'Panel',
10
+ kind: 'FakePanel',
11
+ plugin: {
12
+ PanelComponent: () => {
13
+ return (0, jsx_runtime_1.jsx)("div", { role: "figure", children: "FakePanel chart" });
14
+ },
15
+ },
16
+ };
17
+ describe('Panel', () => {
18
+ let props;
19
+ beforeEach(() => {
20
+ props = {
21
+ definition: {
22
+ display: {
23
+ name: 'Fake Panel',
24
+ description: 'This is a fake panel',
25
+ },
26
+ kind: 'FakePanel',
27
+ options: {},
28
+ },
29
+ };
30
+ });
31
+ // Helper to render the panel with some context set
32
+ const renderPanel = () => {
33
+ const { addMockPlugin, pluginRegistryProps } = (0, test_1.mockPluginRegistryProps)();
34
+ addMockPlugin(FAKE_PANEL_PLUGIN);
35
+ (0, test_1.renderWithContext)((0, jsx_runtime_1.jsx)(plugin_system_1.PluginRegistry, { ...pluginRegistryProps, children: (0, jsx_runtime_1.jsx)(Panel_1.Panel, { ...props }) }));
36
+ };
37
+ it('should render name and info icon', async () => {
38
+ renderPanel();
39
+ await react_1.screen.findByText('Fake Panel');
40
+ react_1.screen.queryByLabelText('info-tooltip');
41
+ });
42
+ });
@@ -17,8 +17,8 @@ const jsx_runtime_1 = require("react/jsx-runtime");
17
17
  const material_1 = require("@mui/material");
18
18
  const components_1 = require("@perses-dev/components");
19
19
  const plugin_system_1 = require("@perses-dev/plugin-system");
20
- const context_1 = require("../context");
21
- const VariableAutocomplete_1 = require("./VariableAutocomplete");
20
+ const context_1 = require("../../context");
21
+ const VariableAutocomplete_1 = require("../VariableAutocomplete");
22
22
  const DRAWER_WIDTH = 296;
23
23
  /**
24
24
  * Dashboard options drawer that includes variable inputs.
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const jsx_runtime_1 = require("react/jsx-runtime");
7
+ // Copyright 2022 The Perses Authors
8
+ // Licensed under the Apache License, Version 2.0 (the "License");
9
+ // you may not use this file except in compliance with the License.
10
+ // You may obtain a copy of the License at
11
+ //
12
+ // http://www.apache.org/licenses/LICENSE-2.0
13
+ //
14
+ // Unless required by applicable law or agreed to in writing, software
15
+ // distributed under the License is distributed on an "AS IS" BASIS,
16
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ // See the License for the specific language governing permissions and
18
+ // limitations under the License.
19
+ const react_1 = require("@testing-library/react");
20
+ const user_event_1 = __importDefault(require("@testing-library/user-event"));
21
+ const plugin_system_1 = require("@perses-dev/plugin-system");
22
+ const test_1 = require("../../test");
23
+ const context_1 = require("../../context");
24
+ const VariableOptionsDrawer_1 = require("./VariableOptionsDrawer");
25
+ describe('VariableOptionsDrawer', () => {
26
+ const variables = {
27
+ job: {
28
+ display: {
29
+ label: 'Job',
30
+ },
31
+ kind: 'PrometheusLabelValues',
32
+ selection: {
33
+ default_value: 'node',
34
+ },
35
+ options: {
36
+ label_name: 'job',
37
+ match: ['node_uname_info'],
38
+ },
39
+ },
40
+ };
41
+ const options = {
42
+ data: ['node', 'all'],
43
+ isLoading: false,
44
+ error: undefined,
45
+ };
46
+ const FAKE_PANEL_PLUGIN = {
47
+ pluginType: 'Variable',
48
+ kind: 'PrometheusLabelValues',
49
+ plugin: {
50
+ useVariableOptions: () => {
51
+ return options;
52
+ },
53
+ },
54
+ };
55
+ const renderVariableOptionsDrawer = () => {
56
+ const { addMockPlugin, pluginRegistryProps } = (0, test_1.mockPluginRegistryProps)();
57
+ addMockPlugin(FAKE_PANEL_PLUGIN);
58
+ (0, test_1.renderWithContext)((0, jsx_runtime_1.jsx)(plugin_system_1.PluginRegistry, { ...pluginRegistryProps, children: (0, jsx_runtime_1.jsx)(context_1.TemplateVariablesProvider, { variableDefinitions: variables, children: (0, jsx_runtime_1.jsx)(VariableOptionsDrawer_1.VariableOptionsDrawer, { variables: variables }) }) }));
59
+ };
60
+ it('should display Variables as the title', async () => {
61
+ renderVariableOptionsDrawer();
62
+ await react_1.screen.findByText('Variables');
63
+ });
64
+ describe('VariableAutocomplete', () => {
65
+ it('should display correct variable', async () => {
66
+ renderVariableOptionsDrawer();
67
+ await react_1.screen.findByLabelText('Job');
68
+ });
69
+ it('should display correct default value', async () => {
70
+ renderVariableOptionsDrawer();
71
+ await react_1.screen.findByDisplayValue('node');
72
+ });
73
+ it('should display correct options', async () => {
74
+ renderVariableOptionsDrawer();
75
+ const openButton = await react_1.screen.findByRole('button', { name: 'Open' });
76
+ user_event_1.default.click(openButton);
77
+ await react_1.screen.findByText('all');
78
+ react_1.screen.getByText('node');
79
+ });
80
+ });
81
+ });
@@ -28,6 +28,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
29
  __exportStar(require("./Dashboard"), exports);
30
30
  __exportStar(require("./GridLayout"), exports);
31
- __exportStar(require("./Panel"), exports);
31
+ __exportStar(require("./Panel/Panel"), exports);
32
32
  __exportStar(require("./VariableAutocomplete"), exports);
33
- __exportStar(require("./VariableOptionsDrawer"), exports);
33
+ __exportStar(require("./VariableOptionsDrawer/VariableOptionsDrawer"), exports);
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ // Copyright 2022 The Perses Authors
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ var desc = Object.getOwnPropertyDescriptor(m, k);
17
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
18
+ desc = { enumerable: true, get: function() { return m[k]; } };
19
+ }
20
+ Object.defineProperty(o, k2, desc);
21
+ }) : (function(o, m, k, k2) {
22
+ if (k2 === undefined) k2 = k;
23
+ o[k2] = m[k];
24
+ }));
25
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
26
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ __exportStar(require("./plugin-registry"), exports);
30
+ __exportStar(require("./render"), exports);
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mockPluginRegistryProps = void 0;
4
+ /**
5
+ * Helper for mocking `PluginRegistry` data during tests. Returns props that can be spread on the `PluginRegistry`
6
+ * component so that it will load the mock plugins you setup. You can use the `addMockPlugin` function that's returned
7
+ * to add mock plugins before rendering components that use them.
8
+ */
9
+ function mockPluginRegistryProps() {
10
+ const mockPluginResource = {
11
+ kind: 'Plugin',
12
+ metadata: {
13
+ name: 'Fake Plugin for Tests',
14
+ },
15
+ spec: {
16
+ supported_kinds: {},
17
+ },
18
+ };
19
+ // Allow adding mock plugins in tests
20
+ const mockSetupFunctions = [];
21
+ const addMockPlugin = (config) => {
22
+ mockPluginResource.spec.supported_kinds[config.kind] = config.pluginType;
23
+ mockSetupFunctions.push((registerPlugin) => {
24
+ registerPlugin(config);
25
+ });
26
+ };
27
+ // Our mock plugin module just calls all the setup functions that were added
28
+ const mockPluginModule = {
29
+ setup(registerPlugin) {
30
+ for (const setup of mockSetupFunctions) {
31
+ setup(registerPlugin);
32
+ }
33
+ },
34
+ };
35
+ const pluginRegistryProps = {
36
+ getInstalledPlugins() {
37
+ return Promise.resolve([mockPluginResource]);
38
+ },
39
+ importPluginModule( /* resource */) {
40
+ return Promise.resolve(mockPluginModule);
41
+ },
42
+ };
43
+ return {
44
+ pluginRegistryProps,
45
+ addMockPlugin,
46
+ };
47
+ }
48
+ exports.mockPluginRegistryProps = mockPluginRegistryProps;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.renderWithContext = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ // Copyright 2022 The Perses Authors
6
+ // Licensed under the Apache License, Version 2.0 (the "License");
7
+ // you may not use this file except in compliance with the License.
8
+ // You may obtain a copy of the License at
9
+ //
10
+ // http://www.apache.org/licenses/LICENSE-2.0
11
+ //
12
+ // Unless required by applicable law or agreed to in writing, software
13
+ // distributed under the License is distributed on an "AS IS" BASIS,
14
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ // See the License for the specific language governing permissions and
16
+ // limitations under the License.
17
+ const react_1 = require("@testing-library/react");
18
+ const react_query_1 = require("react-query");
19
+ const queryClient = new react_query_1.QueryClient({ defaultOptions: { queries: { refetchOnWindowFocus: false } } });
20
+ /**
21
+ * Test helper to render a React component with some common app-level providers wrapped around it.
22
+ */
23
+ function renderWithContext(ui, options) {
24
+ return (0, react_1.render)((0, jsx_runtime_1.jsx)(react_query_1.QueryClientProvider, { client: queryClient, children: ui }), options);
25
+ }
26
+ exports.renderWithContext = renderWithContext;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ // Copyright 2022 The Perses Authors
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ // Add testing library assertions
16
+ require("@testing-library/jest-dom/extend-expect");
17
+ // Always mock e-charts during tests since we don't have a proper canvas in jsdom
18
+ jest.mock('echarts/core');
@@ -1 +1 @@
1
- import{jsx as _jsx}from"react/jsx-runtime";import{ErrorAlert}from"@perses-dev/components";import{resolvePanelRef}from"@perses-dev/core";import{Panel}from"../Panel";export function GridItemContent(r){const{content:e,spec:o}=r;try{const r=resolvePanelRef(o,e);return _jsx(Panel,{definition:r})}catch(r){return _jsx(ErrorAlert,{error:r})}}
1
+ import{jsx as _jsx}from"react/jsx-runtime";import{ErrorAlert}from"@perses-dev/components";import{resolvePanelRef}from"@perses-dev/core";import{Panel}from"../Panel/Panel";export function GridItemContent(e){const{content:r,spec:o}=e;try{const e=resolvePanelRef(o,r);return _jsx(Panel,{definition:e})}catch(e){return _jsx(ErrorAlert,{error:e})}}
@@ -1 +1 @@
1
- import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import{useState}from"react";import{Box,Collapse}from"@mui/material";import{GridTitle}from"./GridTitle";const COLUMNS=24;export function GridLayout(i){var o,s;const{definition:{display:t,items:e},renderGridItemContent:n,...r}=i,[l,a]=useState(null===(s=null===(o=null==t?void 0:t.collapse)||void 0===o?void 0:o.open)||void 0===s||s),p=[];let d=1;return e.forEach(((i,o)=>{const s=24/i.width,t=Math.floor(i.height*s);p.push(_jsx(Box,{sx:{gridColumn:{xs:"1 / span 24",sm:`${i.x+1} / span ${i.width}`},gridRow:{xs:`${d} / span ${t}`,sm:`${i.y+1} / span ${i.height}`}},children:n(i)},o)),d+=t})),_jsxs(Box,{...r,component:"section",sx:{"& + &":{marginTop:i=>i.spacing(1)}},children:[void 0!==t&&_jsx(GridTitle,{title:t.title,collapse:void 0===t.collapse?void 0:{isOpen:l,onToggleOpen:()=>a((i=>!i))}}),_jsx(Collapse,{in:l,unmountOnExit:!0,children:_jsx(Box,{sx:{display:"grid",gridTemplateColumns:"repeat(24, 1fr)",gridAutoRows:{xs:24,sm:36},columnGap:i=>i.spacing(1),rowGap:i=>i.spacing(1)},children:p})})]})}
1
+ import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import{useState}from"react";import{Box,Collapse}from"@mui/material";import{GridTitle}from"./GridTitle";const COLUMNS=24;export function GridLayout(i){var s,o,e;const{definition:{spec:t},renderGridItemContent:n,...l}=i,[r,a]=useState(null===(e=null===(o=null===(s=t.display)||void 0===s?void 0:s.collapse)||void 0===o?void 0:o.open)||void 0===e||e),p=[];let d=1;return t.items.forEach(((i,s)=>{const o=24/i.width,e=Math.floor(i.height*o);p.push(_jsx(Box,{sx:{gridColumn:{xs:"1 / span 24",sm:`${i.x+1} / span ${i.width}`},gridRow:{xs:`${d} / span ${e}`,sm:`${i.y+1} / span ${i.height}`}},children:n(i)},s)),d+=e})),_jsxs(Box,{...l,component:"section",sx:{"& + &":{marginTop:i=>i.spacing(1)}},children:[void 0!==t.display&&_jsx(GridTitle,{title:t.display.title,collapse:void 0===t.display.collapse?void 0:{isOpen:r,onToggleOpen:()=>a((i=>!i))}}),_jsx(Collapse,{in:r,unmountOnExit:!0,children:_jsx(Box,{sx:{display:"grid",gridTemplateColumns:"repeat(24, 1fr)",gridAutoRows:{xs:24,sm:36},columnGap:i=>i.spacing(1),rowGap:i=>i.spacing(1)},children:p})})]})}
@@ -1,6 +1,6 @@
1
1
  /// <reference types="react" />
2
- import { CardProps } from '@mui/material';
3
2
  import { PanelDefinition } from '@perses-dev/core';
3
+ import { CardProps } from '@mui/material';
4
4
  export interface PanelProps extends CardProps {
5
5
  definition: PanelDefinition;
6
6
  }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Panel.d.ts","sourceRoot":"","sources":["../../../src/components/Panel/Panel.tsx"],"names":[],"mappings":";AAgBA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAa,SAAS,EAAuC,MAAM,eAAe,CAAC;AAI1F,MAAM,WAAW,UAAW,SAAQ,SAAS;IAC3C,UAAU,EAAE,eAAe,CAAC;CAC7B;AAED;;GAEG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,UAAU,eAoFtC"}
@@ -0,0 +1 @@
1
+ import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import{useState,useMemo}from"react";import{PluginBoundary,PanelComponent}from"@perses-dev/plugin-system";import{ErrorAlert,InfoTooltip,TooltipPlacement}from"@perses-dev/components";import{Box,Card,CardHeader,CardContent,Typography}from"@mui/material";import InformationOutlineIcon from"mdi-material-ui/InformationOutline";import useResizeObserver from"use-resize-observer";export function Panel(e){const{definition:i,...o}=e,[r,t]=useState(null),{width:n,height:s}=useResizeObserver({ref:r}),a=useMemo((()=>{if(void 0!==n&&void 0!==s)return{width:n,height:s}}),[n,s]);return _jsxs(Card,{sx:{...o.sx,width:"100%",height:"100%",display:"flex",flexFlow:"column nowrap"},variant:"outlined",...o,children:[_jsx(CardHeader,{title:_jsxs(Box,{sx:{display:"flex",alignItems:"center"},children:[_jsx(Typography,{component:"h2",variant:"body2",fontWeight:e=>e.typography.fontWeightMedium,whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis",children:i.display.name}),i.display.description&&_jsx(InfoTooltip,{id:"info-tooltip",description:i.display.description,placement:TooltipPlacement.Right,children:_jsx(InformationOutlineIcon,{"aria-describedby":"info-tooltip","aria-hidden":!1,sx:{fontSize:"1rem",position:"relative",left:"4px",cursor:"pointer"}})})]}),sx:{display:"block",padding:e=>e.spacing(1,1.5),borderBottom:e=>`solid 1px ${e.palette.divider}`}}),_jsx(CardContent,{sx:{position:"relative",overflow:"hidden",flexGrow:1,padding:e=>e.spacing(1.5),":last-child":{padding:e=>e.spacing(1.5)}},ref:t,children:_jsx(PluginBoundary,{loadingFallback:"Loading...",ErrorFallbackComponent:ErrorAlert,children:_jsx(PanelComponent,{definition:i,contentDimensions:a})})})]})}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=Panel.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Panel.test.d.ts","sourceRoot":"","sources":["../../../src/components/Panel/Panel.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1 @@
1
+ import{jsx as _jsx}from"react/jsx-runtime";import{PluginRegistry}from"@perses-dev/plugin-system";import{screen}from"@testing-library/react";import{renderWithContext,mockPluginRegistryProps}from"../../test";import{Panel}from"./Panel";const FAKE_PANEL_PLUGIN={pluginType:"Panel",kind:"FakePanel",plugin:{PanelComponent:()=>_jsx("div",{role:"figure",children:"FakePanel chart"})}};describe("Panel",(()=>{let e;beforeEach((()=>{e={definition:{display:{name:"Fake Panel",description:"This is a fake panel"},kind:"FakePanel",options:{}}}})),it("should render name and info icon",(async()=>{(()=>{const{addMockPlugin:n,pluginRegistryProps:i}=mockPluginRegistryProps();n(FAKE_PANEL_PLUGIN),renderWithContext(_jsx(PluginRegistry,{...i,children:_jsx(Panel,{...e})}))})(),await screen.findByText("Fake Panel"),screen.queryByLabelText("info-tooltip")}))}));
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VariableOptionsDrawer.d.ts","sourceRoot":"","sources":["../../../src/components/VariableOptionsDrawer/VariableOptionsDrawer.tsx"],"names":[],"mappings":";AAaA,OAAO,EAAqB,UAAU,EAAE,MAAM,eAAe,CAAC;AAE9D,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAOjD,MAAM,WAAW,0BAA2B,SAAQ,UAAU;IAC5D,SAAS,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;CACvC;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,0BAA0B,eA8CtE"}
@@ -0,0 +1 @@
1
+ import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import{Paper,Typography}from"@mui/material";import{ErrorAlert,combineSx}from"@perses-dev/components";import{PluginBoundary,useTemplateVariables}from"@perses-dev/plugin-system";import{useTemplateVariablesSetters}from"../../context";import{VariableAutocomplete}from"../VariableAutocomplete";const DRAWER_WIDTH=296;export function VariableOptionsDrawer(e){const{variables:r,sx:t,...a}=e,{variables:o}=useTemplateVariables(),{setValue:i,setOptions:s}=useTemplateVariablesSetters();return _jsxs(Paper,{sx:combineSx({width:296,flexShrink:0,padding:e=>e.spacing(1,2),borderLeft:e=>`1px solid ${e.palette.divider}`},t),square:!0,elevation:0,...a,children:[_jsx(Typography,{component:"h2",variant:"h6",children:"Variables"}),Object.entries(r).map((([e,r])=>{if(!0===r.display.hide)return null;const t=o[e];if(void 0===t){const r=new Error(`Variable state for '${e}' not found`);return _jsx(ErrorAlert,{error:r},e)}return _jsx(PluginBoundary,{loadingFallback:"Loading...",ErrorFallbackComponent:ErrorAlert,children:_jsx(VariableAutocomplete,{definition:r,state:t,onChange:r=>i(e,r),onOptionsChange:r=>s(e,r)})},e)}))]})}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=VariableOptionsDrawer.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VariableOptionsDrawer.test.d.ts","sourceRoot":"","sources":["../../../src/components/VariableOptionsDrawer/VariableOptionsDrawer.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1 @@
1
+ import{jsx as _jsx}from"react/jsx-runtime";import{screen}from"@testing-library/react";import userEvent from"@testing-library/user-event";import{PluginRegistry}from"@perses-dev/plugin-system";import{mockPluginRegistryProps,renderWithContext}from"../../test";import{TemplateVariablesProvider}from"../../context";import{VariableOptionsDrawer}from"./VariableOptionsDrawer";describe("VariableOptionsDrawer",(()=>{const e={job:{display:{label:"Job"},kind:"PrometheusLabelValues",selection:{default_value:"node"},options:{label_name:"job",match:["node_uname_info"]}}},i={data:["node","all"],isLoading:!1,error:void 0},r={pluginType:"Variable",kind:"PrometheusLabelValues",plugin:{useVariableOptions:()=>i}},a=()=>{const{addMockPlugin:i,pluginRegistryProps:a}=mockPluginRegistryProps();i(r),renderWithContext(_jsx(PluginRegistry,{...a,children:_jsx(TemplateVariablesProvider,{variableDefinitions:e,children:_jsx(VariableOptionsDrawer,{variables:e})})}))};it("should display Variables as the title",(async()=>{a(),await screen.findByText("Variables")})),describe("VariableAutocomplete",(()=>{it("should display correct variable",(async()=>{a(),await screen.findByLabelText("Job")})),it("should display correct default value",(async()=>{a(),await screen.findByDisplayValue("node")})),it("should display correct options",(async()=>{a();const e=await screen.findByRole("button",{name:"Open"});userEvent.click(e),await screen.findByText("all"),screen.getByText("node")}))}))}));
@@ -1,6 +1,6 @@
1
1
  export * from './Dashboard';
2
2
  export * from './GridLayout';
3
- export * from './Panel';
3
+ export * from './Panel/Panel';
4
4
  export * from './VariableAutocomplete';
5
- export * from './VariableOptionsDrawer';
5
+ export * from './VariableOptionsDrawer/VariableOptionsDrawer';
6
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAaA,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,SAAS,CAAC;AACxB,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAaA,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,wBAAwB,CAAC;AACvC,cAAc,+CAA+C,CAAC"}
@@ -1 +1 @@
1
- export*from"./Dashboard";export*from"./GridLayout";export*from"./Panel";export*from"./VariableAutocomplete";export*from"./VariableOptionsDrawer";
1
+ export*from"./Dashboard";export*from"./GridLayout";export*from"./Panel/Panel";export*from"./VariableAutocomplete";export*from"./VariableOptionsDrawer/VariableOptionsDrawer";
@@ -0,0 +1,3 @@
1
+ export * from './plugin-registry';
2
+ export * from './render';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/test/index.ts"],"names":[],"mappings":"AAaA,cAAc,mBAAmB,CAAC;AAClC,cAAc,UAAU,CAAC"}
@@ -0,0 +1 @@
1
+ export*from"./plugin-registry";export*from"./render";
@@ -0,0 +1,11 @@
1
+ import { PluginRegistryProps, RegisterPlugin } from '@perses-dev/plugin-system';
2
+ /**
3
+ * Helper for mocking `PluginRegistry` data during tests. Returns props that can be spread on the `PluginRegistry`
4
+ * component so that it will load the mock plugins you setup. You can use the `addMockPlugin` function that's returned
5
+ * to add mock plugins before rendering components that use them.
6
+ */
7
+ export declare function mockPluginRegistryProps(): {
8
+ pluginRegistryProps: Omit<PluginRegistryProps, "children">;
9
+ addMockPlugin: RegisterPlugin;
10
+ };
11
+ //# sourceMappingURL=plugin-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-registry.d.ts","sourceRoot":"","sources":["../../src/test/plugin-registry.ts"],"names":[],"mappings":"AAYA,OAAO,EAEL,mBAAmB,EAGnB,cAAc,EACf,MAAM,2BAA2B,CAAC;AAEnC;;;;GAIG;AACH,wBAAgB,uBAAuB;;;EA0CtC"}
@@ -0,0 +1 @@
1
+ export function mockPluginRegistryProps(){const e={kind:"Plugin",metadata:{name:"Fake Plugin for Tests"},spec:{supported_kinds:{}}},s=[],n={setup(e){for(const n of s)n(e)}};return{pluginRegistryProps:{getInstalledPlugins:()=>Promise.resolve([e]),importPluginModule:()=>Promise.resolve(n)},addMockPlugin:n=>{e.spec.supported_kinds[n.kind]=n.pluginType,s.push((e=>{e(n)}))}}}
@@ -0,0 +1,7 @@
1
+ /// <reference types="react" />
2
+ import { RenderOptions } from '@testing-library/react';
3
+ /**
4
+ * Test helper to render a React component with some common app-level providers wrapped around it.
5
+ */
6
+ export declare function renderWithContext(ui: React.ReactElement, options?: Omit<RenderOptions, 'queries'>): import("@testing-library/react").RenderResult<typeof import("@testing-library/dom/types/queries"), HTMLElement, HTMLElement>;
7
+ //# sourceMappingURL=render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/test/render.tsx"],"names":[],"mappings":";AAaA,OAAO,EAAU,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAK/D;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,KAAK,CAAC,YAAY,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,SAAS,CAAC,gIAEjG"}
@@ -0,0 +1 @@
1
+ import{jsx as _jsx}from"react/jsx-runtime";import{render}from"@testing-library/react";import{QueryClient,QueryClientProvider}from"react-query";const queryClient=new QueryClient({defaultOptions:{queries:{refetchOnWindowFocus:!1}}});export function renderWithContext(e,r){return render(_jsx(QueryClientProvider,{client:queryClient,children:e}),r)}
@@ -0,0 +1,2 @@
1
+ import '@testing-library/jest-dom/extend-expect';
2
+ //# sourceMappingURL=setup-tests.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup-tests.d.ts","sourceRoot":"","sources":["../../src/test/setup-tests.ts"],"names":[],"mappings":"AAcA,OAAO,yCAAyC,CAAC"}
@@ -0,0 +1 @@
1
+ import"@testing-library/jest-dom/extend-expect";jest.mock("echarts/core");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@perses-dev/dashboards",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "The dashboards feature in Perses",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://github.com/perses/perses/blob/main/README.md",
@@ -18,16 +18,17 @@
18
18
  "clean": "rimraf dist/",
19
19
  "build": "tsc --build",
20
20
  "build:cjs": "tsc --project ./tsconfig.cjs.json",
21
- "test": "echo 'no test to run' && exit 0",
21
+ "test": "TZ=UTC jest",
22
+ "test:watch": "TZ=UTC jest --watch",
22
23
  "lint": "eslint src --ext .ts,.tsx",
23
24
  "lint:fix": "eslint --fix src --ext .ts,.tsx"
24
25
  },
25
26
  "dependencies": {
26
- "@perses-dev/components": "^0.4.0",
27
- "@perses-dev/core": "^0.4.0",
28
- "@perses-dev/plugin-system": "^0.4.0",
29
- "immer": "^9.0.12",
30
- "use-immer": "^0.6.0",
27
+ "@perses-dev/components": "^0.5.0",
28
+ "@perses-dev/core": "^0.5.0",
29
+ "@perses-dev/plugin-system": "^0.5.0",
30
+ "immer": "^9.0.15",
31
+ "use-immer": "^0.7.0",
31
32
  "use-resize-observer": "^8.0.0"
32
33
  },
33
34
  "peerDependencies": {
@@ -1 +0,0 @@
1
- {"version":3,"file":"Panel.d.ts","sourceRoot":"","sources":["../../src/components/Panel.tsx"],"names":[],"mappings":";AAcA,OAAO,EAAQ,SAAS,EAAuC,MAAM,eAAe,CAAC;AAIrF,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,MAAM,WAAW,UAAW,SAAQ,SAAS;IAC3C,UAAU,EAAE,eAAe,CAAC;CAC7B;AAED;;GAEG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,UAAU,eA8DtC"}
@@ -1 +0,0 @@
1
- import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import{useState,useMemo}from"react";import{Card,CardHeader,CardContent,Typography}from"@mui/material";import{PluginBoundary,PanelComponent}from"@perses-dev/plugin-system";import{ErrorAlert}from"@perses-dev/components";import useResizeObserver from"use-resize-observer";export function Panel(e){const{definition:r,...i}=e,[o,n]=useState(null),t="StatChart"===r.kind?0:2,{width:s,height:a}=useResizeObserver({ref:o}),d=useMemo((()=>{if(void 0!==s&&void 0!==a)return{width:s,height:a}}),[s,a]);return _jsxs(Card,{sx:{...i.sx,width:"100%",height:"100%",display:"flex",flexFlow:"column nowrap"},variant:"outlined",...i,children:[_jsx(CardHeader,{title:_jsx(Typography,{component:"h2",variant:"body2",fontWeight:e=>e.typography.fontWeightMedium,whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis",children:r.display.name}),sx:{display:"block",padding:e=>e.spacing(1,2)}}),_jsx(CardContent,{sx:{position:"relative",overflow:"hidden",flexGrow:1,padding:e=>e.spacing(t),":last-child":{padding:e=>e.spacing(t)}},ref:n,children:_jsx(PluginBoundary,{loadingFallback:"Loading...",ErrorFallbackComponent:ErrorAlert,children:_jsx(PanelComponent,{definition:r,contentDimensions:d})})})]})}
@@ -1 +0,0 @@
1
- {"version":3,"file":"VariableOptionsDrawer.d.ts","sourceRoot":"","sources":["../../src/components/VariableOptionsDrawer.tsx"],"names":[],"mappings":";AAaA,OAAO,EAAqB,UAAU,EAAE,MAAM,eAAe,CAAC;AAE9D,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAOjD,MAAM,WAAW,0BAA2B,SAAQ,UAAU;IAC5D,SAAS,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;CACvC;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,0BAA0B,eA8CtE"}
@@ -1 +0,0 @@
1
- import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import{Paper,Typography}from"@mui/material";import{ErrorAlert,combineSx}from"@perses-dev/components";import{PluginBoundary,useTemplateVariables}from"@perses-dev/plugin-system";import{useTemplateVariablesSetters}from"../context";import{VariableAutocomplete}from"./VariableAutocomplete";const DRAWER_WIDTH=296;export function VariableOptionsDrawer(e){const{variables:r,sx:t,...a}=e,{variables:o}=useTemplateVariables(),{setValue:i,setOptions:s}=useTemplateVariablesSetters();return _jsxs(Paper,{sx:combineSx({width:296,flexShrink:0,padding:e=>e.spacing(1,2),borderLeft:e=>`1px solid ${e.palette.divider}`},t),square:!0,elevation:0,...a,children:[_jsx(Typography,{component:"h2",variant:"h6",children:"Variables"}),Object.entries(r).map((([e,r])=>{if(!0===r.display.hide)return null;const t=o[e];if(void 0===t){const r=new Error(`Variable state for '${e}' not found`);return _jsx(ErrorAlert,{error:r},e)}return _jsx(PluginBoundary,{loadingFallback:"Loading...",ErrorFallbackComponent:ErrorAlert,children:_jsx(VariableAutocomplete,{definition:r,state:t,onChange:r=>i(e,r),onOptionsChange:r=>s(e,r)})},e)}))]})}