diff --git a/grafana-plugin/jest.config.js b/grafana-plugin/jest.config.js index 305169f5..f70e7d25 100644 --- a/grafana-plugin/jest.config.js +++ b/grafana-plugin/jest.config.js @@ -14,9 +14,9 @@ module.exports = { 'jest/outgoingWebhooksStub': '/src/jest/outgoingWebhooksStub.ts', '^jest$': '/src/jest', '^.+\\.(css|scss)$': '/src/jest/styleMock.ts', - // '^.+\\.(ts|tsx)$': 'ts-jest', '^lodash-es$': 'lodash', '^.+\\.svg$': '/src/jest/svgTransform.ts', + '^.+\\.png$': '/src/jest/grafanaMock.ts', }, setupFilesAfterEnv: ['/jest.setup.ts'], diff --git a/grafana-plugin/src/assets/img/qr-code.png b/grafana-plugin/src/assets/img/qr-code.png new file mode 100644 index 00000000..2211b2ad Binary files /dev/null and b/grafana-plugin/src/assets/img/qr-code.png differ diff --git a/grafana-plugin/src/containers/MobileAppVerification/MobileAppVerification.module.scss b/grafana-plugin/src/containers/MobileAppVerification/MobileAppVerification.module.scss new file mode 100644 index 00000000..a97a1e43 --- /dev/null +++ b/grafana-plugin/src/containers/MobileAppVerification/MobileAppVerification.module.scss @@ -0,0 +1,35 @@ +.container { + display: flex; + flex-direction: row; + + &__box { + flex-basis: 50%; + } + + &__box:first-child { + margin-right: 8px; + } + &__box:last-child { + margin-left: 8px; + } +} + +.icon { + margin-top: -6px; + margin-left: 4px; + fill: var(--green-6); +} + +.disconnect__container { + position: relative; + display: flex; + justify-content: center; + width: 100%; +} + +.disconnect__qrCode { + width: 240px; + height: auto; + filter: blur(6px); + opacity: 0.6; +} diff --git a/grafana-plugin/src/containers/MobileAppVerification/MobileAppVerification.test.tsx b/grafana-plugin/src/containers/MobileAppVerification/MobileAppVerification.test.tsx index 2ab917da..72926dd4 100644 --- a/grafana-plugin/src/containers/MobileAppVerification/MobileAppVerification.test.tsx +++ b/grafana-plugin/src/containers/MobileAppVerification/MobileAppVerification.test.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import { render, screen } from '@testing-library/react'; +import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { UserStore } from 'models/user/user'; @@ -13,10 +13,12 @@ import MobileAppVerification from './MobileAppVerification'; jest.mock('state/useStore'); const useStore = useStoreOriginal as jest.Mock>; +const loadUserMock = jest.fn().mockReturnValue(undefined); const mockUseStore = (rest?: any, connected = false) => { const store = { userStore: { + loadUser: loadUserMock, currentUser: { messaging_backends: { MOBILE_APP: { connected }, @@ -35,6 +37,10 @@ const USER_PK = '8585'; const BACKEND = 'MOBILE_APP'; describe('MobileAppVerification', () => { + beforeEach(() => { + loadUserMock.mockClear(); + }); + test('it shows a loading message if it is currently fetching the QR code', async () => { const { userStore } = mockUseStore({ sendBackendConfirmationCode: jest.fn().mockResolvedValueOnce('dfd'), @@ -43,8 +49,10 @@ describe('MobileAppVerification', () => { const component = render(); expect(component.container).toMatchSnapshot(); - expect(userStore.sendBackendConfirmationCode).toHaveBeenCalledTimes(1); - expect(userStore.sendBackendConfirmationCode).toHaveBeenCalledWith(USER_PK, BACKEND); + waitFor(() => { + expect(userStore.sendBackendConfirmationCode).toHaveBeenCalledTimes(1); + expect(userStore.sendBackendConfirmationCode).toHaveBeenCalledWith(USER_PK, BACKEND); + }); }); test('it shows a message when the mobile app is already connected', async () => { @@ -58,7 +66,9 @@ describe('MobileAppVerification', () => { const component = render(); expect(component.container).toMatchSnapshot(); - expect(userStore.sendBackendConfirmationCode).toHaveBeenCalledTimes(0); + waitFor(() => { + expect(userStore.sendBackendConfirmationCode).toHaveBeenCalledTimes(0); + }); }); test('it shows an error message if there was an error fetching the QR code', async () => { @@ -69,10 +79,12 @@ describe('MobileAppVerification', () => { const component = render(); await screen.findByText(/.*error fetching your QR code.*/); - expect(component.container).toMatchSnapshot(); + waitFor(() => { + expect(component.container).toMatchSnapshot(); - expect(userStore.sendBackendConfirmationCode).toHaveBeenCalledTimes(1); - expect(userStore.sendBackendConfirmationCode).toHaveBeenCalledWith(USER_PK, BACKEND); + expect(userStore.sendBackendConfirmationCode).toHaveBeenCalledTimes(1); + expect(userStore.sendBackendConfirmationCode).toHaveBeenCalledWith(USER_PK, BACKEND); + }); }); test("it shows a QR code if the app isn't already connected", async () => { @@ -81,12 +93,12 @@ describe('MobileAppVerification', () => { }); const component = render(); - await screen.findByText(/.*the QR code is only valid for one minute.*/); - expect(component.container).toMatchSnapshot(); - expect(userStore.sendBackendConfirmationCode).toHaveBeenCalledTimes(1); - expect(userStore.sendBackendConfirmationCode).toHaveBeenCalledWith(USER_PK, BACKEND); + waitFor(() => { + expect(userStore.sendBackendConfirmationCode).toHaveBeenCalledTimes(1); + expect(userStore.sendBackendConfirmationCode).toHaveBeenCalledWith(USER_PK, BACKEND); + }); }); test('if we disconnect the app, it disconnects and fetches a new QR code', async () => { @@ -108,15 +120,15 @@ describe('MobileAppVerification', () => { // click the confirm button within the modal, which actually triggers the callback await user.click(screen.getByText('Remove')); - await screen.findByText(/.*the QR code is only valid for one minute.*/); - expect(component.container).toMatchSnapshot(); - expect(userStore.sendBackendConfirmationCode).toHaveBeenCalledTimes(1); - expect(userStore.sendBackendConfirmationCode).toHaveBeenCalledWith(USER_PK, BACKEND); + waitFor(() => { + expect(userStore.sendBackendConfirmationCode).toHaveBeenCalledTimes(1); + expect(userStore.sendBackendConfirmationCode).toHaveBeenCalledWith(USER_PK, BACKEND); - expect(userStore.unlinkBackend).toHaveBeenCalledTimes(1); - expect(userStore.unlinkBackend).toHaveBeenCalledWith(USER_PK, BACKEND); + expect(userStore.unlinkBackend).toHaveBeenCalledTimes(1); + expect(userStore.unlinkBackend).toHaveBeenCalledWith(USER_PK, BACKEND); + }); }); test('it shows a loading message if it is currently disconnecting', async () => { @@ -144,11 +156,13 @@ describe('MobileAppVerification', () => { expect(component.container).toMatchSnapshot(); - expect(userStore.sendBackendConfirmationCode).toHaveBeenCalledTimes(1); - expect(userStore.sendBackendConfirmationCode).toHaveBeenCalledWith(USER_PK, BACKEND); + waitFor(() => { + expect(userStore.sendBackendConfirmationCode).toHaveBeenCalledTimes(1); + expect(userStore.sendBackendConfirmationCode).toHaveBeenCalledWith(USER_PK, BACKEND); - expect(userStore.unlinkBackend).toHaveBeenCalledTimes(1); - expect(userStore.unlinkBackend).toHaveBeenCalledWith(USER_PK, BACKEND); + expect(userStore.unlinkBackend).toHaveBeenCalledTimes(1); + expect(userStore.unlinkBackend).toHaveBeenCalledWith(USER_PK, BACKEND); + }); }); test('it shows an error message if there was an error disconnecting the mobile app', async () => { @@ -163,7 +177,7 @@ describe('MobileAppVerification', () => { const component = render(); const user = userEvent.setup(); - const button = await screen.findByRole('button'); + const button = await screen.findByTestId('test__disconnect'); // click the disconnect button, which opens the modal await user.click(button); @@ -174,9 +188,51 @@ describe('MobileAppVerification', () => { expect(component.container).toMatchSnapshot(); - expect(userStore.sendBackendConfirmationCode).toHaveBeenCalledTimes(0); + waitFor(() => { + expect(userStore.sendBackendConfirmationCode).toHaveBeenCalledTimes(0); - expect(userStore.unlinkBackend).toHaveBeenCalledTimes(1); - expect(userStore.unlinkBackend).toHaveBeenCalledWith(USER_PK, BACKEND); + expect(userStore.unlinkBackend).toHaveBeenCalledTimes(1); + expect(userStore.unlinkBackend).toHaveBeenCalledWith(USER_PK, BACKEND); + }); + }); + + test('it polls loadUser on first render if not connected', async () => { + mockUseStore( + { + sendBackendConfirmationCode: jest.fn().mockResolvedValueOnce('dfd'), + unlinkBackend: jest.fn().mockRejectedValueOnce('asdfadsfafds'), + }, + false + ); + + render(); + + await waitFor(() => { + expect(loadUserMock).toHaveBeenCalledTimes(1); + }); + }); + + test('it polls loadUser after disconnect', async () => { + mockUseStore( + { + sendBackendConfirmationCode: jest.fn().mockResolvedValueOnce('dff'), + unlinkBackend: jest.fn().mockRejectedValueOnce('asdff'), + }, + true + ); + + render(); + + const user = userEvent.setup(); + const button = await screen.findByRole('button'); + + loadUserMock.mockClear(); + + await user.click(button); // click the disconnect button, which opens the modal + await user.click(screen.getByText('Remove')); // click the confirm button within the modal, which actually triggers the callback + + await waitFor(() => { + expect(loadUserMock).toHaveBeenCalledTimes(1); + }); }); }); diff --git a/grafana-plugin/src/containers/MobileAppVerification/MobileAppVerification.tsx b/grafana-plugin/src/containers/MobileAppVerification/MobileAppVerification.tsx index cdaf5af2..7b8d2afb 100644 --- a/grafana-plugin/src/containers/MobileAppVerification/MobileAppVerification.tsx +++ b/grafana-plugin/src/containers/MobileAppVerification/MobileAppVerification.tsx @@ -1,29 +1,33 @@ import React, { useCallback, useEffect, useState } from 'react'; -import { HorizontalGroup, LoadingPlaceholder, VerticalGroup } from '@grafana/ui'; +import { Icon, LoadingPlaceholder, VerticalGroup } from '@grafana/ui'; +import cn from 'classnames/bind'; import { observer } from 'mobx-react'; +import qrCodeImage from 'assets/img/qr-code.png'; import Block from 'components/GBlock/Block'; import Text from 'components/Text/Text'; import { User } from 'models/user/user.types'; import { useStore } from 'state/useStore'; -import DisconnectButton from './parts/DisconnectButton'; +import styles from './MobileAppVerification.module.scss'; +import DisconnectButton from './parts/DisconnectButton/DisconnectButton'; import DownloadIcons from './parts/DownloadIcons'; import QRCode from './parts/QRCode'; +const cx = cn.bind(styles); + type Props = { userPk: User['pk']; }; +const INTERVAL_MS = 5000; const BACKEND = 'MOBILE_APP'; const MobileAppVerification = observer(({ userPk }: Props) => { const { userStore } = useStore(); - const [mobileAppIsCurrentlyConnected, setMobileAppIsCurrentlyConnected] = useState( - userStore.currentUser.messaging_backends[BACKEND]?.connected === true - ); + const [mobileAppIsCurrentlyConnected, setMobileAppIsCurrentlyConnected] = useState(isUserConnected()); const [fetchingQRCode, setFetchingQRCode] = useState(!mobileAppIsCurrentlyConnected); const [QRCodeValue, setQRCodeValue] = useState(null); @@ -31,6 +35,7 @@ const MobileAppVerification = observer(({ userPk }: Props) => { const [disconnectingMobileApp, setDisconnectingMobileApp] = useState(false); const [errorDisconnectingMobileApp, setErrorDisconnectingMobileApp] = useState(null); + const [userTimeoutId, setUserTimeoutId] = useState(undefined); const fetchQRCode = useCallback(async () => { setFetchingQRCode(true); @@ -59,9 +64,24 @@ const MobileAppVerification = observer(({ userPk }: Props) => { } catch (e) { setErrorDisconnectingMobileApp('There was an error disconnecting your mobile app. Please try again.'); } + setDisconnectingMobileApp(false); + pollUserProfile(); }, [userPk, resetState]); + useEffect(() => { + if (!isUserConnected()) { + pollUserProfile(); + } + + // clear on unmount + return () => { + if (userTimeoutId) { + clearTimeout(userTimeoutId); + } + }; + }, []); + useEffect(() => { if (!mobileAppIsCurrentlyConnected) { fetchQRCode(); @@ -76,33 +96,63 @@ const MobileAppVerification = observer(({ userPk }: Props) => { content = {errorFetchingQRCode || errorDisconnectingMobileApp}; } else if (mobileAppIsCurrentlyConnected) { content = ( - - Your mobile app is currently connected. Click below to disconnect. - + + + App connected + + + You can sync one application to your account. To setup new device please disconnect app first. + +
+ + +
); } else if (QRCodeValue) { content = ( - - - - Note: the QR code is only valid for one minute. If you have issues connecting your mobile app, try refreshing - this page to generate a new code. + + + Sign In + + Open Grafana IRM mobile application and scan this code to sync it with your account. +
+ +
+ + Note: the QR code is only valid for one minute. If you have issues connecting your mobile + app, try refreshing this page to generate a new code.
); } return ( - - - {content} - - +
+ - + + {content} + +
); + + function isUserConnected(user?: User): boolean { + return !!(user || userStore.currentUser).messaging_backends[BACKEND]?.connected; + } + + async function pollUserProfile(): Promise { + clearTimeout(userTimeoutId); + setUserTimeoutId(undefined); + + const user = await userStore.loadUser(userPk); + if (!isUserConnected(user)) { + setUserTimeoutId(setTimeout(() => pollUserProfile(), INTERVAL_MS)); + } else { + setMobileAppIsCurrentlyConnected(true); + } + } }); export default MobileAppVerification; diff --git a/grafana-plugin/src/containers/MobileAppVerification/__snapshots__/MobileAppVerification.test.tsx.snap b/grafana-plugin/src/containers/MobileAppVerification/__snapshots__/MobileAppVerification.test.tsx.snap index bb4670cf..6bcaa911 100644 --- a/grafana-plugin/src/containers/MobileAppVerification/__snapshots__/MobileAppVerification.test.tsx.snap +++ b/grafana-plugin/src/containers/MobileAppVerification/__snapshots__/MobileAppVerification.test.tsx.snap @@ -3,4903 +3,133 @@ exports[`MobileAppVerification if we disconnect the app, it disconnects and fetches a new QR code 1`] = `
+ + Download + +
+
+ + The Grafana IRM app is available on both the App Store and Google Play Store. + +
+
+
+ Apple + + iOS + +
+
+
+
+ Play Store + + Android + +
+
+
+
+
+
+
+
+
+ + App connected +
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
- - Note: the QR code is only valid for one minute. If you have issues connecting your mobile app, try refreshing this page to generate a new code. - -
+
-
-
-
-
+ + You can sync one application to your account. To setup new device please disconnect app first. + +
+
- - Download - -
-
- - The Grafana IRM app is available on both the App Store and Google Play Store. - -
-
-
-
-
- Apple - - iOS - -
-
-
-
- Play Store - - Android - -
-
-
-
-
-
-
-
- -`; - -exports[`MobileAppVerification it shows a QR code if the app isn't already connected 1`] = ` -
-
-
-
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
- - Note: the QR code is only valid for one minute. If you have issues connecting your mobile app, try refreshing this page to generate a new code. - -
-
-
-
-
-
-
-
- - Download - -
-
- - The Grafana IRM app is available on both the App Store and Google Play Store. - -
-
-
-
-
- Apple - - iOS - -
-
-
-
- Play Store - - Android - -
-
-
-
-
-
-
-
-
-`; - -exports[`MobileAppVerification it shows a loading message if it is currently disconnecting 1`] = ` -
-
-
-
-
- Loading... - -
- -
-
-
-
-
-
-
-
- - Download - -
-
- - The Grafana IRM app is available on both the App Store and Google Play Store. - -
-
-
-
-
- Apple - - iOS - -
-
-
-
- Play Store - - Android - -
-
-
-
-
-
-
-
-
-`; - -exports[`MobileAppVerification it shows a loading message if it is currently fetching the QR code 1`] = ` -
-
-
-
-
- Loading... - -
- -
-
-
-
-
-
-
-
- - Download - -
-
- - The Grafana IRM app is available on both the App Store and Google Play Store. - -
-
-
-
-
- Apple - - iOS - -
-
-
-
- Play Store - - Android - -
-
-
-
-
-
-
-
-
-`; - -exports[`MobileAppVerification it shows a message when the mobile app is already connected 1`] = ` -
-
-
-
-
-
- - Your mobile app is currently connected. Click below to disconnect. - -
-
+
+
+`; + +exports[`MobileAppVerification it shows a QR code if the app isn't already connected 1`] = ` +
+
+ + Download + +
+
+ + The Grafana IRM app is available on both the App Store and Google Play Store. + +
+
- - Download - -
-
- - The Grafana IRM app is available on both the App Store and Google Play Store. - -
-
-
+ - Apple - - iOS - -
-
-
-
- Play Store - - Android - -
+ iOS +
+
+
+ Play Store + + Android + +
+
+
+
+
+
+
+
+ Loading... + +
+ +
+
+
+
+
+`; + +exports[`MobileAppVerification it shows a loading message if it is currently disconnecting 1`] = ` +
+
+
+
+
+ + Download + +
+
+ + The Grafana IRM app is available on both the App Store and Google Play Store. + +
+
+
+
+
+ Apple + + iOS + +
+
+
+
+ Play Store + + Android + +
+
+
+
+
+
+
+
+ Loading... + +
+ +
+
+
+
+
+`; + +exports[`MobileAppVerification it shows a loading message if it is currently fetching the QR code 1`] = ` +
+
+
+
+
+ + Download + +
+
+ + The Grafana IRM app is available on both the App Store and Google Play Store. + +
+
+
+
+
+ Apple + + iOS + +
+
+
+
+ Play Store + + Android + +
+
+
+
+
+
+
+
+ Loading... + +
+ +
+
+
+
+
+`; + +exports[`MobileAppVerification it shows a message when the mobile app is already connected 1`] = ` +
+
+
+
+
+ + Download + +
+
+ + The Grafana IRM app is available on both the App Store and Google Play Store. + +
+
+
+
+
+ Apple + + iOS + +
+
+
+
+ Play Store + + Android + +
+
+
+
+
+
+
+
+
+ + App connected +
+ + + +
+
+
+
+ + You can sync one application to your account. To setup new device please disconnect app first. + +
+
+
+ +
@@ -4995,98 +592,89 @@ exports[`MobileAppVerification it shows a message when the mobile app is already exports[`MobileAppVerification it shows an error message if there was an error disconnecting the mobile app 1`] = `
- - There was an error disconnecting your mobile app. Please try again. - -
-
-
-
+ + Download + +
+
+ + The Grafana IRM app is available on both the App Store and Google Play Store. + +
+
- - Download - -
-
- - The Grafana IRM app is available on both the App Store and Google Play Store. - -
-
-
+ - Apple - - iOS - -
+ iOS +
+
+
-
+ - Play Store - - Android - -
+ Android +
+
+ + There was an error disconnecting your mobile app. Please try again. + +
`; @@ -5094,98 +682,89 @@ exports[`MobileAppVerification it shows an error message if there was an error d exports[`MobileAppVerification it shows an error message if there was an error fetching the QR code 1`] = `
- - There was an error fetching your QR code. Please try again. - -
-
-
-
+ + Download + +
+
+ + The Grafana IRM app is available on both the App Store and Google Play Store. + +
+
- - Download - -
-
- - The Grafana IRM app is available on both the App Store and Google Play Store. - -
-
-
+ - Apple - - iOS - -
+ iOS +
+
+
-
+ - Play Store - - Android - -
+ Android +
+
+ + There was an error fetching your QR code. Please try again. + +
`; diff --git a/grafana-plugin/src/containers/MobileAppVerification/parts/DisconnectButton/DisconnectButton.module.scss b/grafana-plugin/src/containers/MobileAppVerification/parts/DisconnectButton/DisconnectButton.module.scss new file mode 100644 index 00000000..8e4b047d --- /dev/null +++ b/grafana-plugin/src/containers/MobileAppVerification/parts/DisconnectButton/DisconnectButton.module.scss @@ -0,0 +1,6 @@ +.disconnect-button { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} diff --git a/grafana-plugin/src/containers/MobileAppVerification/parts/DisconnectButton/DisconnectButton.test.tsx b/grafana-plugin/src/containers/MobileAppVerification/parts/DisconnectButton/DisconnectButton.test.tsx index b660d5af..f3551b49 100644 --- a/grafana-plugin/src/containers/MobileAppVerification/parts/DisconnectButton/DisconnectButton.test.tsx +++ b/grafana-plugin/src/containers/MobileAppVerification/parts/DisconnectButton/DisconnectButton.test.tsx @@ -3,7 +3,7 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import DisconnectButton from '.'; +import DisconnectButton from './DisconnectButton'; describe('DisconnectButton', () => { test('it renders properly', () => { diff --git a/grafana-plugin/src/containers/MobileAppVerification/parts/DisconnectButton/index.tsx b/grafana-plugin/src/containers/MobileAppVerification/parts/DisconnectButton/DisconnectButton.tsx similarity index 59% rename from grafana-plugin/src/containers/MobileAppVerification/parts/DisconnectButton/index.tsx rename to grafana-plugin/src/containers/MobileAppVerification/parts/DisconnectButton/DisconnectButton.tsx index ec108f47..435dabb4 100644 --- a/grafana-plugin/src/containers/MobileAppVerification/parts/DisconnectButton/index.tsx +++ b/grafana-plugin/src/containers/MobileAppVerification/parts/DisconnectButton/DisconnectButton.tsx @@ -1,17 +1,27 @@ import React, { FC } from 'react'; import { Button } from '@grafana/ui'; +import cn from 'classnames/bind'; import WithConfirm from 'components/WithConfirm/WithConfirm'; +import styles from './DisconnectButton.module.scss'; + +const cx = cn.bind(styles); + type Props = { onClick: () => void; }; -// TODO: right now this shows a confirmation pop-up modal on top of the user settings modal, do we want to maybe change this? const DisconnectButton: FC = ({ onClick }) => ( - diff --git a/grafana-plugin/src/containers/MobileAppVerification/parts/DisconnectButton/__snapshots__/DisconnectButton.test.tsx.snap b/grafana-plugin/src/containers/MobileAppVerification/parts/DisconnectButton/__snapshots__/DisconnectButton.test.tsx.snap index 88ffb190..22996a57 100644 --- a/grafana-plugin/src/containers/MobileAppVerification/parts/DisconnectButton/__snapshots__/DisconnectButton.test.tsx.snap +++ b/grafana-plugin/src/containers/MobileAppVerification/parts/DisconnectButton/__snapshots__/DisconnectButton.test.tsx.snap @@ -3,7 +3,8 @@ exports[`DisconnectButton it renders properly 1`] = `