From 14e6ed2858e8cef93ba4d8f669851faab2955f4a Mon Sep 17 00:00:00 2001 From: Martin Michalik <62351699+xmicha82@users.noreply.github.com> Date: Thu, 17 Oct 2024 11:24:02 +0200 Subject: [PATCH] fix(SystemCVEs): RHINENG-11464 inventory tab advisory filter (#2149) --- .../SmartComponents/SystemCves/SystemCves.js | 11 +++- src/Helpers/Hooks.js | 50 +++++++++++++++ src/Utilities/AccountStatContextWrapper.js | 35 +++++++++++ src/Utilities/VulnerabilityRoutes.js | 62 ++++--------------- src/index.js | 15 ++++- 5 files changed, 120 insertions(+), 53 deletions(-) create mode 100644 src/Utilities/AccountStatContextWrapper.js diff --git a/src/Components/SmartComponents/SystemCves/SystemCves.js b/src/Components/SmartComponents/SystemCves/SystemCves.js index 8f0fb4640..43f0a7a1f 100644 --- a/src/Components/SmartComponents/SystemCves/SystemCves.js +++ b/src/Components/SmartComponents/SystemCves/SystemCves.js @@ -95,7 +95,7 @@ export const SystemCVEs = ({ entity.id, systemCVEs, columns, linkToCustomerPortal ), [systemCVEs, systemCVEs.isLoading, entity.id, columns]); const [urlParameters, setUrlParams] = useUrlParams(CVES_ALLOWED_PARAMS); - const { includesCvesWithoutErrata } = useContext(AccountStatContext); + const { includesCvesWithoutErrata, isFederated } = useContext(AccountStatContext); const downloadReport = format => { const params = { ...parameters, system: entity.id }; @@ -128,10 +128,15 @@ export const SystemCVEs = ({ dispatch(changeSystemCVEsParameters(params)); }; + const paramsWithoutKeys = (params, keys) => Object.fromEntries(Object.entries(params).filter((p) => !keys.includes(p[0]))); + useEffect(() => { apply( - isEmpty(urlParameters) ? - { advisory_available: 'true' } + isEmpty(paramsWithoutKeys(urlParameters, ['appName'])) ? + { + advisory_available: 'true', + ...isFederated ? { appName: 'vulnerabilities' } : {} + } : urlParameters ); diff --git a/src/Helpers/Hooks.js b/src/Helpers/Hooks.js index 5e6d6f439..9b837482b 100644 --- a/src/Helpers/Hooks.js +++ b/src/Helpers/Hooks.js @@ -14,6 +14,7 @@ import ColumnManagementModal from '../Components/SmartComponents/Modals/ColumnMa import useChrome from '@redhat-cloud-services/frontend-components/useChrome'; import { useFlag, useFlagsStatus } from '@unleash/proxy-client-react'; import { AccountStatContext } from '../Utilities/VulnerabilityRoutes'; +import { getRhelSystems, checkEdgePresence, getCveListByAccount } from './APIHelper'; export const useNotification = (config = {}) => { const dispatch = useDispatch(); @@ -279,3 +280,52 @@ export const useHybridSystemFilterFlag = () => { const shouldUseHybridSystemFilter = isEdgeParityEnabled && hasEdgeDevices; return shouldUseHybridSystemFilter; }; + +export const useAccountStats = (isEdgeParityEnabled, setLoading, addNotification) => { + const [hasEdgeDevices, setHasEdgeDevices] = useState(true); + const [hasConventionalSystems, setHasConventionalSystems] = useState(true); + const [includesCvesWithoutErrata, setIncludesCvesWithoutErrata] = useState(); + const [isAdvisoryAvailable, setAdvisoryAvailable] = useState(); + const [hasAccess, setHasAccess] = useState(true); + + useEffect(() => { + const fetchData = async () => { + try { + const rhelSystems = await getRhelSystems(); + if (isEdgeParityEnabled) { + //if there is at least 1 edge device in the account level, not only in vulnerability + const edgeDevicePresent = await checkEdgePresence(); + setHasEdgeDevices(edgeDevicePresent); + } + + const { meta: { + cves_without_errata: cvesWithoutErrata, advisory_available: advisoryAvailable + } = {} + } = await getCveListByAccount({ limit: 1 }); + + setHasConventionalSystems(rhelSystems); + setIncludesCvesWithoutErrata(cvesWithoutErrata); + setAdvisoryAvailable(advisoryAvailable); + setLoading(false); + } catch (error) { + if (error.status === '403') { + setHasAccess(false); + } + else { + addNotification({ + variant: 'danger', + autoDismiss: false, + msg: 'Failed to fetch systems', + description: error.detail + }); + } + + setLoading(false); + } + }; + + fetchData(); + }, []); + + return { hasEdgeDevices, hasConventionalSystems, includesCvesWithoutErrata, isAdvisoryAvailable, hasAccess }; +}; diff --git a/src/Utilities/AccountStatContextWrapper.js b/src/Utilities/AccountStatContextWrapper.js new file mode 100644 index 000000000..529750e7f --- /dev/null +++ b/src/Utilities/AccountStatContextWrapper.js @@ -0,0 +1,35 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import useFeatureFlag from './useFeatureFlag'; +import { useAccountStats, useNotification } from '../Helpers/Hooks'; +import { AccountStatContext } from './VulnerabilityRoutes'; + +export const AccountStatContextWrapper = ({ children, setLoading, isFederated = false }) => { + const isEdgeParityEnabled = useFeatureFlag('vulnerability.edge_parity'); + const [addNotification] = useNotification(); + + const { + hasConventionalSystems, + hasEdgeDevices, + includesCvesWithoutErrata, + isAdvisoryAvailable + } = useAccountStats(isEdgeParityEnabled, setLoading, addNotification); + + return ( + + { children } + + ); +}; + +AccountStatContextWrapper.propTypes = { + children: PropTypes.func, + setLoading: PropTypes.func, + isFederated: PropTypes.bool +}; diff --git a/src/Utilities/VulnerabilityRoutes.js b/src/Utilities/VulnerabilityRoutes.js index e7fd7c8d1..87bda2d3a 100644 --- a/src/Utilities/VulnerabilityRoutes.js +++ b/src/Utilities/VulnerabilityRoutes.js @@ -1,7 +1,6 @@ import React, { useEffect, useState, lazy, Suspense, createContext } from 'react'; import PropTypes from 'prop-types'; import { Navigate, Route, Routes, useLocation } from 'react-router-dom'; -import { checkEdgePresence, getRhelSystems, getCveListByAccount } from '../Helpers/APIHelper'; import { PATHS } from '../Helpers/constants'; import { intl } from './IntlProvider'; import messages from '../Messages'; @@ -10,7 +9,7 @@ import ErrorState from '@redhat-cloud-services/frontend-components/ErrorState'; import { useChrome } from '@redhat-cloud-services/frontend-components/useChrome'; import useFeatureFlag from './useFeatureFlag'; import { NotAuthorized } from '@redhat-cloud-services/frontend-components/NotAuthorized'; -import { useNotification } from '../Helpers/Hooks'; +import { useAccountStats, useNotification } from '../Helpers/Hooks'; import PageLoading from '../Components/PresentationalComponents/Snippets/PageLoading'; const SystemsPage = lazy(() => @@ -54,57 +53,20 @@ export const checkForAccountSystems = (isEdgeParityEnabled, hasEdgeDevices, hasC return isEdgeParityEnabled && (hasEdgeDevices || hasConventionalSystems) || hasConventionalSystems; }; -export const InsightsElement = ({ element: Element, title, globalFilterEnabled, ...elementProps }) => { +export const InsightsElement = ({ element: Element, title, globalFilterEnabled, ...elementProps }) => { let location = useLocation(); const [isLoading, setLoading] = useState(true); - const [hasConventionalSystems, setHasConventionalSystems] = useState(true); - const [hasEdgeDevices, setHasEdgeDevices] = useState(true); - const [hasAccess, setHasAccess] = useState(true); - const [includesCvesWithoutErrata, setIncludesCvesWithoutErrata] = useState(); - const [isAdvisoryAvailable, setAdvisoryAvailable] = useState(); - const [addNotification] = useNotification(); const isEdgeParityEnabled = useFeatureFlag('vulnerability.edge_parity'); + const [addNotification] = useNotification(); const chrome = useChrome(); - useEffect(() => { - const fetchData = async () => { - try { - const rhelSystems = await getRhelSystems(); - if (isEdgeParityEnabled) { - //if there is at least 1 edge device in the account level, not only in vulnerability - const edgeDevicePresent = await checkEdgePresence(); - setHasEdgeDevices(edgeDevicePresent); - } - - const { meta: - { - cves_without_errata: cvesWithoutErrata, advisory_available: advisoryAvailable - } = {} - } = await getCveListByAccount({ limit: 1 }); - - setHasConventionalSystems(rhelSystems); - setIncludesCvesWithoutErrata(cvesWithoutErrata); - setAdvisoryAvailable(advisoryAvailable); - setLoading(false); - } catch (error) { - if (error.status === '403') { - setHasAccess(false); - } - else { - addNotification({ - variant: 'danger', - autoDismiss: false, - msg: 'Failed to fetch systems', - description: error.detail - }); - } - - setLoading(false); - } - }; - - fetchData(); - }, []); + const { + hasEdgeDevices, + hasConventionalSystems, + includesCvesWithoutErrata, + isAdvisoryAvailable, + hasAccess + } = useAccountStats(isEdgeParityEnabled, setLoading, addNotification); const subPath = location.pathname && location.pathname.split('/')[4]; @@ -112,6 +74,7 @@ export const InsightsElement = ({ element: Element, title, globalFilterEnabled, chrome.updateDocumentTitle( `${subPath ? `${subPath} - ` : ''} ${title} - ${intl.formatMessage(messages.pageTitleSuffix)}` ); + }, [chrome, intl, subPath]); useEffect(() => { @@ -161,7 +124,8 @@ export const InsightsElement = ({ element: Element, title, globalFilterEnabled, InsightsElement.propTypes = { element: PropTypes.func, title: PropTypes.string, - globalFilterEnabled: PropTypes.bool + globalFilterEnabled: PropTypes.bool, + changeTitle: PropTypes.bool }; export const VulnerabilityRoutes = () => { diff --git a/src/index.js b/src/index.js index fc1e6f227..90df19bc2 100644 --- a/src/index.js +++ b/src/index.js @@ -6,9 +6,11 @@ import { Provider } from 'react-redux'; import { useRbac } from './Helpers/Hooks'; import { PERMISSIONS } from './Helpers/constants'; import PageLoading from './Components/PresentationalComponents/Snippets/PageLoading'; +import { AccountStatContextWrapper } from './Utilities/AccountStatContextWrapper'; const WrappedSystemCves = ({ getRegistry, ...props }) => { const [Wrapper, setWrapper] = useState(); + const [isLoading, setLoading] = useState(true); const [[canExport, canEditPairStatus]] = useRbac([PERMISSIONS.basicReporting, PERMISSIONS.setPairStatus]); @@ -18,12 +20,23 @@ const WrappedSystemCves = ({ getRegistry, ...props }) => { } setWrapper(() => getRegistry ? Provider : Fragment); + setLoading(false); }, []); + if (isLoading) { + return ; + } + return ( Wrapper ? - + + + : );