Merge branch 'master' into issues/2752

This commit is contained in:
Roman Zabaluev 2023-04-27 10:03:20 +08:00 committed by GitHub
commit f9ba69dc71
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 62 additions and 161 deletions

View file

@ -1,52 +1,38 @@
import React from 'react'; import React from 'react';
import WarningIcon from 'components/common/Icons/WarningIcon'; import WarningIcon from 'components/common/Icons/WarningIcon';
import { gitCommitPath } from 'lib/paths'; import { gitCommitPath } from 'lib/paths';
import { useActuatorInfo } from 'lib/hooks/api/actuatorInfo';
import { BUILD_VERSION_PATTERN } from 'lib/constants';
import { useLatestVersion } from 'lib/hooks/api/latestVersion'; import { useLatestVersion } from 'lib/hooks/api/latestVersion';
import { formatTimestamp } from 'lib/dateTimeHelpers'; import { formatTimestamp } from 'lib/dateTimeHelpers';
import * as S from './Version.styled'; import * as S from './Version.styled';
import compareVersions from './compareVersions';
const Version: React.FC = () => { const Version: React.FC = () => {
const { data: actuatorInfo = {} } = useActuatorInfo();
const { data: latestVersionInfo = {} } = useLatestVersion(); const { data: latestVersionInfo = {} } = useLatestVersion();
const { buildTime, commitId, isLatestRelease } = latestVersionInfo.build;
const tag = actuatorInfo?.build?.version; const { versionTag } = latestVersionInfo?.latestRelease || '';
const commit = actuatorInfo?.git?.commit.id;
const { tag_name: latestTag } = latestVersionInfo;
const outdated = compareVersions(tag, latestTag);
const currentVersion = tag?.match(BUILD_VERSION_PATTERN)
? tag
: formatTimestamp(actuatorInfo?.build?.time);
if (!tag) return null;
return ( return (
<S.Wrapper> <S.Wrapper>
{!!outdated && ( {!isLatestRelease && (
<S.OutdatedWarning <S.OutdatedWarning
title={`Your app version is outdated. Current latest version is ${latestTag}`} title={`Your app version is outdated. Current latest version is ${versionTag}`}
> >
<WarningIcon /> <WarningIcon />
</S.OutdatedWarning> </S.OutdatedWarning>
)} )}
{commit && ( {commitId && (
<div> <div>
<S.CurrentCommitLink <S.CurrentCommitLink
title="Current commit" title="Current commit"
target="__blank" target="__blank"
href={gitCommitPath(commit)} href={gitCommitPath(commitId)}
> >
{commit} {commitId}
</S.CurrentCommitLink> </S.CurrentCommitLink>
</div> </div>
)} )}
<S.CurrentVersion>{currentVersion}</S.CurrentVersion> <S.CurrentVersion>{formatTimestamp(buildTime)}</S.CurrentVersion>
</S.Wrapper> </S.Wrapper>
); );
}; };

View file

@ -2,87 +2,40 @@ import React from 'react';
import { screen } from '@testing-library/dom'; import { screen } from '@testing-library/dom';
import Version from 'components/Version/Version'; import Version from 'components/Version/Version';
import { render } from 'lib/testHelpers'; import { render } from 'lib/testHelpers';
import { formatTimestamp } from 'lib/dateTimeHelpers';
import { useActuatorInfo } from 'lib/hooks/api/actuatorInfo';
import { useLatestVersion } from 'lib/hooks/api/latestVersion'; import { useLatestVersion } from 'lib/hooks/api/latestVersion';
import { actuatorInfoPayload } from 'lib/fixtures/actuatorInfo'; import {
import { latestVersionPayload } from 'lib/fixtures/latestVersion'; deprecatedVersionPayload,
latestVersionPayload,
} from 'lib/fixtures/latestVersion';
jest.mock('lib/hooks/api/actuatorInfo', () => ({
useActuatorInfo: jest.fn(),
}));
jest.mock('lib/hooks/api/latestVersion', () => ({ jest.mock('lib/hooks/api/latestVersion', () => ({
useLatestVersion: jest.fn(), useLatestVersion: jest.fn(),
})); }));
describe('Version Component', () => { describe('Version Component', () => {
const versionTag = 'v0.5.0'; const commitId = '96a577a';
const snapshotTag = 'test-SNAPSHOT';
const commitTag = 'befd3b328e2c9c7df57b0c5746561b2f7fee8813';
const actuatorVersionPayload = actuatorInfoPayload(versionTag);
const formattedTimestamp = formatTimestamp(actuatorVersionPayload.build.time);
describe('render latest version', () => {
beforeEach(() => { beforeEach(() => {
(useActuatorInfo as jest.Mock).mockImplementation(() => ({
data: actuatorVersionPayload,
}));
(useLatestVersion as jest.Mock).mockImplementation(() => ({ (useLatestVersion as jest.Mock).mockImplementation(() => ({
data: latestVersionPayload, data: latestVersionPayload,
})); }));
}); });
it('renders latest release version as current version', async () => {
render(<Version />);
expect(screen.getByText(commitId)).toBeInTheDocument();
});
describe('tag does not exist', () => { it('should not show warning icon if it is last release', async () => {
it('does not render component', async () => { render(<Version />);
(useActuatorInfo as jest.Mock).mockImplementation(() => ({ expect(screen.queryByRole('img')).not.toBeInTheDocument();
data: null,
}));
const { container } = render(<Version />);
expect(container.firstChild).toBeEmptyDOMElement();
}); });
}); });
describe('renders current version', () => { it('show warning icon if it is not last release', async () => {
it('renders release build version as current version', async () => { (useLatestVersion as jest.Mock).mockImplementation(() => ({
render(<Version />); data: deprecatedVersionPayload,
expect(screen.getByText(versionTag)).toBeInTheDocument();
});
it('renders formatted timestamp as current version when version is commit', async () => {
(useActuatorInfo as jest.Mock).mockImplementation(() => ({
data: actuatorInfoPayload(commitTag),
})); }));
render(<Version />); render(<Version />);
expect(screen.getByText(formattedTimestamp)).toBeInTheDocument(); expect(screen.getByRole('img')).toBeInTheDocument();
});
it('renders formatted timestamp as current version when version contains -SNAPSHOT', async () => {
(useActuatorInfo as jest.Mock).mockImplementation(() => ({
data: actuatorInfoPayload(snapshotTag),
}));
render(<Version />);
expect(screen.getByText(formattedTimestamp)).toBeInTheDocument();
});
});
describe('outdated build version', () => {
it('renders warning message', async () => {
(useActuatorInfo as jest.Mock).mockImplementation(() => ({
data: actuatorInfoPayload('v0.3.0'),
}));
render(<Version />);
expect(
screen.getByTitle(
`Your app version is outdated. Current latest version is ${latestVersionPayload.tag_name}`
)
).toBeInTheDocument();
});
});
describe('current commit id with link', () => {
it('renders', async () => {
render(<Version />);
expect(
screen.getByText(actuatorVersionPayload.git.commit.id)
).toBeInTheDocument();
});
}); });
}); });

View file

@ -13,6 +13,7 @@ const WarningIcon: React.FC = () => {
return ( return (
<WarningIconContainer> <WarningIconContainer>
<svg <svg
role="img"
width="14" width="14"
height="13" height="13"
viewBox="0 0 14 13" viewBox="0 0 14 13"

View file

@ -1,12 +0,0 @@
export const actuatorInfoPayload = (
version = 'befd3b328e2c9c7df57b0c5746561b2f7fee8813'
) => ({
git: { commit: { id: 'befd3b3' } },
build: {
artifact: 'kafka-ui-api',
name: 'kafka-ui-api',
time: '2022-09-15T09:52:21.753Z',
version,
group: 'com.provectus',
},
});

View file

@ -1,3 +1,16 @@
export const latestVersionPayload = { export const deprecatedVersionPayload = {
tag_name: 'v0.4.0', build: {
buildTime: '2023-04-14T09:47:35.463Z',
commitId: '96a577a',
isLatestRelease: false,
version: '96a577a98c6069376c5d22ed49cffd3739f1bbdc',
},
};
export const latestVersionPayload = {
build: {
buildTime: '2023-04-14T09:47:35.463Z',
commitId: '96a577a',
isLatestRelease: true,
version: '96a577a98c6069376c5d22ed49cffd3739f1bbdc',
},
}; };

View file

@ -1,17 +0,0 @@
import fetchMock from 'fetch-mock';
import * as hooks from 'lib/hooks/api/actuatorInfo';
import { expectQueryWorks, renderQueryHook } from 'lib/testHelpers';
import { actuatorInfoPayload } from 'lib/fixtures/actuatorInfo';
const actuatorInfoPath = '/actuator/info';
describe('Actuator info hooks', () => {
beforeEach(() => fetchMock.restore());
describe('useActuatorInfo', () => {
it('returns the correct data', async () => {
const mock = fetchMock.getOnce(actuatorInfoPath, actuatorInfoPayload());
const { result } = renderQueryHook(() => hooks.useActuatorInfo());
await expectQueryWorks(mock, result);
});
});
});

View file

@ -1,18 +1,16 @@
import fetchMock from 'fetch-mock'; import fetchMock from 'fetch-mock';
import { expectQueryWorks, renderQueryHook } from 'lib/testHelpers'; import { expectQueryWorks, renderQueryHook } from 'lib/testHelpers';
import * as hooks from 'lib/hooks/api/latestVersion';
import { GIT_REPO_LATEST_RELEASE_LINK } from 'lib/constants';
import { latestVersionPayload } from 'lib/fixtures/latestVersion'; import { latestVersionPayload } from 'lib/fixtures/latestVersion';
import { useLatestVersion } from 'lib/hooks/api/latestVersion';
const latestVersionPath = '/api/info';
describe('Latest version hooks', () => { describe('Latest version hooks', () => {
beforeEach(() => fetchMock.restore()); beforeEach(() => fetchMock.restore());
describe('useLatestVersion', () => { describe('useLatestVersion', () => {
it('returns the correct data', async () => { it('returns the correct data', async () => {
const mock = fetchMock.getOnce( const mock = fetchMock.getOnce(latestVersionPath, latestVersionPayload);
GIT_REPO_LATEST_RELEASE_LINK, const { result } = renderQueryHook(() => useLatestVersion());
latestVersionPayload
);
const { result } = renderQueryHook(() => hooks.useLatestVersion());
await expectQueryWorks(mock, result); await expectQueryWorks(mock, result);
}); });
}); });

View file

@ -1,19 +0,0 @@
import { useQuery } from '@tanstack/react-query';
import { BASE_PARAMS, QUERY_REFETCH_OFF_OPTIONS } from 'lib/constants';
const fetchActuatorInfo = async () => {
const data = await fetch(
`${BASE_PARAMS.basePath}/actuator/info`,
BASE_PARAMS
).then((res) => res.json());
return data;
};
export function useActuatorInfo() {
return useQuery(
['actuatorInfo'],
fetchActuatorInfo,
QUERY_REFETCH_OFF_OPTIONS
);
}

View file

@ -1,21 +1,19 @@
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { import { BASE_PARAMS, QUERY_REFETCH_OFF_OPTIONS } from 'lib/constants';
QUERY_REFETCH_OFF_OPTIONS,
GIT_REPO_LATEST_RELEASE_LINK,
} from 'lib/constants';
const fetchLatestVersion = async () => { const fetchLatestVersionInfo = async () => {
const data = await fetch(GIT_REPO_LATEST_RELEASE_LINK).then((res) => const data = await fetch(
res.json() `${BASE_PARAMS.basePath}/api/info`,
); BASE_PARAMS
).then((res) => res.json());
return data; return data;
}; };
export function useLatestVersion() { export function useLatestVersion() {
return useQuery( return useQuery(
['latestVersion'], ['versionInfo'],
fetchLatestVersion, fetchLatestVersionInfo,
QUERY_REFETCH_OFF_OPTIONS QUERY_REFETCH_OFF_OPTIONS
); );
} }