From 33dcc936bbe9a80807a087e38aa81192f5276f74 Mon Sep 17 00:00:00 2001 From: Raul Kele Date: Tue, 1 Nov 2022 14:40:33 +0200 Subject: [PATCH] refactor: Applied backend model mapping Signed-off-by: Raul Kele --- .eslintignore | 10 +++ .prettierignore | 4 +- src/App.js | 2 +- src/__tests__/Explore/Explore.test.js | 7 -- src/__tests__/HomePage/Home.test.js | 5 -- src/__tests__/LoginPage/SignIn.test.js | 4 - src/__tests__/RepoPage/Repo.test.js | 9 -- src/__tests__/RepoPage/RepoPage.test.js | 1 - src/__tests__/RepoPage/Tags.test.js | 1 - src/__tests__/Shared/PreviewCard.test.js | 1 - src/__tests__/Shared/RepoCard.test.js | 1 - src/__tests__/Shared/SearchSuggestion.test.js | 6 -- src/__tests__/TagPage/DependsOn.test.js | 4 - src/__tests__/TagPage/HistoryLayers.test.js | 4 - src/__tests__/TagPage/IsDependentOn.test.js | 4 - src/__tests__/TagPage/TagDetails.test.js | 16 ++-- .../TagPage/VulnerabilitiesDetails.test.js | 8 +- src/api.js | 1 - src/components/DependsOn.jsx | 23 ++--- src/components/IsDependentOn.jsx | 23 ++--- src/components/RepoDetails.jsx | 61 ++----------- src/components/RepoDetailsMetadata.jsx | 2 +- src/components/TagCard.jsx | 2 +- src/components/TagDetails.jsx | 87 +++++-------------- src/components/VulnerabilitiesDetails.jsx | 24 ++--- src/utilities/objectModels.js | 52 ++++++++++- src/utilities/transform.js | 2 +- 27 files changed, 135 insertions(+), 229 deletions(-) create mode 100644 .eslintignore diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..3e72aee1 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,10 @@ +**/.git +**/.svn +**/.hg +**/node_modules +**/.github +README.md +LICENSE +Makefile +**/coverage +**/build \ No newline at end of file diff --git a/.prettierignore b/.prettierignore index 412f1c94..3e72aee1 100644 --- a/.prettierignore +++ b/.prettierignore @@ -5,4 +5,6 @@ **/.github README.md LICENSE -Makefile \ No newline at end of file +Makefile +**/coverage +**/build \ No newline at end of file diff --git a/src/App.js b/src/App.js index 7713045d..a5a89d48 100644 --- a/src/App.js +++ b/src/App.js @@ -28,7 +28,7 @@ function App() { } /> } /> } /> - } /> + } /> }> ({ - // @ts-ignore ...jest.requireActual('react-router-dom'), useNavigate: () => mockedUsedNavigate })); @@ -136,7 +135,6 @@ afterEach(() => { describe('Explore component', () => { it("fetches image data and renders the list of images based on it's filters", async () => { - // @ts-ignore jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImageList } }); render(); expect(await screen.findByText(/alpine/i)).toBeInTheDocument(); @@ -145,14 +143,12 @@ describe('Explore component', () => { }); it('displays the no data message if no data is received', async () => { - // @ts-ignore jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: { GlobalSearch: { Repos: [] } } } }); render(); expect(await screen.findByText(/Looks like/i)).toBeInTheDocument(); }); it('renders signature icons', async () => { - // @ts-ignore jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImageList } }); render(); expect(await screen.findAllByTestId('unverified-icon')).toHaveLength(1); @@ -160,7 +156,6 @@ describe('Explore component', () => { }); it('renders vulnerability icons', async () => { - // @ts-ignore jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImageList } }); render(); expect(await screen.findAllByTestId('low-vulnerability-icon')).toHaveLength(1); @@ -172,7 +167,6 @@ describe('Explore component', () => { }); it("should log an error when data can't be fetched", async () => { - // @ts-ignore jest.spyOn(api, 'get').mockRejectedValue({ status: 500, data: {} }); const error = jest.spyOn(console, 'error').mockImplementation(() => {}); render(); @@ -180,7 +174,6 @@ describe('Explore component', () => { }); it("should render the sort filter and be able to change it's value", async () => { - // @ts-ignore jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImageList } }); render(); const selectFilter = await screen.findByText('Relevance'); diff --git a/src/__tests__/HomePage/Home.test.js b/src/__tests__/HomePage/Home.test.js index 45be1b6b..bd62658f 100644 --- a/src/__tests__/HomePage/Home.test.js +++ b/src/__tests__/HomePage/Home.test.js @@ -6,7 +6,6 @@ import React from 'react'; // useNavigate mock const mockedUsedNavigate = jest.fn(); jest.mock('react-router-dom', () => ({ - // @ts-ignore ...jest.requireActual('react-router-dom'), useNavigate: () => mockedUsedNavigate })); @@ -129,7 +128,6 @@ afterEach(() => { describe('Home component', () => { it('fetches image data and renders popular, bookmarks and recently updated', async () => { - // @ts-ignore jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImageList } }); render(); await waitFor(() => expect(screen.getAllByText(/alpine/i)).toHaveLength(2)); @@ -138,7 +136,6 @@ describe('Home component', () => { }); it('renders signature icons', async () => { - // @ts-ignore jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImageList } }); render(); expect(await screen.findAllByTestId('unverified-icon')).toHaveLength(2); @@ -146,7 +143,6 @@ describe('Home component', () => { }); it('renders vulnerability icons', async () => { - // @ts-ignore jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImageList } }); render(); expect(await screen.findAllByTestId('low-vulnerability-icon')).toHaveLength(2); @@ -156,7 +152,6 @@ describe('Home component', () => { }); it("should log an error when data can't be fetched", async () => { - // @ts-ignore jest.spyOn(api, 'get').mockRejectedValue({ status: 500, data: {} }); const error = jest.spyOn(console, 'error').mockImplementation(() => {}); render(); diff --git a/src/__tests__/LoginPage/SignIn.test.js b/src/__tests__/LoginPage/SignIn.test.js index 1bc798be..07f21248 100644 --- a/src/__tests__/LoginPage/SignIn.test.js +++ b/src/__tests__/LoginPage/SignIn.test.js @@ -7,7 +7,6 @@ import userEvent from '@testing-library/user-event'; // useNavigate mock const mockedUsedNavigate = jest.fn(); jest.mock('react-router-dom', () => ({ - // @ts-ignore ...jest.requireActual('react-router-dom'), useNavigate: () => mockedUsedNavigate })); @@ -25,7 +24,6 @@ describe('Signin component automatic navigation', () => { it('navigates to homepage when auth is disabled', async () => { // mock request to check auth - // @ts-ignore jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: {} }); render( {}} isLoggedIn={false} setIsLoggedIn={() => {}} />); await waitFor(() => { @@ -37,7 +35,6 @@ describe('Signin component automatic navigation', () => { describe('Sign in form', () => { beforeEach(() => { // mock auth check request - // @ts-ignore jest.spyOn(api, 'get').mockRejectedValue({ status: 401, data: {} }); }); @@ -70,7 +67,6 @@ describe('Sign in form', () => { it('should log in the user and navigate to homepage if login is successful', async () => { render( {}} isLoggedIn={false} setIsLoggedIn={() => {}} />); const submitButton = await screen.findByText('Continue'); - // @ts-ignore jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: {} } }); fireEvent.click(submitButton); await waitFor(() => { diff --git a/src/__tests__/RepoPage/Repo.test.js b/src/__tests__/RepoPage/Repo.test.js index 30aef566..bee877da 100644 --- a/src/__tests__/RepoPage/Repo.test.js +++ b/src/__tests__/RepoPage/Repo.test.js @@ -12,7 +12,6 @@ const mockUseLocationValue = { }; jest.mock('react-router-dom', () => ({ - // @ts-ignore ...jest.requireActual('react-router-dom'), useParams: () => { return { name: 'test' }; @@ -161,34 +160,27 @@ afterEach(() => { describe('Repo details component', () => { it('fetches repo detailed data and renders', async () => { - // @ts-ignore jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockRepoDetailsData } }); render(); expect(await screen.findByText('test')).toBeInTheDocument(); }); it('renders vulnerability icons', async () => { - // @ts-ignore jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockRepoDetailsData } }); render(); expect(await screen.findAllByTestId('critical-vulnerability-icon')).toHaveLength(1); - // @ts-ignore jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockRepoDetailsNone } }); render(); expect(await screen.findAllByTestId('none-vulnerability-icon')).toHaveLength(1); - // @ts-ignore // jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockRepoDetailsUnknown } }); // render(); // expect(await screen.findAllByTestId('unknown-vulnerability-icon')).toHaveLength(1); - // @ts-ignore jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockRepoDetailsLow } }); render(); expect(await screen.findAllByTestId('low-vulnerability-icon')).toHaveLength(1); - // @ts-ignore jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockRepoDetailsMedium } }); render(); expect(await screen.findAllByTestId('medium-vulnerability-icon')).toHaveLength(1); - // @ts-ignore jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockRepoDetailsHigh } }); render(); expect(await screen.findAllByTestId('high-vulnerability-icon')).toHaveLength(1); @@ -202,7 +194,6 @@ describe('Repo details component', () => { }); it('should switch between tabs', async () => { - // @ts-ignore jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockRepoDetailsData } }); render(); expect(await screen.findByTestId('overview-container')).toBeInTheDocument(); diff --git a/src/__tests__/RepoPage/RepoPage.test.js b/src/__tests__/RepoPage/RepoPage.test.js index ffe58bfa..92bf0285 100644 --- a/src/__tests__/RepoPage/RepoPage.test.js +++ b/src/__tests__/RepoPage/RepoPage.test.js @@ -4,7 +4,6 @@ import React from 'react'; import { BrowserRouter, Route, Routes } from 'react-router-dom'; jest.mock('react-router-dom', () => ({ - // @ts-ignore ...jest.requireActual('react-router-dom'), useLocation: () => ({ pathname: 'localhost:3000/image/test', diff --git a/src/__tests__/RepoPage/Tags.test.js b/src/__tests__/RepoPage/Tags.test.js index 6bdf3eb5..67e10ad6 100644 --- a/src/__tests__/RepoPage/Tags.test.js +++ b/src/__tests__/RepoPage/Tags.test.js @@ -4,7 +4,6 @@ import React from 'react'; const mockedUsedNavigate = jest.fn(); jest.mock('react-router-dom', () => ({ - // @ts-ignore ...jest.requireActual('react-router-dom'), useNavigate: () => mockedUsedNavigate })); diff --git a/src/__tests__/Shared/PreviewCard.test.js b/src/__tests__/Shared/PreviewCard.test.js index 1e56cfbf..e846806b 100644 --- a/src/__tests__/Shared/PreviewCard.test.js +++ b/src/__tests__/Shared/PreviewCard.test.js @@ -6,7 +6,6 @@ import PreviewCard from 'components/PreviewCard'; // usenavigate mock const mockedUsedNavigate = jest.fn(); jest.mock('react-router-dom', () => ({ - // @ts-ignore ...jest.requireActual('react-router-dom'), useNavigate: () => mockedUsedNavigate })); diff --git a/src/__tests__/Shared/RepoCard.test.js b/src/__tests__/Shared/RepoCard.test.js index 9620c9e2..b615a45f 100644 --- a/src/__tests__/Shared/RepoCard.test.js +++ b/src/__tests__/Shared/RepoCard.test.js @@ -6,7 +6,6 @@ import RepoCard from 'components/RepoCard'; // usenavigate mock const mockedUsedNavigate = jest.fn(); jest.mock('react-router-dom', () => ({ - // @ts-ignore ...jest.requireActual('react-router-dom'), useNavigate: () => mockedUsedNavigate })); diff --git a/src/__tests__/Shared/SearchSuggestion.test.js b/src/__tests__/Shared/SearchSuggestion.test.js index ccfbb87b..7b5d828e 100644 --- a/src/__tests__/Shared/SearchSuggestion.test.js +++ b/src/__tests__/Shared/SearchSuggestion.test.js @@ -7,7 +7,6 @@ import React from 'react'; // router mock const mockedUsedNavigate = jest.fn(); jest.mock('react-router-dom', () => ({ - // @ts-ignore ...jest.requireActual('react-router-dom'), useNavigate: () => mockedUsedNavigate })); @@ -71,7 +70,6 @@ afterEach(() => { describe('Search component', () => { it('should display suggestions when user searches', async () => { - // @ts-ignore jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImageList } }); render(); const searchInput = screen.getByPlaceholderText(/search for content/i); @@ -81,7 +79,6 @@ describe('Search component', () => { }); it('should navigate to repo page when a repo suggestion is clicked', async () => { - // @ts-ignore jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImageList } }); render(); const searchInput = screen.getByPlaceholderText(/search for content/i); @@ -92,7 +89,6 @@ describe('Search component', () => { }); it('should navigate to repo page when a image suggestion is clicked', async () => { - // @ts-ignore jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImageList } }); render(); const searchInput = screen.getByPlaceholderText(/search for content/i); @@ -103,7 +99,6 @@ describe('Search component', () => { }); it('should log an error if it doesnt receive an ok response for repo search', async () => { - // @ts-ignore jest.spyOn(api, 'get').mockRejectedValue({ status: 500, data: {} }); const error = jest.spyOn(console, 'error').mockImplementation(() => {}); render(); @@ -113,7 +108,6 @@ describe('Search component', () => { }); it('should log an error if it doesnt receive an ok response for image search', async () => { - // @ts-ignore jest.spyOn(api, 'get').mockRejectedValue({ status: 500, data: {} }); const error = jest.spyOn(console, 'error').mockImplementation(() => {}); render(); diff --git a/src/__tests__/TagPage/DependsOn.test.js b/src/__tests__/TagPage/DependsOn.test.js index a2e3db87..42ddc64a 100644 --- a/src/__tests__/TagPage/DependsOn.test.js +++ b/src/__tests__/TagPage/DependsOn.test.js @@ -56,7 +56,6 @@ const RouterDependsWrapper = () => { // useNavigate mock const mockedUsedNavigate = jest.fn(); jest.mock('react-router-dom', () => ({ - // @ts-ignore ...jest.requireActual('react-router-dom'), useNavigate: () => mockedUsedNavigate })); @@ -68,14 +67,12 @@ afterEach(() => { describe('Dependencies tab', () => { it('should render the dependencies if there are any', async () => { - // @ts-ignore jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: mockDependenciesList }); render(); expect(await screen.findAllByText(/Tag/i)).toHaveLength(8); }); it('renders no dependencies if there are not any', async () => { - // @ts-ignore jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: { BaseImageList: [] } } @@ -85,7 +82,6 @@ describe('Dependencies tab', () => { }); it("should log an error when data can't be fetched", async () => { - // @ts-ignore jest.spyOn(api, 'get').mockRejectedValue({ status: 500, data: {} }); const error = jest.spyOn(console, 'error').mockImplementation(() => {}); render(); diff --git a/src/__tests__/TagPage/HistoryLayers.test.js b/src/__tests__/TagPage/HistoryLayers.test.js index 1ffdde91..11aed5df 100644 --- a/src/__tests__/TagPage/HistoryLayers.test.js +++ b/src/__tests__/TagPage/HistoryLayers.test.js @@ -33,14 +33,12 @@ afterEach(() => { describe('Layers page', () => { it('renders the layers if there are any', async () => { - // @ts-ignore jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: { Image: { History: mockLayersList } } } }); render(); expect(await screen.findAllByTestId('layer-card-container')).toHaveLength(2); }); it('renders no layers if there are not any', async () => { - // @ts-ignore jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: { History: { Tag: '', mockLayersList: [] } } } @@ -50,7 +48,6 @@ describe('Layers page', () => { }); it('renders hash layers', async () => { - // @ts-ignore jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: { Image: { History: mockLayersList } } } }); render(); expect(await screen.findAllByTestId('hash-typography')).toHaveLength(1); @@ -60,7 +57,6 @@ describe('Layers page', () => { }); it("should log an error when data can't be fetched", async () => { - // @ts-ignore jest.spyOn(api, 'get').mockRejectedValue({ status: 500, data: {} }); const error = jest.spyOn(console, 'error').mockImplementation(() => {}); render(); diff --git a/src/__tests__/TagPage/IsDependentOn.test.js b/src/__tests__/TagPage/IsDependentOn.test.js index 489f8be0..3cc19fbb 100644 --- a/src/__tests__/TagPage/IsDependentOn.test.js +++ b/src/__tests__/TagPage/IsDependentOn.test.js @@ -56,7 +56,6 @@ const RouterDependsWrapper = () => { // useNavigate mock const mockedUsedNavigate = jest.fn(); jest.mock('react-router-dom', () => ({ - // @ts-ignore ...jest.requireActual('react-router-dom'), useNavigate: () => mockedUsedNavigate })); @@ -68,14 +67,12 @@ afterEach(() => { describe('Dependents tab', () => { it('should render the dependents if there are any', async () => { - // @ts-ignore jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: mockDependentsList }); render(); expect(await screen.findAllByText(/tag/i)).toHaveLength(8); }); it('renders no dependents if there are not any', async () => { - // @ts-ignore jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: { DerivedImageList: [] } } @@ -85,7 +82,6 @@ describe('Dependents tab', () => { }); it("should log an error when data can't be fetched", async () => { - // @ts-ignore jest.spyOn(api, 'get').mockRejectedValue({ status: 500, data: {} }); const error = jest.spyOn(console, 'error').mockImplementation(() => {}); render(); diff --git a/src/__tests__/TagPage/TagDetails.test.js b/src/__tests__/TagPage/TagDetails.test.js index 8feb17c7..5c739764 100644 --- a/src/__tests__/TagPage/TagDetails.test.js +++ b/src/__tests__/TagPage/TagDetails.test.js @@ -170,7 +170,6 @@ Object.assign(navigator, { }); jest.mock('react-router-dom', () => ({ - // @ts-ignore ...jest.requireActual('react-router-dom'), useParams: () => { return { name: 'test', tag: '1.0.1' }; @@ -193,7 +192,6 @@ afterEach(() => { describe('Tags details', () => { it('should show tabs and allow nagivation between them', async () => { - // @ts-ignore jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImage } }); render(); const dependenciesTab = await screen.findByTestId('dependencies-tab'); @@ -210,34 +208,32 @@ describe('Tags details', () => { }); it('should show tag details metadata', async () => { - // @ts-ignore jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImage } }); render(); expect(await screen.findByTestId('tagDetailsMetadata-container')).toBeInTheDocument(); }); it('renders vulnerability icons', async () => { - // @ts-ignore jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImage } }); render(); expect(await screen.findByTestId('critical-vulnerability-icon')).toBeInTheDocument(); - // @ts-ignore + jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImageNone } }); render(); expect(await screen.findByTestId('none-vulnerability-icon')).toBeInTheDocument(); - // @ts-ignore + jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImageUnknown } }); render(); expect(await screen.findByTestId('unknown-vulnerability-icon')).toBeInTheDocument(); - // @ts-ignore + jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImageLow } }); render(); expect(await screen.findByTestId('low-vulnerability-icon')).toBeInTheDocument(); - // @ts-ignore + jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImageMedium } }); render(); expect(await screen.findByTestId('medium-vulnerability-icon')).toBeInTheDocument(); - // @ts-ignore + jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImageHigh } }); render(); expect(await screen.findByTestId('high-vulnerability-icon')).toBeInTheDocument(); @@ -246,7 +242,7 @@ describe('Tags details', () => { it('should copy the pull string to clipboard', async () => { jest .spyOn(api, 'get') - // @ts-ignore + .mockResolvedValue({ status: 200, data: { data: mockImage } }); render(); fireEvent.click(await screen.findByTestId('pullcopy-btn')); diff --git a/src/__tests__/TagPage/VulnerabilitiesDetails.test.js b/src/__tests__/TagPage/VulnerabilitiesDetails.test.js index 46c30353..32d177e4 100644 --- a/src/__tests__/TagPage/VulnerabilitiesDetails.test.js +++ b/src/__tests__/TagPage/VulnerabilitiesDetails.test.js @@ -452,7 +452,6 @@ afterEach(() => { describe('Vulnerabilties page', () => { it('renders the vulnerabilities if there are any', async () => { - // @ts-ignore jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockCVEList } }); render(); await waitFor(() => expect(screen.getAllByText('Vulnerabilities')).toHaveLength(1)); @@ -460,7 +459,6 @@ describe('Vulnerabilties page', () => { }); it('renders no vulnerabilities if there are not any', async () => { - // @ts-ignore jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: { CVEListForImage: { Tag: '', CVEList: [] } } } @@ -470,7 +468,6 @@ describe('Vulnerabilties page', () => { }); it('should open and close description dropdown for vulnerabilities', async () => { - // @ts-ignore jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockCVEList } }); render(); await waitFor(() => expect(screen.getAllByText(/description/i)).toHaveLength(20)); @@ -486,7 +483,6 @@ describe('Vulnerabilties page', () => { }); it("should log an error when data can't be fetched", async () => { - // @ts-ignore jest.spyOn(api, 'get').mockRejectedValue({ status: 500, data: {} }); const error = jest.spyOn(console, 'error').mockImplementation(() => {}); render(); @@ -496,9 +492,9 @@ describe('Vulnerabilties page', () => { it('should find out which version fixes the CVEs', async () => { jest .spyOn(api, 'get') - // @ts-ignore + .mockResolvedValueOnce({ status: 200, data: { data: mockCVEList } }) - // @ts-ignore + .mockResolvedValue({ status: 200, data: { data: mockCVEFixed } }); render(); await waitFor(() => expect(screen.getAllByText('Vulnerabilities')).toHaveLength(1)); diff --git a/src/api.js b/src/api.js index a8255aff..dfbd2acc 100644 --- a/src/api.js +++ b/src/api.js @@ -1,4 +1,3 @@ -// @ts-nocheck import axios from 'axios'; import { isEmpty } from 'lodash'; import { sortByCriteria } from 'utilities/sortCriteria'; diff --git a/src/components/DependsOn.jsx b/src/components/DependsOn.jsx index fcc630f7..7782a8e0 100644 --- a/src/components/DependsOn.jsx +++ b/src/components/DependsOn.jsx @@ -1,4 +1,5 @@ import React, { useEffect, useState, useMemo } from 'react'; +import { isEmpty } from 'lodash'; // utility import { api, endpoints } from '../api'; @@ -9,6 +10,7 @@ import makeStyles from '@mui/styles/makeStyles'; import { host } from '../host'; import Loading from './Loading'; import TagCard from './TagCard'; +import { mapToImage } from 'utilities/objectModels'; const useStyles = makeStyles(() => ({ card: { @@ -78,7 +80,7 @@ function DependsOn(props) { .get(`${host()}${endpoints.dependsOnForImage(name)}`, abortController.signal) .then((response) => { if (response.data && response.data.data) { - let imagesData = response.data.data.BaseImageList; + let imagesData = response.data.data.BaseImageList?.map((img) => mapToImage(img)); setImages(imagesData); } setIsLoading(false); @@ -93,20 +95,19 @@ function DependsOn(props) { }, []); const renderDependencies = () => { - return images?.length ? ( + return !isEmpty(images) ? ( images.map((dependence, index) => { return ( ); }) diff --git a/src/components/IsDependentOn.jsx b/src/components/IsDependentOn.jsx index b559feb8..affffb6e 100644 --- a/src/components/IsDependentOn.jsx +++ b/src/components/IsDependentOn.jsx @@ -1,4 +1,5 @@ import React, { useEffect, useMemo, useState } from 'react'; +import { isEmpty } from 'lodash'; // utility import { api, endpoints } from '../api'; @@ -9,6 +10,7 @@ import makeStyles from '@mui/styles/makeStyles'; import { host } from '../host'; import Loading from './Loading'; import TagCard from './TagCard'; +import { mapToImage } from 'utilities/objectModels'; const useStyles = makeStyles(() => ({ card: { @@ -78,7 +80,7 @@ function IsDependentOn(props) { .get(`${host()}${endpoints.isDependentOnForImage(name)}`, abortController.signal) .then((response) => { if (response.data && response.data.data) { - let imageData = response.data.data.DerivedImageList; + let imageData = response.data.data.DerivedImageList?.map((img) => mapToImage(img)); setImages(imageData); } setIsLoading(false); @@ -93,20 +95,19 @@ function IsDependentOn(props) { }, []); const renderDependents = () => { - return images?.length ? ( + return !isEmpty(images) ? ( images.map((dependence, index) => { return ( ); }) diff --git a/src/components/RepoDetails.jsx b/src/components/RepoDetails.jsx index 1380022e..c4cbcd58 100644 --- a/src/components/RepoDetails.jsx +++ b/src/components/RepoDetails.jsx @@ -22,8 +22,8 @@ import RepoDetailsMetadata from './RepoDetailsMetadata'; import Loading from './Loading'; import { isEmpty } from 'lodash'; import { VulnerabilityIconCheck, SignatureIconCheck } from 'utilities/vulnerabilityAndSignatureCheck'; +import { mapToRepoFromRepoInfo } from 'utilities/objectModels'; -// @ts-ignore const useStyles = makeStyles(() => ({ pageWrapper: { backgroundColor: '#FFFFFF', @@ -123,7 +123,7 @@ const randomImage = () => { function RepoDetails() { const [repoDetailData, setRepoDetailData] = useState({}); const [tags, setTags] = useState([]); - // @ts-ignore + const [isLoading, setIsLoading] = useState(true); const [selectedTab, setSelectedTab] = useState('Overview'); // get url param from { if (response.data && response.data.data) { let repoInfo = response.data.data.ExpandedRepoInfo; - let imageData = { - name: name, - images: repoInfo.Images, - lastUpdated: repoInfo.Summary?.LastUpdated, - size: repoInfo.Summary?.Size, - platforms: repoInfo.Summary?.Platforms, - vendors: repoInfo.Summary?.Vendors, - newestTag: repoInfo.Summary?.NewestImage, - description: repoInfo.Summary?.NewestImage?.Description, - title: repoInfo.Summary?.NewestImage?.Title, - source: repoInfo.Summary?.NewestImage?.Source, - downloads: repoInfo.Summary?.NewestImage?.DownloadCount, - overview: repoInfo.Summary?.NewestImage?.Documentation, - license: repoInfo.Summary?.NewestImage?.Licenses, - vulnerabiltySeverity: repoInfo.Summary?.NewestImage?.Vulnerabilities?.MaxSeverity, - vulnerabilityCount: repoInfo.Summary?.NewestImage?.Vulnerabilities?.Count, - isSigned: repoInfo.Summary?.NewestImage?.IsSigned, - logo: repoInfo.Summary?.NewestImage?.Logo - }; + let imageData = mapToRepoFromRepoInfo(repoInfo); setRepoDetailData(imageData); setTags(imageData.images); } @@ -173,7 +155,6 @@ function RepoDetails() { }, [name]); const platformChips = () => { - // @ts-ignore const platforms = repoDetailData?.platforms || []; return platforms.map((platform, index) => ( @@ -200,8 +181,6 @@ function RepoDetails() { )); }; - // @ts-ignore - // @ts-ignore const handleTabChange = (event, newValue) => { setSelectedTab(newValue); }; @@ -220,10 +199,7 @@ function RepoDetails() { alignSelf: 'stretch' }} > - { - // @ts-ignore - repoDetailData.description || 'Description not available' - } + {repoDetailData.description || 'Description not available'} @@ -247,13 +223,10 @@ function RepoDetails() { img: classes.avatar }} component="img" - // @ts-ignore // eslint-disable-next-line prettier/prettier image={ - // @ts-ignore !isEmpty(repoDetailData?.logo) - ? // @ts-ignore - `data:image/png;base64, ${repoDetailData?.logo}` + ? `data:image/png;base64, ${repoDetailData?.logo}` : randomImage() } alt="icon" @@ -262,19 +235,10 @@ function RepoDetails() { {name} - + {/* */} - { - // @ts-ignore - repoDetailData?.title || 'Title not available' - } + {repoDetailData?.title || 'Title not available'} {platformChips()} @@ -320,17 +281,11 @@ function RepoDetails() { diff --git a/src/components/RepoDetailsMetadata.jsx b/src/components/RepoDetailsMetadata.jsx index e34b2214..72dbe8dc 100644 --- a/src/components/RepoDetailsMetadata.jsx +++ b/src/components/RepoDetailsMetadata.jsx @@ -37,7 +37,7 @@ const useStyles = makeStyles(() => ({ function RepoDetailsMetadata(props) { const classes = useStyles(); const { repoURL, totalDownloads, lastUpdated, size, license } = props; - // @ts-ignore + const lastDate = (lastUpdated ? DateTime.fromISO(lastUpdated) : DateTime.now().minus({ days: 1 })).toRelative({ unit: ['weeks', 'days', 'hours', 'minutes'] }); diff --git a/src/components/TagCard.jsx b/src/components/TagCard.jsx index f9caf105..c2250671 100644 --- a/src/components/TagCard.jsx +++ b/src/components/TagCard.jsx @@ -65,7 +65,7 @@ export default function TagCard(props) { //const tags = data && data.tags; const [open, setOpen] = useState(false); const classes = useStyles(); - // @ts-ignore + const lastDate = (lastUpdated ? DateTime.fromISO(lastUpdated) : DateTime.now().minus({ days: 1 })).toRelative({ unit: ['weeks', 'days', 'hours', 'minutes'] }); diff --git a/src/components/TagDetails.jsx b/src/components/TagDetails.jsx index 979dfa2e..c2f974c7 100644 --- a/src/components/TagDetails.jsx +++ b/src/components/TagDetails.jsx @@ -3,7 +3,7 @@ import React, { useEffect, useMemo, useState } from 'react'; // utility import { api, endpoints } from '../api'; - +import { mapToImage } from '../utilities/objectModels'; // components import { Box, @@ -41,7 +41,6 @@ import Loading from './Loading'; import { dockerPull, podmanPull, skopeoPull } from 'utilities/pullStrings'; import { VulnerabilityIconCheck, SignatureIconCheck } from 'utilities/vulnerabilityAndSignatureCheck'; -// @ts-ignore const useStyles = makeStyles(() => ({ pageWrapper: { backgroundColor: '#FFFFFF', @@ -157,8 +156,7 @@ function TagDetails() { const abortController = useMemo(() => new AbortController(), []); // get url param from { if (response.data && response.data.data) { let imageInfo = response.data.data.Image; - let imageData = { - name: imageInfo.RepoName, - tag: imageInfo.Tag, - lastUpdated: imageInfo.LastUpdated, - size: imageInfo.Size, - digest: imageInfo.ConfigDigest, - platform: imageInfo.Platform, - vendor: imageInfo.Vendor, - history: imageInfo.History, - license: imageInfo.Licenses, - vulnerabiltySeverity: imageInfo.Vulnerabilities?.MaxSeverity, - vulnerabilityCount: imageInfo.Vulnerabilities?.Count, - isSigned: imageInfo.IsSigned, - logo: imageInfo.Logo - }; + let imageData = mapToImage(imageInfo); setImageDetailData(imageData); - setFullName(imageData.name + ':' + imageData.tag); - setPullString(dockerPull(imageData.name + ':' + imageData.tag)); + setPullString(dockerPull(imageData.name)); } setIsLoading(false); }) @@ -203,14 +186,12 @@ function TagDetails() { return () => { abortController.abort(); }; - }, [name, tag]); + }, [reponame, tag]); const getPlatform = () => { - // @ts-ignore return imageDetailData?.platform ? imageDetailData.platform : '--/--'; }; - // @ts-ignore const handleTabChange = (event, newValue) => { setSelectedTab(newValue); }; @@ -245,32 +226,20 @@ function TagDetails() { }} component="img" image={ - // @ts-ignore - // eslint-disable-next-line prettier/prettier !isEmpty(imageDetailData?.logo) - ? // @ts-ignore - `data:image/ png;base64, ${imageDetailData?.logo}` + ? `data:image/ png;base64, ${imageDetailData?.logo}` : randomImage() } alt="icon" /> - {name}:{tag} + {reponame}:{tag} - + {/* */} - DIGEST:{' '} - { - // @ts-ignore - imageDetailData?.digest - } + DIGEST: {imageDetailData?.digest} @@ -320,14 +285,14 @@ function TagDetails() { classes: { root: classes.copyStringSelect, list: classes.textEllipsis } }} > - - {dockerPull(fullName)} + + {dockerPull(imageDetailData.name)} - - {podmanPull(fullName)} + + {podmanPull(imageDetailData.name)} - - {skopeoPull(fullName)} + + {skopeoPull(imageDetailData.name)} @@ -355,22 +320,16 @@ function TagDetails() { - + - + - + - + @@ -379,13 +338,9 @@ function TagDetails() { diff --git a/src/components/VulnerabilitiesDetails.jsx b/src/components/VulnerabilitiesDetails.jsx index 30d82d7f..d4409d63 100644 --- a/src/components/VulnerabilitiesDetails.jsx +++ b/src/components/VulnerabilitiesDetails.jsx @@ -13,6 +13,7 @@ import { Link } from 'react-router-dom'; import Loading from './Loading'; import { KeyboardArrowDown, KeyboardArrowRight } from '@mui/icons-material'; import { VulnerabilityChipCheck } from 'utilities/vulnerabilityAndSignatureCheck'; +import { mapCVEInfo } from 'utilities/objectModels'; const useStyles = makeStyles(() => ({ card: { @@ -96,7 +97,7 @@ function VulnerabilitiyCard(props) { } setLoadingFixed(true); api - .get(`${host()}${endpoints.imageListWithCVEFixed(cve.Id, name)}`) + .get(`${host()}${endpoints.imageListWithCVEFixed(cve.id, name)}`) .then((response) => { if (response.data && response.data.data) { const fixedTagsList = response.data.data.ImageListWithCVEFixed?.map((e) => e.Tag); @@ -129,14 +130,14 @@ function VulnerabilitiyCard(props) { {' '} - {cve.Id} + {cve.id} - + {' '} - {cve.Title} + {cve.title} setOpenFixed(!openFixed)}> @@ -167,7 +168,7 @@ function VulnerabilitiyCard(props) { {' '} - {cve.Description}{' '} + {cve.description}{' '} @@ -190,9 +191,7 @@ function VulnerabilitiesDetails(props) { .then((response) => { if (response.data && response.data.data) { let cveInfo = response.data.data.CVEListForImage; - let cveListData = { - cveList: cveInfo?.CVEList - }; + let cveListData = mapCVEInfo(cveInfo); setCveData(cveListData); } setIsLoading(false); @@ -249,14 +248,7 @@ function VulnerabilitiesDetails(props) { width: '100%' }} /> - {isLoading ? ( - - ) : ( - renderCVEs( - // @ts-ignore - cveData?.cveList - ) - )} + {isLoading ? : renderCVEs(cveData?.cveList)} ); } diff --git a/src/utilities/objectModels.js b/src/utilities/objectModels.js index ea02340b..48c5cc73 100644 --- a/src/utilities/objectModels.js +++ b/src/utilities/objectModels.js @@ -17,14 +17,60 @@ const mapToRepo = (responseRepo) => { }; }; +const mapToRepoFromRepoInfo = (responseRepoInfo) => { + return { + name: responseRepoInfo.Summary?.Name, + images: responseRepoInfo.Images, + lastUpdated: responseRepoInfo.Summary?.LastUpdated, + size: responseRepoInfo.Summary?.Size, + platforms: responseRepoInfo.Summary?.Platforms, + vendors: responseRepoInfo.Summary?.Vendors, + newestTag: responseRepoInfo.Summary?.NewestImage, + description: responseRepoInfo.Summary?.NewestImage?.Description, + title: responseRepoInfo.Summary?.NewestImage?.Title, + source: responseRepoInfo.Summary?.NewestImage?.Source, + downloads: responseRepoInfo.Summary?.NewestImage?.DownloadCount, + overview: responseRepoInfo.Summary?.NewestImage?.Documentation, + license: responseRepoInfo.Summary?.NewestImage?.Licenses, + vulnerabiltySeverity: responseRepoInfo.Summary?.NewestImage?.Vulnerabilities?.MaxSeverity, + vulnerabilityCount: responseRepoInfo.Summary?.NewestImage?.Vulnerabilities?.Count, + isSigned: responseRepoInfo.Summary?.NewestImage?.IsSigned, + logo: responseRepoInfo.Summary?.NewestImage?.Logo + }; +}; + const mapToImage = (responseImage) => { return { repoName: responseImage.RepoName, tag: responseImage.Tag, + lastUpdated: responseImage.LastUpdated, + size: responseImage.Size, + digest: responseImage.ConfigDigest, + platform: responseImage.Platform, + vendor: responseImage.Vendor, + history: responseImage.History, + license: responseImage.Licenses, + vulnerabiltySeverity: responseImage.Vulnerabilities?.MaxSeverity, + vulnerabilityCount: responseImage.Vulnerabilities?.Count, + isSigned: responseImage.IsSigned, + logo: responseImage.Logo, // frontend only prop to increase interop with Repo objects and code reusability - name: `${responseImage.RepoName}:${responseImage.Tag}`, - logo: responseImage.Logo + name: `${responseImage.RepoName}:${responseImage.Tag}` }; }; -export { mapToRepo, mapToImage }; +const mapCVEInfo = (cveInfo) => { + const cveList = cveInfo.CVEList?.map((cve) => { + return { + id: cve.Id, + severity: cve.Severity, + title: cve.Title, + description: cve.Description + }; + }); + return { + cveList + }; +}; + +export { mapToRepo, mapToImage, mapToRepoFromRepoInfo, mapCVEInfo }; diff --git a/src/utilities/transform.js b/src/utilities/transform.js index 736bc210..9c3ccda6 100644 --- a/src/utilities/transform.js +++ b/src/utilities/transform.js @@ -15,7 +15,7 @@ const transform = { let value = bytes / Math.pow(k, unitIdx); // minimum 2 significant digits - // @ts-ignore + value = value < 10 ? value.toPrecision(2) : Math.round(value); return value + ' ' + DATA_UNITS[unitIdx];