diff --git a/.eslintrc b/.eslintrc index 5df519a..99c3ab5 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,20 +1,17 @@ { - "extends": "./.config/.eslintrc", + "extends": ["./.config/.eslintrc", "@volkovlabs/eslint-config"], "parser": "@typescript-eslint/parser", "parserOptions": { "ecmaVersion": "latest", "project": "./tsconfig.json", "sourceType": "module" }, - "plugins": ["deprecation"], - "rules": { - "deprecation/deprecation": ["warn"], - "sort-imports": [ - "error", - { - "ignoreCase": true, - "ignoreDeclarationSort": true + "overrides": [ + { + "files": ["**/*.test.tsx", "**/*.test.ts", "src/__testUtils__/**/*", "**/__mocks__/**/*"], + "rules": { + "@typescript-eslint/no-explicit-any": "off" } - ] - } + } + ] } diff --git a/CHANGELOG.md b/CHANGELOG.md index 9856f37..aa775dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 4.2.0 (IN PROGRESS) + +- Update ESLint configuration and refactoring + ## 4.1.0 (2023-10-29) ### Features / Enhancements diff --git a/LICENSE b/LICENSE index 924404e..37c7ae0 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2021-2023 Volkov Labs + Copyright 2021-2024 Volkov Labs Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/cypress/integration/01-view-panel.test.ts b/cypress/integration/01-view-panel.test.ts index c880af5..5735bbc 100644 --- a/cypress/integration/01-view-panel.test.ts +++ b/cypress/integration/01-view-panel.test.ts @@ -1,5 +1,5 @@ import { e2e } from '@grafana/e2e'; -import { TestIds } from '../../src/constants'; +import { TEST_IDS } from '../../src/constants'; /** * Dashboard @@ -29,7 +29,7 @@ describe('Viewing a panel with an Image', () => { /** * Image */ - const image = currentPanel.find(getTestIdSelector(TestIds.panel.root)); + const image = currentPanel.find(getTestIdSelector(TEST_IDS.panel.root)); image.should('be.visible'); /** diff --git a/jest-setup.js b/jest-setup.js index 35a700b..264e914 100644 --- a/jest-setup.js +++ b/jest-setup.js @@ -1,2 +1,9 @@ // Jest setup provided by Grafana scaffolding import './.config/jest-setup'; + +import { TextDecoder, TextEncoder } from 'util'; + +/** + * Assign Text Decoder and Encoder which are required in @grafana/ui + */ +Object.assign(global, { TextDecoder, TextEncoder }); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 2683dcc..3972b19 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "volkovlabs-image-panel", - "version": "4.1.0", + "version": "4.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "volkovlabs-image-panel", - "version": "4.1.0", + "version": "4.2.0", "license": "Apache-2.0", "dependencies": { "@emotion/css": "^11.11.2", @@ -37,6 +37,7 @@ "@types/lodash": "^4.14.200", "@types/node": "^18.18.7", "@typescript-eslint/eslint-plugin": "^6.9.0", + "@volkovlabs/eslint-config": "^1.3.0", "copy-webpack-plugin": "^11.0.0", "css-loader": "^6.8.1", "eslint-plugin-deprecation": "^2.0.0", @@ -6430,7 +6431,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.9.0.tgz", "integrity": "sha512-GZmjMh4AJ/5gaH4XF2eXA8tMnHWP+Pm1mjQR2QN4Iz+j/zO04b9TOvJYOX2sCNIQHtRStKTxRY1FX7LhpJT4Gw==", "dev": true, - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "6.9.0", "@typescript-eslint/types": "6.9.0", @@ -6660,6 +6660,21 @@ "dev": true, "peer": true }, + "node_modules/@volkovlabs/eslint-config": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@volkovlabs/eslint-config/-/eslint-config-1.3.0.tgz", + "integrity": "sha512-xrzF9aj1tP/LEiKYJJSfEKiaIVm7mBhYFdAVaYqejL/NIgcRPDhP8EzL120rggDEaGc5yO/zy82cFTfE/3UiNw==", + "dev": true, + "dependencies": { + "@typescript-eslint/eslint-plugin": "^6.0.0", + "@typescript-eslint/parser": "^6.0.0", + "eslint-plugin-deprecation": "^2.0.0", + "eslint-plugin-simple-import-sort": "^10.0.0" + }, + "peerDependencies": { + "eslint": "^8.0.0" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", @@ -10220,6 +10235,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/eslint-plugin-simple-import-sort": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-10.0.0.tgz", + "integrity": "sha512-AeTvO9UCMSNzIHRkg8S6c3RPy5YEwKWSQPx3DYghLedo2ZQxowPFLGDN1AZ2evfg6r6mjBSZSLxLFsWSu3acsw==", + "dev": true, + "peerDependencies": { + "eslint": ">=5.0.0" + } + }, "node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", diff --git a/package.json b/package.json index 896d88e..0b8bfb1 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "@types/lodash": "^4.14.200", "@types/node": "^18.18.7", "@typescript-eslint/eslint-plugin": "^6.9.0", + "@volkovlabs/eslint-config": "^1.3.0", "copy-webpack-plugin": "^11.0.0", "css-loader": "^6.8.1", "eslint-plugin-deprecation": "^2.0.0", @@ -73,5 +74,5 @@ "test:ci": "jest --maxWorkers 4 --coverage", "upgrade": "npm upgrade --save" }, - "version": "4.1.0" -} + "version": "4.2.0" +} \ No newline at end of file diff --git a/src/components/ImagePanel/ImagePanel.styles.ts b/src/components/ImagePanel/ImagePanel.styles.ts index cdc728e..e8f4f67 100644 --- a/src/components/ImagePanel/ImagePanel.styles.ts +++ b/src/components/ImagePanel/ImagePanel.styles.ts @@ -4,7 +4,7 @@ import { GrafanaTheme2 } from '@grafana/data'; /** * Styles */ -export const Styles = (theme: GrafanaTheme2) => { +export const getStyles = (theme: GrafanaTheme2) => { return { wrapper: css` position: relative; diff --git a/src/components/ImagePanel/ImagePanel.test.tsx b/src/components/ImagePanel/ImagePanel.test.tsx index fa0bdf4..0cdc986 100644 --- a/src/components/ImagePanel/ImagePanel.test.tsx +++ b/src/components/ImagePanel/ImagePanel.test.tsx @@ -1,9 +1,10 @@ -import saveAs from 'file-saver'; -import React from 'react'; import { FieldType, toDataFrame } from '@grafana/data'; import { fireEvent, render, screen } from '@testing-library/react'; -import { ImageFields, ImageSizeModes, TestIds } from '../../constants'; -import { ButtonType, ZoomType } from '../../types'; +import saveAs from 'file-saver'; +import React from 'react'; + +import { TEST_IDS } from '../../constants'; +import { ButtonType, ImageField, ImageSizeMode, ZoomType } from '../../types'; import { ImagePanel } from './ImagePanel'; /** @@ -31,7 +32,7 @@ jest.mock('file-saver', () => jest.fn()); */ jest.mock('react-medium-image-zoom', () => ({ Controlled: jest.fn(({ isZoomed, children, zoomImg }) => { - return isZoomed ? : children; + return isZoomed ? : children; }), })); @@ -65,8 +66,8 @@ describe('Image Panel', () => { }) ); - expect(screen.getByTestId(TestIds.panel.root)).toBeInTheDocument(); - expect(screen.getByTestId(TestIds.panel.warning)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.root)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.warning)).toBeInTheDocument(); }); it('Should render image', async () => { @@ -79,7 +80,7 @@ describe('Image Panel', () => { fields: [ { type: FieldType.string, - name: ImageFields.IMG, + name: ImageField.IMG, values: ['/9j/4AAQSkZJRAAdLxAACEAAIX/9k='], }, ], @@ -89,8 +90,8 @@ describe('Image Panel', () => { }) ); - expect(screen.getByTestId(TestIds.panel.root)).toBeInTheDocument(); - expect(screen.getByTestId(TestIds.panel.image)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.root)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.image)).toBeInTheDocument(); }); it('Should render application', async () => { @@ -103,7 +104,7 @@ describe('Image Panel', () => { fields: [ { type: FieldType.string, - name: ImageFields.IMG, + name: ImageField.IMG, values: ['JVBERi0xLjMKJcTl8uXrp/jQ0CiUlRU9GCg=='], }, ], @@ -113,8 +114,8 @@ describe('Image Panel', () => { }) ); - expect(screen.getByTestId(TestIds.panel.root)).toBeInTheDocument(); - expect(screen.getByTestId(TestIds.panel.iframe)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.root)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.iframe)).toBeInTheDocument(); }); it('Should render image with header', async () => { @@ -127,7 +128,7 @@ describe('Image Panel', () => { fields: [ { type: FieldType.string, - name: ImageFields.IMG, + name: ImageField.IMG, values: ['data:image/jpg;base64,/9j/4AAQSkZJRgABA9k='], }, ], @@ -137,8 +138,8 @@ describe('Image Panel', () => { }) ); - expect(screen.getByTestId(TestIds.panel.root)).toBeInTheDocument(); - expect(screen.getByTestId(TestIds.panel.image)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.root)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.image)).toBeInTheDocument(); }); it('Should render application with header', async () => { @@ -151,7 +152,7 @@ describe('Image Panel', () => { fields: [ { type: FieldType.string, - name: ImageFields.IMG, + name: ImageField.IMG, values: ['data:application/pdf;base64,JVBERiiUlRU9GCg=='], }, ], @@ -161,8 +162,8 @@ describe('Image Panel', () => { }) ); - expect(screen.getByTestId(TestIds.panel.root)).toBeInTheDocument(); - expect(screen.getByTestId(TestIds.panel.iframe)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.root)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.iframe)).toBeInTheDocument(); }); it('Should render raw image', async () => { @@ -185,8 +186,8 @@ describe('Image Panel', () => { }) ); - expect(screen.getByTestId(TestIds.panel.root)).toBeInTheDocument(); - expect(screen.getByTestId(TestIds.panel.image)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.root)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.image)).toBeInTheDocument(); }); it('Should render raw image with URL', async () => { @@ -211,9 +212,9 @@ describe('Image Panel', () => { }) ); - expect(screen.getByTestId(TestIds.panel.root)).toBeInTheDocument(); - expect(screen.getByTestId(TestIds.panel.imageLink)).toBeInTheDocument(); - expect(screen.getByTestId(TestIds.panel.image)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.root)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.imageLink)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.image)).toBeInTheDocument(); }); describe('Image height', () => { @@ -232,24 +233,24 @@ describe('Image Panel', () => { }, { type: FieldType.string, - name: ImageFields.IMG, + name: ImageField.IMG, values: ['data:image/jpg;base64,/9j/4AAQSkZJRgABA9k='], }, ], }), ], }, - options: { name: ImageFields.IMG, widthMode: ImageSizeModes.AUTO, heightMode: ImageSizeModes.AUTO }, + options: { name: ImageField.IMG, widthMode: ImageSizeMode.AUTO, heightMode: ImageSizeMode.AUTO }, height: 50, width: 50, }) ); - expect(screen.getByTestId(TestIds.panel.root)).toBeInTheDocument(); - expect(screen.getByTestId(TestIds.panel.image)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.root)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.image)).toBeInTheDocument(); - expect(screen.getByTestId(TestIds.panel.image)).toHaveAttribute('width', '50'); - expect(screen.getByTestId(TestIds.panel.image)).toHaveAttribute('height', '50'); + expect(screen.getByTestId(TEST_IDS.panel.image)).toHaveAttribute('width', '50'); + expect(screen.getByTestId(TEST_IDS.panel.image)).toHaveAttribute('height', '50'); }); it('Should remove toolbar height from image height', async () => { @@ -267,7 +268,7 @@ describe('Image Panel', () => { }, { type: FieldType.string, - name: ImageFields.IMG, + name: ImageField.IMG, values: ['data:image/jpg;base64,/9j/4AAQSkZJRgABA9k='], }, ], @@ -275,9 +276,9 @@ describe('Image Panel', () => { ], }, options: { - name: ImageFields.IMG, - widthMode: ImageSizeModes.AUTO, - heightMode: ImageSizeModes.AUTO, + name: ImageField.IMG, + widthMode: ImageSizeMode.AUTO, + heightMode: ImageSizeMode.AUTO, toolbar: true, buttons: [ButtonType.DOWNLOAD], }, @@ -286,10 +287,10 @@ describe('Image Panel', () => { }) ); - expect(screen.getByTestId(TestIds.panel.image)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.image)).toBeInTheDocument(); - expect(screen.getByTestId(TestIds.panel.image)).toHaveAttribute('width', '200'); - expect(screen.getByTestId(TestIds.panel.image)).toHaveAttribute('height', (200 - elementHeight).toString()); + expect(screen.getByTestId(TEST_IDS.panel.image)).toHaveAttribute('width', '200'); + expect(screen.getByTestId(TEST_IDS.panel.image)).toHaveAttribute('height', (200 - elementHeight).toString()); }); it('Should remove description height from image height', async () => { @@ -307,7 +308,7 @@ describe('Image Panel', () => { }, { type: FieldType.string, - name: ImageFields.IMG, + name: ImageField.IMG, values: ['data:image/jpg;base64,/9j/4AAQSkZJRgABA9k='], }, ], @@ -315,10 +316,10 @@ describe('Image Panel', () => { ], }, options: { - name: ImageFields.IMG, + name: ImageField.IMG, description: 'imageDescription', - widthMode: ImageSizeModes.AUTO, - heightMode: ImageSizeModes.AUTO, + widthMode: ImageSizeMode.AUTO, + heightMode: ImageSizeMode.AUTO, toolbar: true, buttons: [ButtonType.DOWNLOAD], }, @@ -327,10 +328,10 @@ describe('Image Panel', () => { }) ); - expect(screen.getByTestId(TestIds.panel.image)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.image)).toBeInTheDocument(); - expect(screen.getByTestId(TestIds.panel.image)).toHaveAttribute('width', '200'); - expect(screen.getByTestId(TestIds.panel.image)).toHaveAttribute('height', (200 - elementHeight * 2).toString()); + expect(screen.getByTestId(TEST_IDS.panel.image)).toHaveAttribute('width', '200'); + expect(screen.getByTestId(TEST_IDS.panel.image)).toHaveAttribute('height', (200 - elementHeight * 2).toString()); }); it('Should not remove description height if no description', async () => { @@ -343,7 +344,7 @@ describe('Image Panel', () => { fields: [ { type: FieldType.string, - name: ImageFields.IMG, + name: ImageField.IMG, values: ['data:image/jpg;base64,/9j/4AAQSkZJRgABA9k='], }, ], @@ -351,10 +352,10 @@ describe('Image Panel', () => { ], }, options: { - name: ImageFields.IMG, + name: ImageField.IMG, description: 'imageDescription', - widthMode: ImageSizeModes.AUTO, - heightMode: ImageSizeModes.AUTO, + widthMode: ImageSizeMode.AUTO, + heightMode: ImageSizeMode.AUTO, toolbar: true, buttons: [ButtonType.DOWNLOAD], }, @@ -363,10 +364,10 @@ describe('Image Panel', () => { }) ); - expect(screen.getByTestId(TestIds.panel.image)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.image)).toBeInTheDocument(); - expect(screen.getByTestId(TestIds.panel.image)).toHaveAttribute('width', '200'); - expect(screen.getByTestId(TestIds.panel.image)).toHaveAttribute('height', (200 - elementHeight).toString()); + expect(screen.getByTestId(TEST_IDS.panel.image)).toHaveAttribute('width', '200'); + expect(screen.getByTestId(TEST_IDS.panel.image)).toHaveAttribute('height', (200 - elementHeight).toString()); }); describe('Image height updates', () => { @@ -382,7 +383,7 @@ describe('Image Panel', () => { }, { type: FieldType.string, - name: ImageFields.IMG, + name: ImageField.IMG, values: ['data:image/jpg;base64,/9j/4AAQSkZJRgABA9k='], }, ], @@ -390,9 +391,9 @@ describe('Image Panel', () => { ], }; const options = { - name: ImageFields.IMG, - widthMode: ImageSizeModes.AUTO, - heightMode: ImageSizeModes.AUTO, + name: ImageField.IMG, + widthMode: ImageSizeMode.AUTO, + heightMode: ImageSizeMode.AUTO, toolbar: true, buttons: [ButtonType.DOWNLOAD], }; @@ -407,10 +408,10 @@ describe('Image Panel', () => { }) ); - expect(screen.getByTestId(TestIds.panel.image)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.image)).toBeInTheDocument(); - expect(screen.getByTestId(TestIds.panel.image)).toHaveAttribute('width', '200'); - expect(screen.getByTestId(TestIds.panel.image)).toHaveAttribute('height', (200 - elementHeight).toString()); + expect(screen.getByTestId(TEST_IDS.panel.image)).toHaveAttribute('width', '200'); + expect(screen.getByTestId(TEST_IDS.panel.image)).toHaveAttribute('height', (200 - elementHeight).toString()); /** * Rerender with updated panel size @@ -424,7 +425,7 @@ describe('Image Panel', () => { }) ); - expect(screen.getByTestId(TestIds.panel.image)).toHaveAttribute('height', (300 - elementHeight).toString()); + expect(screen.getByTestId(TEST_IDS.panel.image)).toHaveAttribute('height', (300 - elementHeight).toString()); }); it('Should update image height if toolbar hidden', async () => { @@ -437,10 +438,10 @@ describe('Image Panel', () => { }) ); - expect(screen.getByTestId(TestIds.panel.image)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.image)).toBeInTheDocument(); - expect(screen.getByTestId(TestIds.panel.image)).toHaveAttribute('width', '200'); - expect(screen.getByTestId(TestIds.panel.image)).toHaveAttribute('height', (200 - elementHeight).toString()); + expect(screen.getByTestId(TEST_IDS.panel.image)).toHaveAttribute('width', '200'); + expect(screen.getByTestId(TEST_IDS.panel.image)).toHaveAttribute('height', (200 - elementHeight).toString()); /** * Rerender with hidden toolbar @@ -457,7 +458,7 @@ describe('Image Panel', () => { }) ); - expect(screen.getByTestId(TestIds.panel.image)).toHaveAttribute('height', (200).toString()); + expect(screen.getByTestId(TEST_IDS.panel.image)).toHaveAttribute('height', (200).toString()); }); it('Should update image height if only zoom enabled and it type changed', async () => { @@ -475,10 +476,10 @@ describe('Image Panel', () => { }) ); - expect(screen.getByTestId(TestIds.panel.image)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.image)).toBeInTheDocument(); - expect(screen.getByTestId(TestIds.panel.image)).toHaveAttribute('width', '200'); - expect(screen.getByTestId(TestIds.panel.image)).toHaveAttribute('height', (200 - elementHeight).toString()); + expect(screen.getByTestId(TEST_IDS.panel.image)).toHaveAttribute('width', '200'); + expect(screen.getByTestId(TEST_IDS.panel.image)).toHaveAttribute('height', (200 - elementHeight).toString()); /** * Rerender with pan pinch zoom type @@ -496,7 +497,7 @@ describe('Image Panel', () => { }) ); - expect(screen.getByTestId(TestIds.panel.image)).toHaveAttribute('height', (200 - elementHeight).toString()); + expect(screen.getByTestId(TEST_IDS.panel.image)).toHaveAttribute('height', (200 - elementHeight).toString()); }); }); @@ -515,7 +516,7 @@ describe('Image Panel', () => { }, { type: FieldType.string, - name: ImageFields.IMG, + name: ImageField.IMG, values: ['data:image/jpg;base64,/9j/4AAQSkZJRgABA9k='], }, ], @@ -523,22 +524,22 @@ describe('Image Panel', () => { ], }, options: { - name: ImageFields.IMG, - widthMode: ImageSizeModes.CUSTOM, - heightMode: ImageSizeModes.CUSTOM, - widthName: ImageFields.WIDTH, - heightName: ImageFields.HEIGHT, + name: ImageField.IMG, + widthMode: ImageSizeMode.CUSTOM, + heightMode: ImageSizeMode.CUSTOM, + widthName: ImageField.WIDTH, + heightName: ImageField.HEIGHT, width: 20, height: 20, }, }) ); - expect(screen.getByTestId(TestIds.panel.root)).toBeInTheDocument(); - expect(screen.getByTestId(TestIds.panel.image)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.root)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.image)).toBeInTheDocument(); - expect(screen.getByTestId(TestIds.panel.image)).toHaveAttribute('width', '20'); - expect(screen.getByTestId(TestIds.panel.image)).toHaveAttribute('height', '20'); + expect(screen.getByTestId(TEST_IDS.panel.image)).toHaveAttribute('width', '20'); + expect(screen.getByTestId(TEST_IDS.panel.image)).toHaveAttribute('height', '20'); }); it('Should render image with custom size options', async () => { @@ -556,7 +557,7 @@ describe('Image Panel', () => { }, { type: FieldType.string, - name: ImageFields.IMG, + name: ImageField.IMG, values: ['data:image/jpg;base64,/9j/4AAQSkZJRgABA9k='], }, ], @@ -564,20 +565,20 @@ describe('Image Panel', () => { ], }, options: { - name: ImageFields.IMG, - widthMode: ImageSizeModes.CUSTOM, - heightMode: ImageSizeModes.CUSTOM, + name: ImageField.IMG, + widthMode: ImageSizeMode.CUSTOM, + heightMode: ImageSizeMode.CUSTOM, width: 20, height: 20, }, }) ); - expect(screen.getByTestId(TestIds.panel.root)).toBeInTheDocument(); - expect(screen.getByTestId(TestIds.panel.image)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.root)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.image)).toBeInTheDocument(); - expect(screen.getByTestId(TestIds.panel.image)).toHaveAttribute('width', '20'); - expect(screen.getByTestId(TestIds.panel.image)).toHaveAttribute('height', '20'); + expect(screen.getByTestId(TEST_IDS.panel.image)).toHaveAttribute('width', '20'); + expect(screen.getByTestId(TEST_IDS.panel.image)).toHaveAttribute('height', '20'); }); it('Should render image with custom size fields', async () => { @@ -595,17 +596,17 @@ describe('Image Panel', () => { }, { type: FieldType.string, - name: ImageFields.IMG, + name: ImageField.IMG, values: ['data:image/jpg;base64,/9j/4AAQSkZJRgABA9k='], }, { type: FieldType.number, - name: ImageFields.HEIGHT, + name: ImageField.HEIGHT, values: [20], }, { type: FieldType.number, - name: ImageFields.WIDTH, + name: ImageField.WIDTH, values: [20], }, ], @@ -613,20 +614,20 @@ describe('Image Panel', () => { ], }, options: { - name: ImageFields.IMG, - widthMode: ImageSizeModes.CUSTOM, - heightMode: ImageSizeModes.CUSTOM, - widthName: ImageFields.WIDTH, - heightName: ImageFields.HEIGHT, + name: ImageField.IMG, + widthMode: ImageSizeMode.CUSTOM, + heightMode: ImageSizeMode.CUSTOM, + widthName: ImageField.WIDTH, + heightName: ImageField.HEIGHT, }, }) ); - expect(screen.getByTestId(TestIds.panel.root)).toBeInTheDocument(); - expect(screen.getByTestId(TestIds.panel.image)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.root)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.image)).toBeInTheDocument(); - expect(screen.getByTestId(TestIds.panel.image)).toHaveAttribute('width', '20'); - expect(screen.getByTestId(TestIds.panel.image)).toHaveAttribute('height', '20'); + expect(screen.getByTestId(TEST_IDS.panel.image)).toHaveAttribute('width', '20'); + expect(screen.getByTestId(TEST_IDS.panel.image)).toHaveAttribute('height', '20'); }); it('Should render image with original size', async () => { @@ -644,7 +645,7 @@ describe('Image Panel', () => { }, { type: FieldType.string, - name: ImageFields.IMG, + name: ImageField.IMG, values: ['data:image/jpg;base64,/9j/4AAQSkZJRgABA9k='], }, ], @@ -652,18 +653,18 @@ describe('Image Panel', () => { ], }, options: { - name: ImageFields.IMG, - widthMode: ImageSizeModes.ORIGINAL, - heightMode: ImageSizeModes.ORIGINAL, + name: ImageField.IMG, + widthMode: ImageSizeMode.ORIGINAL, + heightMode: ImageSizeMode.ORIGINAL, }, }) ); - expect(screen.getByTestId(TestIds.panel.root)).toBeInTheDocument(); - expect(screen.getByTestId(TestIds.panel.image)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.root)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.image)).toBeInTheDocument(); - expect(screen.getByTestId(TestIds.panel.image)).toHaveAttribute('width', ''); - expect(screen.getByTestId(TestIds.panel.image)).toHaveAttribute('height', ''); + expect(screen.getByTestId(TEST_IDS.panel.image)).toHaveAttribute('width', ''); + expect(screen.getByTestId(TEST_IDS.panel.image)).toHaveAttribute('height', ''); }); }); @@ -677,7 +678,7 @@ describe('Image Panel', () => { fields: [ { type: FieldType.string, - name: ImageFields.IMG, + name: ImageField.IMG, values: ['data:video/mp4;base64,JVBERiiUlRU9GCg=='], }, ], @@ -687,8 +688,8 @@ describe('Image Panel', () => { }) ); - expect(screen.getByTestId(TestIds.panel.root)).toBeInTheDocument(); - expect(screen.getByTestId(TestIds.panel.video)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.root)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.video)).toBeInTheDocument(); }); it('Should render audio with header', async () => { @@ -701,7 +702,7 @@ describe('Image Panel', () => { fields: [ { type: FieldType.string, - name: ImageFields.IMG, + name: ImageField.IMG, values: ['data:audio/mp3;base64,JVBERiiUlRU9GCg=='], }, ], @@ -711,8 +712,8 @@ describe('Image Panel', () => { }) ); - expect(screen.getByTestId(TestIds.panel.root)).toBeInTheDocument(); - expect(screen.getByTestId(TestIds.panel.audio)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.root)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.audio)).toBeInTheDocument(); }); /** @@ -730,7 +731,7 @@ describe('Image Panel', () => { fields: [ { type: FieldType.string, - name: ImageFields.IMG, + name: ImageField.IMG, values: [image], }, ], @@ -741,9 +742,9 @@ describe('Image Panel', () => { }) ); - expect(screen.getByTestId(TestIds.panel.buttonDownload)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.buttonDownload)).toBeInTheDocument(); - fireEvent.click(screen.getByTestId(TestIds.panel.buttonDownload)); + fireEvent.click(screen.getByTestId(TEST_IDS.panel.buttonDownload)); expect(saveAs).toHaveBeenCalledWith(`data:image/jpeg;base64,${image}`); }); @@ -758,7 +759,7 @@ describe('Image Panel', () => { fields: [ { type: FieldType.string, - name: ImageFields.IMG, + name: ImageField.IMG, values: ['/9j/4AAQSkZJRAAdLxAACEAAIX/9k='], }, ], @@ -769,7 +770,7 @@ describe('Image Panel', () => { }) ); - expect(screen.queryByTestId(TestIds.panel.buttonDownload)).not.toBeInTheDocument(); + expect(screen.queryByTestId(TEST_IDS.panel.buttonDownload)).not.toBeInTheDocument(); }); it('Should show zoom button for image', () => { @@ -783,7 +784,7 @@ describe('Image Panel', () => { fields: [ { type: FieldType.string, - name: ImageFields.IMG, + name: ImageField.IMG, values: [image], }, ], @@ -794,12 +795,12 @@ describe('Image Panel', () => { }) ); - expect(screen.getByTestId(TestIds.panel.buttonZoom)).toBeInTheDocument(); - expect(screen.queryByTestId(TestIds.panel.zoomedImage)).not.toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.buttonZoom)).toBeInTheDocument(); + expect(screen.queryByTestId(TEST_IDS.panel.zoomedImage)).not.toBeInTheDocument(); - fireEvent.click(screen.getByTestId(TestIds.panel.buttonZoom)); + fireEvent.click(screen.getByTestId(TEST_IDS.panel.buttonZoom)); - expect(screen.getByTestId(TestIds.panel.zoomedImage)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.zoomedImage)).toBeInTheDocument(); }); it('Should show pan pinch zoom controls for image', () => { @@ -813,7 +814,7 @@ describe('Image Panel', () => { fields: [ { type: FieldType.string, - name: ImageFields.IMG, + name: ImageField.IMG, values: [image], }, ], @@ -824,7 +825,7 @@ describe('Image Panel', () => { }) ); - expect(screen.getByTestId(TestIds.panel.buttonZoomPanPinchIn)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.buttonZoomPanPinchIn)).toBeInTheDocument(); }); it('Should pan pinch zoom image', () => { @@ -838,7 +839,7 @@ describe('Image Panel', () => { fields: [ { type: FieldType.string, - name: ImageFields.IMG, + name: ImageField.IMG, values: [image], }, ], @@ -849,15 +850,15 @@ describe('Image Panel', () => { }) ); - fireEvent.click(screen.getByTestId(TestIds.panel.buttonZoomPanPinchIn)); - fireEvent.click(screen.getByTestId(TestIds.panel.buttonZoomPanPinchOut)); - fireEvent.click(screen.getByTestId(TestIds.panel.buttonZoomPanPinchReset)); + fireEvent.click(screen.getByTestId(TEST_IDS.panel.buttonZoomPanPinchIn)); + fireEvent.click(screen.getByTestId(TEST_IDS.panel.buttonZoomPanPinchOut)); + fireEvent.click(screen.getByTestId(TEST_IDS.panel.buttonZoomPanPinchReset)); /** * Unable to check zooming through unit tests because mocking ref causes warnings * so just check if image is rendered after zooming */ - expect(screen.getByTestId(TestIds.panel.image)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.image)).toBeInTheDocument(); }); it('Should change current image', () => { @@ -873,7 +874,7 @@ describe('Image Panel', () => { fields: [ { type: FieldType.string, - name: ImageFields.IMG, + name: ImageField.IMG, values: [image1, image2, image3], }, ], @@ -887,36 +888,36 @@ describe('Image Panel', () => { /** * Check if first value is rendered */ - expect(screen.getByTestId(TestIds.panel.image)).toBeInTheDocument(); - expect(screen.getByTestId(TestIds.panel.image)).toHaveAttribute('src', `data:;base64,${image1}`); + expect(screen.getByTestId(TEST_IDS.panel.image)).toBeInTheDocument(); + expect(screen.getByTestId(TEST_IDS.panel.image)).toHaveAttribute('src', `data:;base64,${image1}`); /** * Check if second value is rendered */ - fireEvent.click(screen.getByTestId(TestIds.panel.buttonNext)); + fireEvent.click(screen.getByTestId(TEST_IDS.panel.buttonNext)); - expect(screen.getByTestId(TestIds.panel.image)).toHaveAttribute('src', `data:;base64,${image2}`); + expect(screen.getByTestId(TEST_IDS.panel.image)).toHaveAttribute('src', `data:;base64,${image2}`); /** * Check if first value is rendered again */ - fireEvent.click(screen.getByTestId(TestIds.panel.buttonPrevious)); + fireEvent.click(screen.getByTestId(TEST_IDS.panel.buttonPrevious)); - expect(screen.getByTestId(TestIds.panel.image)).toHaveAttribute('src', `data:;base64,${image1}`); + expect(screen.getByTestId(TEST_IDS.panel.image)).toHaveAttribute('src', `data:;base64,${image1}`); /** * Check if previous button moves to last image */ - fireEvent.click(screen.getByTestId(TestIds.panel.buttonPrevious)); + fireEvent.click(screen.getByTestId(TEST_IDS.panel.buttonPrevious)); - expect(screen.getByTestId(TestIds.panel.image)).toHaveAttribute('src', `data:;base64,${image3}`); + expect(screen.getByTestId(TEST_IDS.panel.image)).toHaveAttribute('src', `data:;base64,${image3}`); /** * Check if next button moves to first image */ - fireEvent.click(screen.getByTestId(TestIds.panel.buttonNext)); + fireEvent.click(screen.getByTestId(TEST_IDS.panel.buttonNext)); - expect(screen.getByTestId(TestIds.panel.image)).toHaveAttribute('src', `data:;base64,${image1}`); + expect(screen.getByTestId(TEST_IDS.panel.image)).toHaveAttribute('src', `data:;base64,${image1}`); }); }); }); diff --git a/src/components/ImagePanel/ImagePanel.tsx b/src/components/ImagePanel/ImagePanel.tsx index ab632c1..305f088 100644 --- a/src/components/ImagePanel/ImagePanel.tsx +++ b/src/components/ImagePanel/ImagePanel.tsx @@ -1,16 +1,18 @@ import 'react-medium-image-zoom/dist/styles.css'; + +import { css, cx } from '@emotion/css'; +import { FieldType, PanelProps } from '@grafana/data'; +import { Alert, PageToolbar, ToolbarButton, useStyles2 } from '@grafana/ui'; import saveAs from 'file-saver'; import { Base64 } from 'js-base64'; import React, { JSX, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { Controlled as ControlledZoom } from 'react-medium-image-zoom'; import { ReactZoomPanPinchRef, TransformComponent, TransformWrapper } from 'react-zoom-pan-pinch'; -import { css, cx } from '@emotion/css'; -import { FieldType, PanelProps } from '@grafana/data'; -import { Alert, PageToolbar, ToolbarButton, useStyles2 } from '@grafana/ui'; -import { ImageSizeModes, ImageTypesSymbols, SupportedTypes, TestIds } from '../../constants'; -import { ButtonType, PanelOptions, ZoomType } from '../../types'; + +import { IMAGE_TYPES_SYMBOLS, TEST_IDS } from '../../constants'; +import { ButtonType, ImageSizeMode, PanelOptions, SupportedFileType, ZoomType } from '../../types'; import { base64toBlob } from '../../utils'; -import { Styles } from './ImagePanel.styles'; +import { getStyles } from './ImagePanel.styles'; /** * Properties @@ -148,7 +150,7 @@ export const ImagePanel: React.FC = ({ options, data, width, height, repl /** * Styles */ - const styles = useStyles2(Styles); + const styles = useStyles2(getStyles); /** * Name and description field (string) @@ -162,13 +164,13 @@ export const ImagePanel: React.FC = ({ options, data, width, height, repl /** * Keep auto-scale if Auto */ - let imageHeight = options.heightMode === ImageSizeModes.AUTO ? height - toolbarHeight - descriptionHeight : 0; - let imageWidth = options.widthMode === ImageSizeModes.AUTO ? width : 0; + let imageHeight = options.heightMode === ImageSizeMode.AUTO ? height - toolbarHeight - descriptionHeight : 0; + let imageWidth = options.widthMode === ImageSizeMode.AUTO ? width : 0; /** * Height */ - if (options.heightMode === ImageSizeModes.CUSTOM) { + if (options.heightMode === ImageSizeMode.CUSTOM) { /** * Field */ @@ -188,7 +190,7 @@ export const ImagePanel: React.FC = ({ options, data, width, height, repl /** * Width */ - if (options.widthMode === ImageSizeModes.CUSTOM) { + if (options.widthMode === ImageSizeMode.CUSTOM) { /** * Field */ @@ -210,7 +212,7 @@ export const ImagePanel: React.FC = ({ options, data, width, height, repl */ const renderContainer = (child: JSX.Element) => (
= ({ options, data, width, height, repl */ if (!img) { return renderContainer( - + Nothing to display... ); @@ -256,17 +258,17 @@ export const ImagePanel: React.FC = ({ options, data, width, height, repl /** * Set header */ - type = ImageTypesSymbols[img.charAt(0)]; + type = IMAGE_TYPES_SYMBOLS[img.charAt(0)]; img = type ? `data:${type};base64,${img}` : `data:;base64,${img}`; - } else if (Object.values(SupportedTypes).includes(m[1] as any)) { + } else if (Object.values(SupportedFileType).includes(m[1] as SupportedFileType)) { type = m[1]; } /** * Convert PDF base64 to Blob and display */ - if (type === SupportedTypes.PDF) { - const blob = base64toBlob(img, SupportedTypes.PDF); + if (type === SupportedFileType.PDF) { + const blob = base64toBlob(img, SupportedFileType.PDF); img = URL.createObjectURL(blob); /** @@ -277,21 +279,21 @@ export const ImagePanel: React.FC = ({ options, data, width, height, repl } return renderContainer( -