diff --git a/public/app/percona/shared/services/updates/Updates.service.ts b/public/app/percona/shared/services/updates/Updates.service.ts index 6fedae0592772..cb58d6fb6cf41 100644 --- a/public/app/percona/shared/services/updates/Updates.service.ts +++ b/public/app/percona/shared/services/updates/Updates.service.ts @@ -3,6 +3,6 @@ import { api } from '../../helpers/api'; import { CheckUpdatesBody, CheckUpdatesResponse } from './Updates.types'; export const UpdatesService = { - getCurrentVersion: (body: CheckUpdatesBody = { force: false }) => - api.post('/v1/Updates/Check', body, true), + getCurrentVersion: (params: CheckUpdatesBody = { force: false }) => + api.get('/v1/server/updates', true, { params }), }; diff --git a/public/app/plugins/panel/pmm-update/UpdatePanel.messages.ts b/public/app/plugins/panel/pmm-update/UpdatePanel.messages.ts index 44440bc4c458b..848fb09861d0e 100644 --- a/public/app/plugins/panel/pmm-update/UpdatePanel.messages.ts +++ b/public/app/plugins/panel/pmm-update/UpdatePanel.messages.ts @@ -1,3 +1,4 @@ export const Messages = { + upgrade: 'Upgrade', upgradeTo: (version: string) => `Upgrade to ${version}`, }; diff --git a/public/app/plugins/panel/pmm-update/UpdatePanel.service.ts b/public/app/plugins/panel/pmm-update/UpdatePanel.service.ts deleted file mode 100644 index d27f288fb052f..0000000000000 --- a/public/app/plugins/panel/pmm-update/UpdatePanel.service.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { api } from 'app/percona/shared/helpers/api'; - -import { - GetUpdatesParams, - GetUpdateStatusBody, - GetUpdatesResponse, - GetUpdateStatusResponse, - StartUpdateResponse, -} from './types'; - -export const getCurrentVersion = (params: GetUpdatesParams = { force: false }) => - api.get(`/v1/server/updates`, false, { - params, - }); -export const startUpdate = () => api.post('/v1/server/updates:start', {}); -export const getUpdateStatus = (body: GetUpdateStatusBody) => - api.post('/v1/server/updates:getStatus', body); diff --git a/public/app/plugins/panel/pmm-update/UpdatePanel.styles.ts b/public/app/plugins/panel/pmm-update/UpdatePanel.styles.ts index aff9ebb201eb3..4597d10356e20 100644 --- a/public/app/plugins/panel/pmm-update/UpdatePanel.styles.ts +++ b/public/app/plugins/panel/pmm-update/UpdatePanel.styles.ts @@ -1,26 +1,27 @@ import { css } from '@emotion/css'; -export const panel = css` - display: flex; - flex-direction: column; - position: relative; - height: 100%; +export const styles = { + panel: css` + display: flex; + flex-direction: column; + position: relative; + height: 100%; - p { - margin-bottom: 0; - } - - @media (max-width: 1281px) { - #pmm-update-widget h2 { - font-size: 1.55rem; - margin-bottom: 0.1rem; + p { + margin-bottom: 0; } - } -`; -export const middleSectionWrapper = css` - align-items: center; - display: flex; - flex: 1; - justify-content: center; -`; + @media (max-width: 1281px) { + #pmm-update-widget h2 { + font-size: 1.55rem; + margin-bottom: 0.1rem; + } + } + `, + middleSectionWrapper: css` + align-items: center; + display: flex; + flex: 1; + justify-content: center; + `, +}; diff --git a/public/app/plugins/panel/pmm-update/UpdatePanel.tsx b/public/app/plugins/panel/pmm-update/UpdatePanel.tsx index 05c56f87594f3..12a95155905ab 100644 --- a/public/app/plugins/panel/pmm-update/UpdatePanel.tsx +++ b/public/app/plugins/panel/pmm-update/UpdatePanel.tsx @@ -1,29 +1,32 @@ -import React, { FC, MouseEvent, useEffect, useState } from 'react'; +import React, { FC, MouseEvent, useState } from 'react'; -import { Button, IconName, Spinner } from '@grafana/ui'; -import { getPerconaUser, getPerconaSettings } from 'app/percona/shared/core/selectors'; +import { Button, Spinner } from '@grafana/ui'; +import { PMM_UPDATES_LINK } from 'app/percona/shared/components/PerconaBootstrapper/PerconaNavigation'; +import { checkUpdatesAction } from 'app/percona/shared/core/reducers/updates'; +import { getPerconaUser, getPerconaSettings, getUpdatesInfo } from 'app/percona/shared/core/selectors'; +import { useAppDispatch } from 'app/store/store'; import { useSelector } from 'app/types'; import { Messages } from './UpdatePanel.messages'; -import * as styles from './UpdatePanel.styles'; -import { AvailableUpdate, CurrentVersion, InfoBox, LastCheck, ProgressModal } from './components'; -import { usePerformUpdate, useVersionDetails } from './hooks'; +import { styles } from './UpdatePanel.styles'; +import { formatDateWithTime } from './UpdatePanel.utils'; +import { AvailableUpdate, CurrentVersion, InfoBox, LastCheck } from './components'; -export const UpdatePanel: FC<{}> = () => { +export const UpdatePanel: FC = () => { const isOnline = navigator.onLine; + const { + isLoading: isLoadingVersionDetails, + installed, + latest, + latestNewsUrl, + updateAvailable, + lastChecked, + } = useSelector(getUpdatesInfo); + const { result: settings, loading: isLoadingSettings } = useSelector(getPerconaSettings); + const dispatch = useAppDispatch(); const [forceUpdate, setForceUpdate] = useState(false); - const [showModal, setShowModal] = useState(false); - const [errorMessage, setErrorMessage] = useState(''); const { isAuthorized } = useSelector(getPerconaUser); - const { result: settings, loading: isLoadingSettings } = useSelector(getPerconaSettings); - const [ - { installedVersionDetails, lastCheckDate, nextVersionDetails, isUpdateAvailable }, - fetchVersionErrorMessage, - isLoadingVersionDetails, - isDefaultView, - getCurrentVersionDetails, - ] = useVersionDetails(); - const [output, updateErrorMessage, isUpdated, updateFailed, launchUpdate] = usePerformUpdate(); + const isDefaultView = !latest; const isLoading = isLoadingVersionDetails || isLoadingSettings; const handleCheckForUpdates = (e: MouseEvent) => { @@ -31,32 +34,19 @@ export const UpdatePanel: FC<{}> = () => { setForceUpdate(true); } - getCurrentVersionDetails({ force: true }); + dispatch(checkUpdatesAction()); }; - useEffect(() => { - setErrorMessage(fetchVersionErrorMessage || updateErrorMessage); - - const timeout = setTimeout(() => { - setErrorMessage(''); - }, 5000); - - return () => { - clearTimeout(timeout); - }; - }, [fetchVersionErrorMessage, updateErrorMessage]); - - const handleUpdate = () => { - setShowModal(true); - launchUpdate(); + const handleOpenUpdates = () => { + window.location.assign(PMM_UPDATES_LINK.url!); }; return ( <>
- - {isUpdateAvailable && !isDefaultView && settings?.updatesEnabled && isAuthorized && !isLoading && isOnline ? ( - + {!!installed && } + {updateAvailable && !isDefaultView && settings?.updatesEnabled && isAuthorized && !isLoading && isOnline ? ( + ) : null} {isLoading ? (
@@ -64,11 +54,10 @@ export const UpdatePanel: FC<{}> = () => {
) : ( <> - {(isUpdateAvailable || forceUpdate) && settings?.updatesEnabled && isAuthorized && isOnline ? ( + {(updateAvailable || forceUpdate) && settings?.updatesEnabled && isAuthorized && isOnline ? (
- {/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */} -
) : ( @@ -84,17 +73,9 @@ export const UpdatePanel: FC<{}> = () => {
- ); }; diff --git a/public/app/plugins/panel/pmm-update/UpdatePanel.utils.test.ts b/public/app/plugins/panel/pmm-update/UpdatePanel.utils.test.ts index 7e53cee5a2f18..c8500f350c62c 100644 --- a/public/app/plugins/panel/pmm-update/UpdatePanel.utils.test.ts +++ b/public/app/plugins/panel/pmm-update/UpdatePanel.utils.test.ts @@ -1,5 +1,4 @@ import { formatDateWithYear, formatDateWithTime } from './UpdatePanel.utils'; -import { ISOTimestamp } from './types'; describe('UpdatePanel utils', () => { const timestamp1 = '2020-06-08T19:16:57Z'; @@ -8,15 +7,15 @@ describe('UpdatePanel utils', () => { const timestamp4 = '2021-04-06T00:00:00Z'; it('should format an ISO 8601 timestamp correctly as date without time', () => { - expect(formatDateWithYear(timestamp1 as ISOTimestamp)).toBe('June 08, 2020 UTC'); - expect(formatDateWithYear(timestamp2 as ISOTimestamp)).toBe('June 08, 2020 UTC'); - expect(formatDateWithYear(timestamp3 as ISOTimestamp)).toBe('June 07, 2020 UTC'); - expect(formatDateWithYear(timestamp4 as ISOTimestamp)).toBe('April 06, 2021 UTC'); + expect(formatDateWithYear(timestamp1)).toBe('June 08, 2020 UTC'); + expect(formatDateWithYear(timestamp2)).toBe('June 08, 2020 UTC'); + expect(formatDateWithYear(timestamp3)).toBe('June 07, 2020 UTC'); + expect(formatDateWithYear(timestamp4)).toBe('April 06, 2021 UTC'); }); it('should format an ISO 8601 timestamp correctly as date with time', () => { - expect(formatDateWithTime(timestamp1 as ISOTimestamp)).toBe('June 08, 19:16 UTC'); - expect(formatDateWithTime(timestamp2 as ISOTimestamp)).toBe('June 08, 0:06 UTC'); - expect(formatDateWithTime(timestamp3 as ISOTimestamp)).toBe('June 07, 23:36 UTC'); - expect(formatDateWithTime(timestamp4 as ISOTimestamp)).toBe('April 06, 0:00 UTC'); + expect(formatDateWithTime(timestamp1)).toBe('June 08, 19:16 UTC'); + expect(formatDateWithTime(timestamp2)).toBe('June 08, 0:06 UTC'); + expect(formatDateWithTime(timestamp3)).toBe('June 07, 23:36 UTC'); + expect(formatDateWithTime(timestamp4)).toBe('April 06, 0:00 UTC'); }); }); diff --git a/public/app/plugins/panel/pmm-update/UpdatePanel.utils.ts b/public/app/plugins/panel/pmm-update/UpdatePanel.utils.ts index 13d1d55014724..06042c2d8d5a2 100644 --- a/public/app/plugins/panel/pmm-update/UpdatePanel.utils.ts +++ b/public/app/plugins/panel/pmm-update/UpdatePanel.utils.ts @@ -1,14 +1,12 @@ import { format } from 'date-fns'; import { enUS } from 'date-fns/locale'; -import { ISOTimestamp } from './types'; - -export const formatDateWithTime = (timestamp: ISOTimestamp) => { +export const formatDateWithTime = (timestamp: string) => { const date = new Date(timestamp); return `${format(date.valueOf() + date.getTimezoneOffset() * 60 * 1000, 'MMMM dd, H:mm', { locale: enUS })} UTC`; }; -export const formatDateWithYear = (timestamp: ISOTimestamp) => { +export const formatDateWithYear = (timestamp: string) => { const date = new Date(timestamp); return `${format(date.valueOf() + date.getTimezoneOffset() * 60 * 1000, 'MMMM dd, yyyy', { locale: enUS })} UTC`; }; diff --git a/public/app/plugins/panel/pmm-update/components/AvailableUpdate/AvailableUpdate.styles.ts b/public/app/plugins/panel/pmm-update/components/AvailableUpdate/AvailableUpdate.styles.ts index 9d52805e87ea5..eb74de4515715 100644 --- a/public/app/plugins/panel/pmm-update/components/AvailableUpdate/AvailableUpdate.styles.ts +++ b/public/app/plugins/panel/pmm-update/components/AvailableUpdate/AvailableUpdate.styles.ts @@ -1,15 +1,15 @@ import { css } from '@emotion/css'; -import { GrafanaTheme } from '@grafana/data'; +import { GrafanaTheme2 } from '@grafana/data'; -export const getStyles = ({ spacing, typography }: GrafanaTheme) => ({ +export const getStyles = ({ spacing, typography }: GrafanaTheme2) => ({ availableUpdate: css` align-items: flex-start; display: flex; - font-weight: ${typography.weight.bold}; + font-weight: ${typography.fontWeightBold}; justify-content: flex-start; - line-height: ${typography.lineHeight.sm}; - margin-top: ${spacing.xs}; + line-height: ${typography.bodySmall.lineHeight}; + margin-top: ${spacing(0.5)}; > div { display: flex; @@ -21,18 +21,18 @@ export const getStyles = ({ spacing, typography }: GrafanaTheme) => ({ `, whatsNewLink: css` height: 1em; - margin-top: ${spacing.xs}; + margin-top: ${spacing(0.5)}; padding: 0; `, releaseDate: css` font-size: ${typography.size.sm}; - font-weight: ${typography.weight.regular}; + font-weight: ${typography.fontWeightRegular}; `, latestVersion: css` - margin-right: ${spacing.xs}; + margin-right: ${spacing(0.5)}; `, infoIcon: css` - margin-left: ${spacing.xs}; - margin-right: ${spacing.sm}; + margin-left: ${spacing(0.5)}; + margin-right: ${spacing(1)}; `, }); diff --git a/public/app/plugins/panel/pmm-update/components/AvailableUpdate/AvailableUpdate.test.tsx b/public/app/plugins/panel/pmm-update/components/AvailableUpdate/AvailableUpdate.test.tsx index 3ceb6a4be498e..4ae52c6c767d6 100644 --- a/public/app/plugins/panel/pmm-update/components/AvailableUpdate/AvailableUpdate.test.tsx +++ b/public/app/plugins/panel/pmm-update/components/AvailableUpdate/AvailableUpdate.test.tsx @@ -1,38 +1,39 @@ import { fireEvent, render, screen } from '@testing-library/react'; import React from 'react'; +import { LatestInformation } from 'app/percona/shared/core/reducers/updates'; + import { AvailableUpdate } from './AvailableUpdate'; -const nextFullVersion = 'x.y.z-rc.j+1234567890'; -const nextVersion = 'x.y.z'; +const version = 'x.y.z'; +const tag = 'percona/pmm-server:x.y.z-rc.j+1234567890'; const newsLink = 'https://percona.com'; -const nextVersionDate = '23 Jun'; +const timestamp = '2024-06-23T00:00:00.000Z'; -const nextVersionDetails = { - nextVersionDate, - nextVersion, - nextFullVersion, - newsLink, +const nextVersion: LatestInformation = { + version, + tag, + timestamp, }; describe('AvailableUpdate::', () => { it('should show only the short version by default', () => { - render(); + render(); - expect(screen.getByTestId('update-latest-version').textContent).toEqual(nextVersion); + expect(screen.getByTestId('update-latest-version')).toHaveTextContent(version); }); it('should show the news link if present', () => { - render(); + render(); expect(screen.getByTestId('update-news-link')).toBeTruthy(); }); it('should show the full version on alt-click', () => { - render(); + render(); fireEvent.click(screen.getByTestId('update-latest-section'), { altKey: true }); - expect(screen.getByTestId('update-latest-version').textContent).toEqual(nextFullVersion); + expect(screen.getByTestId('update-latest-version')).toHaveTextContent(tag); }); }); diff --git a/public/app/plugins/panel/pmm-update/components/AvailableUpdate/AvailableUpdate.tsx b/public/app/plugins/panel/pmm-update/components/AvailableUpdate/AvailableUpdate.tsx index e1d353401d220..476c85af5dd72 100755 --- a/public/app/plugins/panel/pmm-update/components/AvailableUpdate/AvailableUpdate.tsx +++ b/public/app/plugins/panel/pmm-update/components/AvailableUpdate/AvailableUpdate.tsx @@ -1,19 +1,17 @@ import React, { FC } from 'react'; -import { useStyles, Icon, LinkButton, Tooltip } from '@grafana/ui'; +import { Icon, LinkButton, Tooltip, useStyles2 } from '@grafana/ui'; import { useToggleOnAltClick } from '../../hooks'; -import { AvailableUpdateProps } from '../../types'; import { Messages } from './AvailableUpdate.messages'; import { getStyles } from './AvailableUpdate.styles'; +import { AvailableUpdateProps } from './AvailableUpdate.types'; -export const AvailableUpdate: FC = ({ nextVersionDetails }) => { - const styles = useStyles(getStyles); +export const AvailableUpdate: FC = ({ nextVersion, newsLink }) => { + const styles = useStyles2(getStyles); const [showFullVersion, handleToggleShowFullVersion] = useToggleOnAltClick(false); - const { nextVersionDate, nextVersion, nextFullVersion, newsLink } = nextVersionDetails; - return ( // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
= ({ nextVersionDetails } {Messages.availableVersion} :  - {showFullVersion ? nextFullVersion : nextVersion} + {showFullVersion ? nextVersion?.tag : nextVersion?.version} - ({nextVersionDate}) + ({nextVersion?.timestamp}) diff --git a/public/app/plugins/panel/pmm-update/components/AvailableUpdate/AvailableUpdate.types.ts b/public/app/plugins/panel/pmm-update/components/AvailableUpdate/AvailableUpdate.types.ts new file mode 100644 index 0000000000000..1ec7b355a349e --- /dev/null +++ b/public/app/plugins/panel/pmm-update/components/AvailableUpdate/AvailableUpdate.types.ts @@ -0,0 +1,6 @@ +import { LatestInformation } from 'app/percona/shared/core/reducers/updates'; + +export interface AvailableUpdateProps { + nextVersion?: LatestInformation; + newsLink?: string; +} diff --git a/public/app/plugins/panel/pmm-update/components/CenteredButton/CenteredButton.styles.ts b/public/app/plugins/panel/pmm-update/components/CenteredButton/CenteredButton.styles.ts deleted file mode 100644 index 09d1fc59aecf7..0000000000000 --- a/public/app/plugins/panel/pmm-update/components/CenteredButton/CenteredButton.styles.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { css } from '@emotion/css'; - -export const centeredButton = css` - display: flex; - justify-content: center; - margin: 10px 0; - width: 100%; -`; diff --git a/public/app/plugins/panel/pmm-update/components/CenteredButton/CenteredButton.test.tsx b/public/app/plugins/panel/pmm-update/components/CenteredButton/CenteredButton.test.tsx deleted file mode 100644 index 55957bd225725..0000000000000 --- a/public/app/plugins/panel/pmm-update/components/CenteredButton/CenteredButton.test.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { render, screen } from '@testing-library/react'; -import React from 'react'; - -import { CenteredButton } from './CenteredButton'; - -describe('CenteredButton::', () => { - it('should pass props to child component', () => { - render(Test); - - expect(screen.getAllByTestId('foobar')).toHaveLength(1); - }); -}); diff --git a/public/app/plugins/panel/pmm-update/components/CenteredButton/CenteredButton.tsx b/public/app/plugins/panel/pmm-update/components/CenteredButton/CenteredButton.tsx deleted file mode 100644 index 2654ad5b52eca..0000000000000 --- a/public/app/plugins/panel/pmm-update/components/CenteredButton/CenteredButton.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { cx } from '@emotion/css'; -import React, { FC } from 'react'; - -import { Button, ButtonProps } from '@grafana/ui'; - -import * as styles from './CenteredButton.styles'; - -export const CenteredButton: FC = ({ children, className, ...props }) => ( - -); diff --git a/public/app/plugins/panel/pmm-update/components/CurrentVersion/CurrentVersion.styles.ts b/public/app/plugins/panel/pmm-update/components/CurrentVersion/CurrentVersion.styles.ts index 8419909e672b4..e5167a0fd6964 100644 --- a/public/app/plugins/panel/pmm-update/components/CurrentVersion/CurrentVersion.styles.ts +++ b/public/app/plugins/panel/pmm-update/components/CurrentVersion/CurrentVersion.styles.ts @@ -1,20 +1,20 @@ import { css } from '@emotion/css'; -import { GrafanaTheme } from '@grafana/data'; +import { GrafanaTheme2 } from '@grafana/data'; -export const getStyles = ({ spacing, typography }: GrafanaTheme) => ({ +export const getStyles = ({ spacing, typography }: GrafanaTheme2) => ({ infoIcon: css` - margin-left: ${spacing.xs}; - margin-right: ${spacing.sm}; + margin-left: ${spacing(0.5)}; + margin-right: ${spacing(1)}; `, currentVersion: css` p { - font-size: ${typography.size.md}; - line-height: ${typography.lineHeight.sm}; - margin-bottom: ${spacing.xxs}; + font-size: ${typography.body.fontSize}; + line-height: ${typography.body.lineHeight}; + margin-bottom: ${spacing(0.25)}; } `, releaseDate: css` - font-size: ${typography.size.sm}; + font-size: ${typography.bodySmall.fontSize}; `, }); diff --git a/public/app/plugins/panel/pmm-update/components/CurrentVersion/CurrentVersion.test.tsx b/public/app/plugins/panel/pmm-update/components/CurrentVersion/CurrentVersion.test.tsx index 74e9490d6b1e7..3061ecfca2edf 100644 --- a/public/app/plugins/panel/pmm-update/components/CurrentVersion/CurrentVersion.test.tsx +++ b/public/app/plugins/panel/pmm-update/components/CurrentVersion/CurrentVersion.test.tsx @@ -1,31 +1,32 @@ import { render, screen, fireEvent } from '@testing-library/react'; import React from 'react'; +import { CurrentInformation } from 'app/percona/shared/core/reducers/updates'; + import { CurrentVersion } from './CurrentVersion'; -const installedFullVersion = 'x.y.z-rc.j+1234567890'; -const installedVersion = 'x.y.z'; -const installedVersionDate = '23 Jun'; +const fullVersion = 'x.y.z-rc.j+1234567890'; +const version = 'x.y.z'; +const timestamp = '2024-06-23T00:00:00.000Z'; +const date = 'June 23, 2024 UTC'; -const installedVersionDetails = { - installedFullVersion, - installedVersion, - installedVersionDate, +const currentInformation: CurrentInformation = { + fullVersion, + version, + timestamp, }; describe('CurrentVersion::', () => { it('should show only the short version by default', async () => { - const container = render(); + const container = render(); - expect(container.baseElement.textContent).toBe(`Current version: ${installedVersion} (${installedVersionDate})`); + expect(container.baseElement).toHaveTextContent(`Current version: ${version} (${date})`); }); it('should show the full version on alt-click', () => { - const container = render(); + const container = render(); fireEvent.click(screen.getByTestId('update-installed-version'), { altKey: true }); - expect(container.baseElement.textContent).toBe( - `Current version: ${installedFullVersion} (${installedVersionDate})` - ); + expect(container.baseElement).toHaveTextContent(`Current version: ${fullVersion} (${date})`); }); }); diff --git a/public/app/plugins/panel/pmm-update/components/CurrentVersion/CurrentVersion.tsx b/public/app/plugins/panel/pmm-update/components/CurrentVersion/CurrentVersion.tsx index 40881dbd3fec4..3f52bbe811c5b 100644 --- a/public/app/plugins/panel/pmm-update/components/CurrentVersion/CurrentVersion.tsx +++ b/public/app/plugins/panel/pmm-update/components/CurrentVersion/CurrentVersion.tsx @@ -1,17 +1,17 @@ import React, { FC } from 'react'; -import { Icon, Tooltip, useStyles } from '@grafana/ui'; +import { Icon, Tooltip, useStyles2 } from '@grafana/ui'; +import { formatDateWithYear } from '../../UpdatePanel.utils'; import { useToggleOnAltClick } from '../../hooks'; -import { CurrentVersionProps } from '../../types'; import { Messages } from './CurrentVersion.messages'; import { getStyles } from './CurrentVersion.styles'; +import { CurrentVersionProps } from './CurrentVersion.types'; -export const CurrentVersion: FC = ({ installedVersionDetails }) => { - const styles = useStyles(getStyles); +export const CurrentVersion: FC = ({ currentVersion }) => { + const styles = useStyles2(getStyles); const [showFullVersion, handleToggleShowFullVersion] = useToggleOnAltClick(false); - const { installedVersionDate, installedVersion, installedFullVersion } = installedVersionDetails; return (
@@ -20,13 +20,13 @@ export const CurrentVersion: FC = ({ installedVersionDetail {Messages.currentVersion}:  - {showFullVersion ? installedFullVersion : installedVersion} + {showFullVersion ? currentVersion.fullVersion : currentVersion.version}   - {!!installedVersionDate && ( + {!!currentVersion.timestamp && ( <> - ({installedVersionDate}) + ({formatDateWithYear(currentVersion.timestamp)}) diff --git a/public/app/plugins/panel/pmm-update/components/CurrentVersion/CurrentVersion.types.ts b/public/app/plugins/panel/pmm-update/components/CurrentVersion/CurrentVersion.types.ts new file mode 100644 index 0000000000000..2f6c29e07d2f9 --- /dev/null +++ b/public/app/plugins/panel/pmm-update/components/CurrentVersion/CurrentVersion.types.ts @@ -0,0 +1,5 @@ +import { CurrentInformation } from 'app/percona/shared/core/reducers/updates'; + +export interface CurrentVersionProps { + currentVersion: CurrentInformation; +} diff --git a/public/app/plugins/panel/pmm-update/components/InfoBox/InfoBox.constants.ts b/public/app/plugins/panel/pmm-update/components/InfoBox/InfoBox.constants.ts index d0125896fc50f..3e1f675282e8b 100644 --- a/public/app/plugins/panel/pmm-update/components/InfoBox/InfoBox.constants.ts +++ b/public/app/plugins/panel/pmm-update/components/InfoBox/InfoBox.constants.ts @@ -1 +1 @@ -export const PMM_ADVANCED_SETTINGS_URL = '/graph/settings/advanced-settings'; +export const PMM_ADVANCED_SETTINGS_URL = '/settings/advanced-settings'; diff --git a/public/app/plugins/panel/pmm-update/components/InfoBox/InfoBox.styles.ts b/public/app/plugins/panel/pmm-update/components/InfoBox/InfoBox.styles.ts index e4c664ffd81b2..9bcf397b13c6c 100644 --- a/public/app/plugins/panel/pmm-update/components/InfoBox/InfoBox.styles.ts +++ b/public/app/plugins/panel/pmm-update/components/InfoBox/InfoBox.styles.ts @@ -1,8 +1,8 @@ import { css } from '@emotion/css'; -import { GrafanaTheme } from '@grafana/data'; +import { GrafanaTheme2 } from '@grafana/data'; -export const getStyles = ({ colors, spacing }: GrafanaTheme) => ({ +export const getStyles = ({ colors, spacing }: GrafanaTheme2) => ({ infoBox: css` margin: 10px 0; display: flex; @@ -13,12 +13,13 @@ export const getStyles = ({ colors, spacing }: GrafanaTheme) => ({ box-sizing: border-box; border: 1px solid #292929; text-align: center; - padding: ${spacing.xs}; + padding: ${spacing(0.5)}; `, link: css` - color: ${colors.linkExternal}; + color: ${colors.text.link}; + &:hover { - color: ${colors.textBlue}; + color: ${colors.primary.text}; } `, }); diff --git a/public/app/plugins/panel/pmm-update/components/InfoBox/InfoBox.tsx b/public/app/plugins/panel/pmm-update/components/InfoBox/InfoBox.tsx index 6c520123afbe0..28bdf8223c5e1 100644 --- a/public/app/plugins/panel/pmm-update/components/InfoBox/InfoBox.tsx +++ b/public/app/plugins/panel/pmm-update/components/InfoBox/InfoBox.tsx @@ -1,15 +1,15 @@ import React, { FC, PropsWithChildren } from 'react'; +import { Link } from 'react-router-dom'; -import { useStyles } from '@grafana/ui'; - -import { InfoBoxProps } from '../../types'; +import { useStyles2 } from '@grafana/ui'; import { PMM_ADVANCED_SETTINGS_URL } from './InfoBox.constants'; import { Messages } from './InfoBox.messages'; import { getStyles } from './InfoBox.styles'; +import { InfoBoxProps } from './InfoBoxProps.types'; const UpdateInfo: FC = ({ children }) => { - const styles = useStyles(getStyles); + const styles = useStyles2(getStyles); return (
@@ -19,7 +19,7 @@ const UpdateInfo: FC = ({ children }) => { }; export const InfoBox: FC = ({ upToDate = false, hasNoAccess, updatesDisabled, isOnline = true }) => { - const styles = useStyles(getStyles); + const styles = useStyles2(getStyles); if (hasNoAccess) { return ( @@ -42,9 +42,9 @@ export const InfoBox: FC = ({ upToDate = false, hasNoAccess, updat

{Messages.updatesDisabled} - + {Messages.pmmSettings} - +

); diff --git a/public/app/plugins/panel/pmm-update/components/InfoBox/InfoBoxProps.types.ts b/public/app/plugins/panel/pmm-update/components/InfoBox/InfoBoxProps.types.ts new file mode 100644 index 0000000000000..a46b9984a16af --- /dev/null +++ b/public/app/plugins/panel/pmm-update/components/InfoBox/InfoBoxProps.types.ts @@ -0,0 +1,6 @@ +export interface InfoBoxProps { + upToDate?: boolean; + updatesDisabled?: boolean; + hasNoAccess?: boolean; + isOnline?: boolean; +} diff --git a/public/app/plugins/panel/pmm-update/components/LastCheck/LastCheck.messages.ts b/public/app/plugins/panel/pmm-update/components/LastCheck/LastCheck.messages.ts index f5448fb81450c..3fb92bb49d337 100644 --- a/public/app/plugins/panel/pmm-update/components/LastCheck/LastCheck.messages.ts +++ b/public/app/plugins/panel/pmm-update/components/LastCheck/LastCheck.messages.ts @@ -1,3 +1,4 @@ export const Messages = { lastCheck: 'Last check: ', + checkAriaLabel: 'Check for updates', }; diff --git a/public/app/plugins/panel/pmm-update/components/LastCheck/LastCheck.styles.ts b/public/app/plugins/panel/pmm-update/components/LastCheck/LastCheck.styles.ts index a136cf69756d1..fb3a6246197e5 100644 --- a/public/app/plugins/panel/pmm-update/components/LastCheck/LastCheck.styles.ts +++ b/public/app/plugins/panel/pmm-update/components/LastCheck/LastCheck.styles.ts @@ -1,15 +1,16 @@ import { css } from '@emotion/css'; -export const lastCheck = css` - bottom: 0; - display: flex; - justify-content: space-between; - align-items: center; - width: 100%; - font-size: 12px; - height: 1em; - - button { +export const styles = { + container: css` + bottom: 0; + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + font-size: 12px; + height: 1em; + `, + button: css` position: relative; display: flex; align-items: center; @@ -18,5 +19,5 @@ export const lastCheck = css` border-radius: 50%; background-color: transparent; border: none; - } -`; + `, +}; diff --git a/public/app/plugins/panel/pmm-update/components/LastCheck/LastCheck.test.tsx b/public/app/plugins/panel/pmm-update/components/LastCheck/LastCheck.test.tsx index b89105e770f9d..23d305701294e 100644 --- a/public/app/plugins/panel/pmm-update/components/LastCheck/LastCheck.test.tsx +++ b/public/app/plugins/panel/pmm-update/components/LastCheck/LastCheck.test.tsx @@ -7,6 +7,10 @@ describe('LastCheck::', () => { const lastCheckDate = '12345'; const fakeHandleClick = jest.fn(); + beforeEach(() => { + fakeHandleClick.mockClear(); + }); + it('should show the passed last check date', () => { const container = render(); @@ -18,6 +22,6 @@ describe('LastCheck::', () => { fireEvent.click(screen.getByTestId('update-last-check-button')); - expect(fakeHandleClick).toBeCalledTimes(1); + expect(fakeHandleClick).toHaveBeenCalledTimes(1); }); }); diff --git a/public/app/plugins/panel/pmm-update/components/LastCheck/LastCheck.tsx b/public/app/plugins/panel/pmm-update/components/LastCheck/LastCheck.tsx index c1e8951ae6ceb..978e61e2d9d1d 100644 --- a/public/app/plugins/panel/pmm-update/components/LastCheck/LastCheck.tsx +++ b/public/app/plugins/panel/pmm-update/components/LastCheck/LastCheck.tsx @@ -1,26 +1,24 @@ import React, { FC } from 'react'; -import { Button, IconName } from '@grafana/ui'; - -import { LastCheckProps } from '../../types'; +import { IconButton } from '@grafana/ui'; import { Messages } from './LastCheck.messages'; -import * as styles from './LastCheck.styles'; +import { styles } from './LastCheck.styles'; +import { LastCheckProps } from './LastCheck.types'; export const LastCheck: FC = ({ lastCheckDate, onCheckForUpdates, disabled = false }) => ( -
+

{Messages.lastCheck} {lastCheckDate}

-
); diff --git a/public/app/plugins/panel/pmm-update/components/LastCheck/LastCheck.types.ts b/public/app/plugins/panel/pmm-update/components/LastCheck/LastCheck.types.ts new file mode 100644 index 0000000000000..ec651d654f09f --- /dev/null +++ b/public/app/plugins/panel/pmm-update/components/LastCheck/LastCheck.types.ts @@ -0,0 +1,7 @@ +import { MouseEventHandler } from 'react'; + +export interface LastCheckProps { + lastCheckDate: string; + onCheckForUpdates: MouseEventHandler; + disabled?: boolean; +} diff --git a/public/app/plugins/panel/pmm-update/components/ProgressModal/ProgressModal.messages.ts b/public/app/plugins/panel/pmm-update/components/ProgressModal/ProgressModal.messages.ts deleted file mode 100644 index 77f3111175e27..0000000000000 --- a/public/app/plugins/panel/pmm-update/components/ProgressModal/ProgressModal.messages.ts +++ /dev/null @@ -1,6 +0,0 @@ -export const Messages = { - copyToClipboard: 'Copy to clipboard', - updateSuccessNotice: 'PMM has been successfully upgraded to version', - log: 'Log', - close: 'Close', -}; diff --git a/public/app/plugins/panel/pmm-update/components/ProgressModal/ProgressModal.styles.ts b/public/app/plugins/panel/pmm-update/components/ProgressModal/ProgressModal.styles.ts deleted file mode 100644 index 59f6f9ef05d93..0000000000000 --- a/public/app/plugins/panel/pmm-update/components/ProgressModal/ProgressModal.styles.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { css } from '@emotion/css'; - -import { GrafanaTheme2 } from '@grafana/data'; - -export const getStyles = (theme: GrafanaTheme2) => ({ - modal: css` - background-clip: padding-box; - background: ${theme.colors.background.primary}; - box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); - display: flex; - flex-direction: column; - left: 0; - margin-left: auto; - margin-right: auto; - max-width: 750px; - outline: none; - position: fixed; - right: 0; - top: 10%; - width: 100%; - z-index: 1050; - padding: 28px; - `, - outputHeader: css` - display: flex; - - span { - flex: 1; - } - `, - clipboardButton: css` - margin-right: 8px; - `, - output: css` - height: 200px; - margin-right: 0; - margin-top: 15px; - overflow-y: scroll; - width: 100%; - `, - outputContent: css` - margin-top: 15px; - padding: 1em; - `, - outputVisibilityToggle: css` - cursor: pointer; - margin-right: 5px; - `, - successNote: css` - padding: 80px; - text-align: center; - `, - closeModal: css` - align-self: center; - `, -}); diff --git a/public/app/plugins/panel/pmm-update/components/ProgressModal/ProgressModal.test.tsx b/public/app/plugins/panel/pmm-update/components/ProgressModal/ProgressModal.test.tsx deleted file mode 100644 index 68f792a86dab8..0000000000000 --- a/public/app/plugins/panel/pmm-update/components/ProgressModal/ProgressModal.test.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import { render, screen, fireEvent } from '@testing-library/react'; -import React from 'react'; - -import { ProgressModal } from '../../components'; - -import { Messages } from './ProgressModal.messages'; - -describe('ProgressModal::', () => { - const version = 'x.y.z'; - - it('should be closed by default', () => { - render(); - expect(screen.queryByTestId('progress-modal-container')).not.toBeInTheDocument(); - }); - - it('should show the upgrade in progress if isUpdated is false', () => { - render(); - - expect(screen.getByText(Messages.copyToClipboard)).toBeInTheDocument(); - expect(screen.getByTestId('modal-chevron-icon-angle-down')).toBeInTheDocument(); - expect(screen.getByTestId('modal-output-pre')).toBeInTheDocument(); - expect(screen.queryByTestId('modal-update-success-text')).not.toBeInTheDocument(); - expect(screen.queryByTestId('modal-close')).not.toBeInTheDocument(); - }); - - it('should show a close button when isUpdated is true', () => { - render(); - - expect(screen.getByTestId('modal-update-success-text')).toBeInTheDocument(); - expect(screen.getByTestId('modal-close')).toBeInTheDocument(); - expect(screen.queryByTestId(Messages.copyToClipboard)).not.toBeInTheDocument(); - expect(screen.queryByTestId('modal-chevron-icon-angle-down')).not.toBeInTheDocument(); - expect(screen.queryByTestId('modal-output-pre')).not.toBeInTheDocument(); - }); - - it('should toggle the upgrade output on click on the chevron icon', () => { - render(); - const chevron = screen.getByTestId('modal-chevron-icon-angle-down'); - - fireEvent.click(chevron); - expect(chevron.getAttribute('data-testid')).toBe('modal-chevron-icon-angle-up'); - fireEvent.click(chevron); - expect(chevron.getAttribute('data-testid')).toBe('modal-chevron-icon-angle-down'); - }); - - it('should reload the page when the close button is clicked', () => { - const mockedReload = jest.fn(); - - Object.defineProperty(window, 'location', { - writable: true, - value: { reload: mockedReload }, - }); - - render(); - - fireEvent.click(screen.getByTestId('modal-close')); - - expect(mockedReload).toBeCalledTimes(1); - }); -}); diff --git a/public/app/plugins/panel/pmm-update/components/ProgressModal/ProgressModal.tsx b/public/app/plugins/panel/pmm-update/components/ProgressModal/ProgressModal.tsx deleted file mode 100644 index 622e5f3a59058..0000000000000 --- a/public/app/plugins/panel/pmm-update/components/ProgressModal/ProgressModal.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import React, { useCallback, useLayoutEffect, useRef, useState, FC } from 'react'; - -import { ClipboardButton, Icon, Button, Modal, IconName, useStyles2 } from '@grafana/ui'; - -import { ProgressModalHeader } from '../../components'; -import { useClickOutside } from '../../hooks'; -import { ProgressModalProps } from '../../types'; - -import { Messages } from './ProgressModal.messages'; -import { getStyles } from './ProgressModal.styles'; - -export const ProgressModal: FC = ({ - version, - errorMessage = '', - isOpen = false, - isUpdated = false, - output = '', - updateFailed = false, -}) => { - const styles = useStyles2(getStyles); - const outputRef = useRef(null); - const modalRef = useRef(null); - const [isOutputShown, setIsOutputShown] = useState(true); - - useClickOutside(modalRef, () => { - if (isUpdated) { - // @ts-ignore - // eslint-disable-next-line no-restricted-globals - location.reload(true); - } - }); - - useLayoutEffect(() => { - // scroll upgrade status to the end. - const interval = setInterval(() => outputRef.current?.scrollIntoView(false), 500); - - return () => { - clearInterval(interval); - }; - }, []); - - const handleToggleShowOutput = () => { - setIsOutputShown((isOutputShown) => !isOutputShown); - }; - - const reloadAfterUpdate = () => { - // @ts-ignore - // eslint-disable-next-line no-restricted-globals - location.reload(true); - }; - - const copyToClipboard = useCallback(() => outputRef.current?.textContent ?? '', [outputRef]); - - const chevronIcon: IconName = isOutputShown ? 'angle-down' : 'angle-up'; - - // TODO (nicolalamacchia): componentize this further - return ( - -
- - {!isUpdated ? ( -
-
- - {Messages.log} - - {Messages.copyToClipboard} - -
- {isOutputShown && ( -
-
-                  {output}
-                
-
- )} -
- ) : ( - <> -
-
- {Messages.updateSuccessNotice} {version} -
-
- - - )} -
-
- ); -}; diff --git a/public/app/plugins/panel/pmm-update/components/ProgressModalHeader/ProgressModalHeader.messages.ts b/public/app/plugins/panel/pmm-update/components/ProgressModalHeader/ProgressModalHeader.messages.ts deleted file mode 100644 index 1c4aab9300f21..0000000000000 --- a/public/app/plugins/panel/pmm-update/components/ProgressModalHeader/ProgressModalHeader.messages.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const Messages = { - updateInProgress: 'Upgrade in progress', - updateFailed: 'Error', - updateSucceeded: 'Success', -}; diff --git a/public/app/plugins/panel/pmm-update/components/ProgressModalHeader/ProgressModalHeader.test.tsx b/public/app/plugins/panel/pmm-update/components/ProgressModalHeader/ProgressModalHeader.test.tsx deleted file mode 100644 index 56d041f2ca185..0000000000000 --- a/public/app/plugins/panel/pmm-update/components/ProgressModalHeader/ProgressModalHeader.test.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { render, screen } from '@testing-library/react'; -import React from 'react'; - -import { ProgressModalHeader } from './ProgressModalHeader'; -import { Messages } from './ProgressModalHeader.messages'; - -describe('ProgressModalHeader::', () => { - it('should show that the upgrade is in progress by default', () => { - render(); - - expect(screen.getByText(Messages.updateInProgress)).toBeInTheDocument(); - }); - - it('should show that the upgrade succeeded if isUpdated is true', () => { - render(); - - expect(screen.getByText(Messages.updateSucceeded)).toBeInTheDocument(); - }); - - it('should show ignore updateFailed if isUpdated is true', () => { - render(); - - expect(screen.getByText(Messages.updateSucceeded)).toBeInTheDocument(); - }); - - it('should show the passed error message if the upgrade failed', () => { - const errorMessage = 'Test Error'; - render(); - - expect(screen.getByText(Messages.updateFailed)).toBeInTheDocument(); - expect(screen.getByText(errorMessage)).toBeInTheDocument(); - }); -}); diff --git a/public/app/plugins/panel/pmm-update/components/ProgressModalHeader/ProgressModalHeader.tsx b/public/app/plugins/panel/pmm-update/components/ProgressModalHeader/ProgressModalHeader.tsx deleted file mode 100644 index b81fd9580a668..0000000000000 --- a/public/app/plugins/panel/pmm-update/components/ProgressModalHeader/ProgressModalHeader.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import React, { FC } from 'react'; - -import { ProgressModalHeaderProps } from '../../types'; - -import { Messages } from './ProgressModalHeader.messages'; - -export const ProgressModalHeader: FC = ({ - errorMessage = '', - isUpdated = false, - updateFailed = false, -}) => ( - <> - {/* eslint-disable-next-line no-nested-ternary */} - {isUpdated ? ( -

{Messages.updateSucceeded}

- ) : !updateFailed ? ( -

{Messages.updateInProgress}

- ) : ( - <> -

{Messages.updateFailed}

-

{errorMessage}

- - )} - -); diff --git a/public/app/plugins/panel/pmm-update/components/index.ts b/public/app/plugins/panel/pmm-update/components/index.ts index 4eb5ebff3b7e0..a955214c06ee5 100644 --- a/public/app/plugins/panel/pmm-update/components/index.ts +++ b/public/app/plugins/panel/pmm-update/components/index.ts @@ -1,7 +1,4 @@ export { AvailableUpdate } from './AvailableUpdate/AvailableUpdate'; -export { CenteredButton } from './CenteredButton/CenteredButton'; export { CurrentVersion } from './CurrentVersion/CurrentVersion'; export { InfoBox } from './InfoBox/InfoBox'; export { LastCheck } from './LastCheck/LastCheck'; -export { ProgressModal } from './ProgressModal/ProgressModal'; -export { ProgressModalHeader } from './ProgressModalHeader/ProgressModalHeader'; diff --git a/public/app/plugins/panel/pmm-update/hooks/index.ts b/public/app/plugins/panel/pmm-update/hooks/index.ts index a8dd609b6bfac..44d2ff4dd08f8 100644 --- a/public/app/plugins/panel/pmm-update/hooks/index.ts +++ b/public/app/plugins/panel/pmm-update/hooks/index.ts @@ -1,6 +1 @@ -export { useApiCall } from './useApiCall'; -export { useClickOutside } from './useClickOutside'; -export { useInitializeUpdate } from './useInitializeUpdate'; -export { usePerformUpdate } from './usePerformUpdate'; export { useToggleOnAltClick } from './useToggleOnAltClick'; -export { useVersionDetails } from './useVersionDetails'; diff --git a/public/app/plugins/panel/pmm-update/hooks/useApiCall.test.tsx b/public/app/plugins/panel/pmm-update/hooks/useApiCall.test.tsx deleted file mode 100644 index f3ee6d8a0c727..0000000000000 --- a/public/app/plugins/panel/pmm-update/hooks/useApiCall.test.tsx +++ /dev/null @@ -1,126 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ - -import { fireEvent, render, screen, waitFor } from '@testing-library/react'; -import React, { FC } from 'react'; - -import { useApiCall } from './useApiCall'; - -const originalConsoleError = console.error; - -const HookWrapper: FC<{ fn: () => any; apiFnArgs?: any; apiFnArgsRetry?: any; retryDefault?: boolean }> = ({ - fn, - apiFnArgs, - apiFnArgsRetry, - retryDefault = true, -}) => { - const [data, errorMessage, isLoading, apiCall] = useApiCall(fn, apiFnArgs, apiFnArgsRetry, retryDefault); - - return ( - <> - {/* @ts-ignore */} - {data} - - {typeof errorMessage === 'string' ? errorMessage : (errorMessage as any).message} - - {isLoading && } -