diff --git a/compiled-lang/en.json b/compiled-lang/en.json index b8d9e357..68ecd5dc 100644 --- a/compiled-lang/en.json +++ b/compiled-lang/en.json @@ -67,6 +67,8 @@ "noRecsForClusterListTitle": "No clusters yet", "noRecsFoundError": "No recommendations to display", "noRecsFoundErrorDesc": "Insights identifies and prioritizes risks to security, performance, availability, and stability of your clusters. This feature uses the Remote Health functionality of OpenShift Container Platform. For further details about Insights, see the", + "noUpgradeRisksFound": "No upgrade risks found for this cluster", + "noUpgradeRisksFoundDesc": "There are no known update risks that affect this cluster.", "none": "None", "oneOrMore": "1 or more", "performance": "Performance", @@ -116,6 +118,8 @@ "undefined": "Undefined", "unknown": "Unknown", "upgradeRisks": "Upgrade risks", + "upgradeRisksNotAvailable": "Upgrade risks are not available", + "upgradeRisksNotAvailableDesc": "This cluster has gone more than two hours without sending metrics. Check the cluster's web console if you think that this is incorrect.", "version": "Version", "veryLow": "Very Low", "viewAffectedClusters": "View {clusters, plural, one {the affected cluster} other {# affected clusters}}", diff --git a/cypress/fixtures/api/insights-results-aggregator/v1/clusters/41c30565-b4c9-49f2-a4ce-3277ad22b258/upgrade-risks-prediction.json b/cypress/fixtures/api/insights-results-aggregator/v1/clusters/41c30565-b4c9-49f2-a4ce-3277ad22b258/upgrade-risks-prediction.json new file mode 100644 index 00000000..42e18168 --- /dev/null +++ b/cypress/fixtures/api/insights-results-aggregator/v1/clusters/41c30565-b4c9-49f2-a4ce-3277ad22b258/upgrade-risks-prediction.json @@ -0,0 +1,35 @@ +{ + "status": "ok", + "upgrade_recommendation": { + "upgrade_risks_predictors": { + "alerts": [ + { + "name": "ClusterOperatorDown", + "namespace": "openshift-monitoring", + "severity": "critical" + }, + { + "name": "PostDisruptionBudgetLimit", + "namespace": "openshift-etcd", + "severity": "warning" + }, + { + "name": "Cluster operators", + "namespace": "openshift-kube-apiserver", + "severity": "info" + } + ], + "operator_conditions": [ + { + "name": "Version", + "condition": "failing" + }, + { + "name": "Node-tuning", + "condition": "degraded", + "reason": "Multiple tasks failed" + } + ] + } + } +} diff --git a/cypress/utils/interceptors.js b/cypress/utils/interceptors.js new file mode 100644 index 00000000..a35e3aca --- /dev/null +++ b/cypress/utils/interceptors.js @@ -0,0 +1,60 @@ +import singleClusterPageReport from '../fixtures/api/insights-results-aggregator/v2/cluster/dcb95bbf-8673-4f3a-a63c-12d4a530aa6f/reports-disabled-false.json'; + +// interceptors +export const clusterReportsInterceptors = { + successful: () => + cy.intercept( + '/api/insights-results-aggregator/v2/cluster/123/reports?get_disabled=false', + { + statusCode: 200, + body: singleClusterPageReport, + } + ), + 'long responding': () => + cy.intercept( + '/api/insights-results-aggregator/v2/cluster/123/reports?get_disabled=false', + { + statusCode: 200, + body: singleClusterPageReport, + delay: 420000, + } + ), + 'server error': () => + cy.intercept( + '/api/insights-results-aggregator/v2/cluster/123/reports?get_disabled=false', + { + statusCode: 500, + } + ), + 'successful, cluster name is null': () => { + const report = singleClusterPageReport; + report.report.meta.cluster_name = ''; + + cy.intercept( + '/api/insights-results-aggregator/v2/cluster/123/reports?get_disabled=false', + { + statusCode: 200, + body: report, + } + ); + }, + 'successful, no rules': () => { + const report = singleClusterPageReport; + report.report.data = []; + + cy.intercept( + '/api/insights-results-aggregator/v2/cluster/123/reports?get_disabled=false', + { + statusCode: 200, + body: report, + } + ); + }, + 'successful, not connected': () => + cy.intercept( + '/api/insights-results-aggregator/v2/cluster/123/reports?get_disabled=false', + { + statusCode: 404, + } + ), +}; diff --git a/src/Components/Cluster/Cluster.cy.js b/src/Components/Cluster/Cluster.cy.js index af6f77d8..7de060b1 100644 --- a/src/Components/Cluster/Cluster.cy.js +++ b/src/Components/Cluster/Cluster.cy.js @@ -5,6 +5,7 @@ import { checkNoMatchingRecs, checkRowCounts, } from '../../../cypress/utils/table'; +import { clusterReportsInterceptors as interceptors } from '../../../cypress/utils/interceptors'; // selectors const CLUSTER_HEADER = '#cluster-header'; @@ -12,65 +13,6 @@ const BREADCRUMBS = 'nav[class=pf-c-breadcrumb]'; const RULES_TABLE = '#cluster-recs-list-table'; const FILTER_CHIPS = 'li[class=pf-c-chip-group__list-item]'; -// interceptors -export const interceptors = { - successful: () => - cy.intercept( - '/api/insights-results-aggregator/v2/cluster/123/reports?get_disabled=false', - { - statusCode: 200, - body: singleClusterPageReport, - } - ), - 'long responding': () => - cy.intercept( - '/api/insights-results-aggregator/v2/cluster/123/reports?get_disabled=false', - { - statusCode: 200, - body: singleClusterPageReport, - delay: 420000, - } - ), - 'server error': () => - cy.intercept( - '/api/insights-results-aggregator/v2/cluster/123/reports?get_disabled=false', - { - statusCode: 500, - } - ), - 'successful, cluster name is null': () => { - const report = singleClusterPageReport; - report.report.meta.cluster_name = ''; - - cy.intercept( - '/api/insights-results-aggregator/v2/cluster/123/reports?get_disabled=false', - { - statusCode: 200, - body: report, - } - ); - }, - 'successful, no rules': () => { - const report = singleClusterPageReport; - report.report.data = []; - - cy.intercept( - '/api/insights-results-aggregator/v2/cluster/123/reports?get_disabled=false', - { - statusCode: 200, - body: report, - } - ); - }, - 'successful, not connected': () => - cy.intercept( - '/api/insights-results-aggregator/v2/cluster/123/reports?get_disabled=false', - { - statusCode: 404, - } - ), -}; - const CLUSTER_ID = '123'; const CLUSTER_NAME = 'Cluster With Issues'; diff --git a/src/Components/ClusterRules/ClusterRules.cy.js b/src/Components/ClusterRules/ClusterRules.cy.js index adbb2c0f..c9bf8f2c 100644 --- a/src/Components/ClusterRules/ClusterRules.cy.js +++ b/src/Components/ClusterRules/ClusterRules.cy.js @@ -27,7 +27,7 @@ import { TABLE, ROWS_TOGGLER, } from '../../../cypress/utils/components'; -import { interceptors } from '../Cluster/Cluster.cy'; +import { clusterReportsInterceptors as interceptors } from '../../../cypress/utils/interceptors'; const data = singleClusterPageReport.report.data; diff --git a/src/Components/ClusterTabs/ClusterTabs.js b/src/Components/ClusterTabs/ClusterTabs.js index 590f3bd0..f2bd642b 100644 --- a/src/Components/ClusterTabs/ClusterTabs.js +++ b/src/Components/ClusterTabs/ClusterTabs.js @@ -7,7 +7,7 @@ import messages from '../../Messages'; import { setSearchParameter } from '../../Utilities/Helpers'; import { useUpgradeRisksFeatureFlag } from '../../Utilities/useFeatureFlag'; import ClusterRules from '../ClusterRules/ClusterRules'; -import { ComingSoon } from '../MessageState/EmptyStates'; +import { UpgradeRisksTable } from '../UpgradeRisksTable'; const CLUSTER_TABS = ['recommendations', 'upgrade_risks']; @@ -40,16 +40,16 @@ const ClusterTabs = () => { eventKey="recommendations" title={intl.formatMessage(messages.recommendations)} > - + {activeKey === 'recommendations' && } + + + {upgradeRisksEnabled && activeKey === 'upgrade_risks' && ( + + )} - {upgradeRisksEnabled && ( - - - - )} diff --git a/src/Components/MessageState/EmptyStates.js b/src/Components/MessageState/EmptyStates.js index c35713b3..28937710 100644 --- a/src/Components/MessageState/EmptyStates.js +++ b/src/Components/MessageState/EmptyStates.js @@ -18,6 +18,7 @@ import { InProgressIcon } from '@patternfly/react-icons/dist/esm/icons/in-progre import InfoCircleIcon from '@patternfly/react-icons/dist/js/icons/info-circle-icon'; import { global_info_color_100 as globalInfoColor100 } from '@patternfly/react-tokens/dist/js/global_info_color_100.js'; import CheckIcon from '@patternfly/react-icons/dist/js/icons/check-icon'; +import ExclamationTriangleIcon from '@patternfly/react-icons/dist/esm/icons/exclamation-triangle-icon'; import DefaultErrorMessage from '@redhat-cloud-services/frontend-components/ErrorState/DefaultErrorMessage'; @@ -187,6 +188,31 @@ const NoRecsAffecting = () => { ); }; +const NoUpgradeRisks = () => { + const intl = useIntl(); + return ( + + ); +}; + +const UpgradeRisksNotAvailable = () => { + const intl = useIntl(); + return ( + + ); +}; + export { ErrorState, NoAffectedClusters, @@ -197,4 +223,6 @@ export { NoInsightsResults, NoRecsError, NoRecsAffecting, + NoUpgradeRisks, + UpgradeRisksNotAvailable, }; diff --git a/src/Components/MessageState/MessageState.js b/src/Components/MessageState/MessageState.js index b3e38007..7138cd27 100644 --- a/src/Components/MessageState/MessageState.js +++ b/src/Components/MessageState/MessageState.js @@ -32,7 +32,9 @@ const MessageState = ({ {title} - {text} + + {text} + {children} ); diff --git a/src/Components/UpgradeRisksTable/AlertsList.js b/src/Components/UpgradeRisksTable/AlertsList.js new file mode 100644 index 00000000..aa6ab363 --- /dev/null +++ b/src/Components/UpgradeRisksTable/AlertsList.js @@ -0,0 +1,89 @@ +import { Flex, Icon } from '@patternfly/react-core'; +import ExclamationCircleIcon from '@patternfly/react-icons/dist/esm/icons/exclamation-circle-icon'; +import InfoCircleIcon from '@patternfly/react-icons/dist/esm/icons/info-circle-icon'; +import ExclamationTriangleIcon from '@patternfly/react-icons/dist/esm/icons/exclamation-triangle-icon'; +import { + TableComposable, + Tbody, + Td, + Th, + Thead, + Tr, +} from '@patternfly/react-table'; +import React from 'react'; +import { useParams } from 'react-router-dom'; +import { useGetUpgradeRisksQuery } from '../../Services/SmartProxy'; + +export const ALERTS_SEVERITY_ICONS = { + critical: ( + + + + ), + warning: ( + + + + ), + info: ( + + + + ), +}; + +export const ALERTS_SEVERITY_LABEL = { + critical: ( + + {ALERTS_SEVERITY_ICONS['critical']} Critical + + ), + warning: ( + + {ALERTS_SEVERITY_ICONS['warning']} Warning + + ), + info: ( + + {ALERTS_SEVERITY_ICONS['info']} Info + + ), +}; + +export const ALERTS_SEVERITY_ORDER = ['critical', 'warning', 'info']; + +const AlertsList = () => { + const { clusterId } = useParams(); + const { data } = useGetUpgradeRisksQuery({ id: clusterId }); + const { alerts = [] } = + data?.upgrade_recommendation?.upgrade_risks_predictors || {}; + + return ( + + + + Name + Status + Namespace + + + + {alerts.map(({ name, namespace, severity }) => ( + + {name} + + {ALERTS_SEVERITY_LABEL[severity]} + + {namespace} + + ))} + + + ); +}; + +export default AlertsList; diff --git a/src/Components/UpgradeRisksTable/ClusterOperatorsList.js b/src/Components/UpgradeRisksTable/ClusterOperatorsList.js new file mode 100644 index 00000000..aedde423 --- /dev/null +++ b/src/Components/UpgradeRisksTable/ClusterOperatorsList.js @@ -0,0 +1,61 @@ +import React from 'react'; +import { + TableComposable, + Tbody, + Td, + Th, + Thead, + Tr, +} from '@patternfly/react-table'; +import { useParams } from 'react-router-dom'; +import { useGetUpgradeRisksQuery } from '../../Services/SmartProxy'; +import { Flex, Icon } from '@patternfly/react-core'; +import ExclamationTriangleIcon from '@patternfly/react-icons/dist/esm/icons/exclamation-triangle-icon'; + +export const CLUSTER_OPERATOR_LABEL = { + degraded: 'Degraded', + failing: 'Failing', + available: 'Not Available', + upgradeable: 'Not Upgradeable', +}; + +const ClusterOperatorsList = () => { + const { clusterId } = useParams(); + const { data } = useGetUpgradeRisksQuery({ id: clusterId }); + const { operator_conditions: conditions = [] } = + data?.upgrade_recommendation?.upgrade_risks_predictors || {}; + + return ( + + + + Name + Status + Message + + + + {conditions.map(({ name, condition, reason }) => ( + + {name} + + + + + + {CLUSTER_OPERATOR_LABEL[condition]} + + + {reason || '-'} + + ))} + + + ); +}; + +export default ClusterOperatorsList; diff --git a/src/Components/UpgradeRisksTable/UpgradeRisksTable.cy.js b/src/Components/UpgradeRisksTable/UpgradeRisksTable.cy.js new file mode 100644 index 00000000..d916d2e1 --- /dev/null +++ b/src/Components/UpgradeRisksTable/UpgradeRisksTable.cy.js @@ -0,0 +1,277 @@ +import React from 'react'; +import upgradeRisksFixtures from '../../../cypress/fixtures/api/insights-results-aggregator/v1/clusters/41c30565-b4c9-49f2-a4ce-3277ad22b258/upgrade-risks-prediction.json'; +import { TABLE_HEADER } from '../../../cypress/utils/components'; +import { + checkEmptyState, + checkTableHeaders, +} from '../../../cypress/utils/table'; +import UpgradeRisksTable from './UpgradeRisksTable'; + +const SEVERITY_MAPPING = { + critical: 'Critical', + warning: 'Warning', + info: 'Info', +}; + +const SEVERITY_ICON_CLASS_MAPPING = { + critical: 'danger', + warning: 'warning', + info: 'info', +}; + +export const CLUSTER_OPERATOR_LABEL_MAPPING = { + degraded: 'Degraded', + failing: 'Failing', + available: 'Not Available', + upgradeable: 'Not Upgradeable', +}; + +const interceptors = { + successful: () => + cy.intercept( + 'GET', + /\/api\/insights-results-aggregator\/v2\/cluster\/.*\/upgrade-risks-prediction/, + { + statusCode: 200, + body: upgradeRisksFixtures, + } + ), + 'successful, alerts empty': () => { + const fixtures = upgradeRisksFixtures; + fixtures.upgrade_recommendation.upgrade_risks_predictors.alerts = []; + cy.intercept( + 'GET', + /\/api\/insights-results-aggregator\/v2\/cluster\/.*\/upgrade-risks-prediction/, + { + statusCode: 200, + body: fixtures, + } + ); + }, + 'successful, empty': () => { + const fixtures = upgradeRisksFixtures; + fixtures.upgrade_recommendation.upgrade_risks_predictors = { + alerts: [], + operator_conditions: [], + }; + cy.intercept( + 'GET', + /\/api\/insights-results-aggregator\/v2\/cluster\/.*\/upgrade-risks-prediction/, + { + statusCode: 200, + body: fixtures, + } + ); + }, + 'error, not available': () => + cy.intercept( + 'GET', + /\/api\/insights-results-aggregator\/v2\/cluster\/.*\/upgrade-risks-prediction/, + { + statusCode: 503, + } + ), + 'error, other': () => + cy.intercept( + 'GET', + /\/api\/insights-results-aggregator\/v2\/cluster\/.*\/upgrade-risks-prediction/, + { + statusCode: 500, + } + ), + 'long responding': () => + cy.intercept( + 'GET', + /\/api\/insights-results-aggregator\/v2\/cluster\/.*\/upgrade-risks-prediction/, + { + delay: 420000, + } + ), +}; + +const CLUSTER_ID = '41c30565-b4c9-49f2-a4ce-3277ad22b258'; + +const mount = (initialEntries = [`/clusters/${CLUSTER_ID}`]) => { + cy.mountWithContext(, { + path: '/clusters/:clusterId', + routerProps: { initialEntries }, + }); +}; + +const TABLE_ROW = '[data-ouia-component-type="PF4/TableRow"]'; + +describe('successful with some risks', () => { + beforeEach(() => { + interceptors.successful(); + mount(); + }); + + it('renders main headers', () => { + cy.get('#upgrade-risks-table'); + cy.get(TABLE_HEADER).contains('Name'); + cy.get(TABLE_ROW).contains('Alerts firing'); + cy.get(TABLE_ROW).contains('Cluster operators'); + }); + + it('shows correct risks number', () => { + cy.get('#alerts-label').should( + 'have.text', + `${upgradeRisksFixtures.upgrade_recommendation.upgrade_risks_predictors.alerts.length} upgrade risks` + ); + cy.get('#operator-conditions-label').should( + 'have.text', + `${upgradeRisksFixtures.upgrade_recommendation.upgrade_risks_predictors.operator_conditions.length} upgrade risks` + ); + }); + + it('shows correct icons', () => { + cy.get('.alerts__header') + .find('.pf-c-icon__content') + .should('have.class', 'pf-m-danger'); + cy.get('.operators__header') + .find('.pf-c-icon__content') + .should('have.class', 'pf-m-warning'); + }); + + it('has alerts table', () => { + cy.get('.alerts__content').should('be.visible'); + cy.get('.alerts__content').within(() => { + checkTableHeaders(['Name', 'Status', 'Namespace']); + cy.get('tbody') + .find(TABLE_ROW) + .each(($row, index) => { + const alert = + upgradeRisksFixtures.upgrade_recommendation.upgrade_risks_predictors + .alerts[index]; + cy.get($row).find('.alerts__name').should('have.text', alert.name); + cy.get($row) + .find('.alerts__severity') + .should('contain.text', SEVERITY_MAPPING[alert.severity]); + cy.get($row) + .find('.alerts__severity .pf-c-icon__content') + .should( + 'have.class', + `pf-m-${SEVERITY_ICON_CLASS_MAPPING[alert.severity]}` + ); + cy.get($row) + .find('.alerts__namespace') + .should('have.text', alert.namespace); + }); + }); + }); + + it('has operator conditions table', () => { + cy.get('.operators__content').should('be.visible'); + cy.get('.operators__content').within(() => { + checkTableHeaders(['Name', 'Status', 'Message']); + cy.get('tbody') + .find(TABLE_ROW) + .each(($row, index) => { + const condition = + upgradeRisksFixtures.upgrade_recommendation.upgrade_risks_predictors + .operator_conditions[index]; + cy.get($row) + .find('.operators__name') + .should('have.text', condition.name); + cy.get($row) + .find('.operators__status') + .should( + 'contain.text', + CLUSTER_OPERATOR_LABEL_MAPPING[condition.condition] + ); + cy.get($row) + .find('.operators__status .pf-c-icon__content') + .should('have.class', `pf-m-warning`); + cy.get($row) + .find('.operators__message') + .should('have.text', condition.reason || '-'); + }); + }); + }); + + it('can hide content', () => { + cy.get('.pf-c-table__toggle button').eq(0).click(); + cy.get('.alerts__content').should('not.be.visible'); + + cy.get('.pf-c-table__toggle button').eq(1).click(); + cy.get('.operators__content').should('not.be.visible'); + }); +}); + +describe('successful, only cluster operators', () => { + beforeEach(() => { + interceptors['successful, alerts empty'](); + mount(); + }); + + it('has alerts hidden', () => { + cy.get('.alerts__content').should('not.exist'); + }); + + it('shows 0 alert risks', () => { + cy.get('#alerts-label').should('have.text', `0 upgrade risks`); + }); + + it('does not show icon for alerts', () => { + cy.get('.alerts__header').find('.pf-c-icon__content').should('not.exist'); + }); +}); + +describe('successful, empty', () => { + beforeEach(() => { + interceptors['successful, empty'](); + mount(); + }); + + it('renders empty state', () => { + checkEmptyState('No upgrade risks found for this cluster', true); + }); + + it('header is present', () => { + checkTableHeaders(['Name']); + }); +}); + +describe('error, service down', () => { + beforeEach(() => { + interceptors['error, not available'](); + mount(); + }); + + it('renders empty state', () => { + checkEmptyState('Upgrade risks are not available', true); + }); + + it('header is present', () => { + checkTableHeaders(['Name']); + }); +}); + +describe('error, other', () => { + beforeEach(() => { + interceptors['error, other'](); + mount(); + }); + + it('renders empty state', () => { + // can't apply checkEmptyState since "something went wrong" component doesn't use OUIA id + cy.get('.pf-c-empty-state h4').should('have.text', 'Something went wrong'); + cy.get('.pf-c-empty-state__icon').should('be.visible'); + }); + + it('header is present', () => { + checkTableHeaders(['Name']); + }); +}); + +describe('loading', () => { + beforeEach(() => { + interceptors['long responding'](); + mount(); + }); + + it('renders spinner', () => { + cy.get('.pf-c-spinner').should('be.visible'); + cy.get('#upgrade-risks-table').should('not.exist'); + }); +}); diff --git a/src/Components/UpgradeRisksTable/UpgradeRisksTable.js b/src/Components/UpgradeRisksTable/UpgradeRisksTable.js new file mode 100644 index 00000000..42985387 --- /dev/null +++ b/src/Components/UpgradeRisksTable/UpgradeRisksTable.js @@ -0,0 +1,182 @@ +import { + EmptyState, + EmptyStateIcon, + Flex, + Icon, + Label, + Spinner, +} from '@patternfly/react-core'; +import ExclamationTriangleIcon from '@patternfly/react-icons/dist/esm/icons/exclamation-triangle-icon'; +import { + ExpandableRowContent, + TableComposable, + Tbody, + Td, + Th, + Thead, + Tr, +} from '@patternfly/react-table'; +import ErrorState from '@redhat-cloud-services/frontend-components/ErrorState'; +import React, { useEffect, useState } from 'react'; +import { useParams } from 'react-router-dom'; +import { useGetUpgradeRisksQuery } from '../../Services/SmartProxy'; +import { + NoUpgradeRisks, + UpgradeRisksNotAvailable, +} from '../MessageState/EmptyStates'; +import AlertsList, { + ALERTS_SEVERITY_ICONS, + ALERTS_SEVERITY_ORDER, +} from './AlertsList'; +import ClusterOperatorsList from './ClusterOperatorsList'; + +const UpgradeRisksTable = () => { + const { clusterId } = useParams(); + const { isError, isUninitialized, isFetching, isSuccess, data, error } = + useGetUpgradeRisksQuery({ id: clusterId }); + const { alerts = [], operator_conditions: conditions = [] } = + data?.upgrade_recommendation?.upgrade_risks_predictors || {}; + + const alertsDisabled = alerts.length === 0; + const conditionsDisabled = conditions.length === 0; + + const [alertsExpanded, setAlertsExpanded] = useState(true); + const [operatorsExpanded, setOperatorsExpanded] = useState(true); + + useEffect(() => { + setAlertsExpanded(!alertsDisabled); + setOperatorsExpanded(!conditionsDisabled); + }, [data]); + + const hasRisks = isSuccess && (alerts.length > 0 || conditions.length > 0); + const noRisks = isSuccess && alerts.length === 0 && conditions.length === 0; + + return isUninitialized || isFetching ? ( + + + + ) : ( + + + + + Name + + + {hasRisks ? ( + <> + + + setAlertsExpanded(!alertsExpanded), + } + } + /> + + + {!alertsDisabled && + ALERTS_SEVERITY_ICONS[ // this algorithm helps to decide which icon (the most severe) to show + ALERTS_SEVERITY_ORDER.filter((s) => + alerts.some(({ severity }) => s === severity) + )[0] + ]} + Alerts firing + + + + + + + + + Learn how to resolve your alert firing risks. + + + + + + + + + setOperatorsExpanded(!operatorsExpanded), + } + } + /> + + + {!conditionsDisabled && ( + + + + )} + Cluster opertors + + + + + + + + + Learn how to resolve your cluster operator risks. + + + + + + + ) : noRisks ? ( + + + + + + + + ) : isError && error.status === 503 ? ( + + + + + {/* back end is temporarily not available */} + + + + ) : ( + + + + + {/* default state for unexpected errors */} + + + + )} + + ); +}; + +export default UpgradeRisksTable; diff --git a/src/Components/UpgradeRisksTable/index.js b/src/Components/UpgradeRisksTable/index.js new file mode 100644 index 00000000..22ec7ea2 --- /dev/null +++ b/src/Components/UpgradeRisksTable/index.js @@ -0,0 +1 @@ +export { default as UpgradeRisksTable } from './UpgradeRisksTable'; diff --git a/src/Messages.js b/src/Messages.js index 97bea3ba..10d38850 100644 --- a/src/Messages.js +++ b/src/Messages.js @@ -647,4 +647,21 @@ export default defineMessages({ description: 'Upgrade risks text', defaultMessage: 'Upgrade risks', }, + noUpgradeRisksFound: { + id: 'noUpgradeRisksFound', + defaultMessage: 'No upgrade risks found for this cluster', + }, + noUpgradeRisksFoundDesc: { + id: 'noUpgradeRisksFoundDesc', + defaultMessage: 'There are no known update risks that affect this cluster.', + }, + upgradeRisksNotAvailable: { + id: 'upgradeRisksNotAvailable', + defaultMessage: 'Upgrade risks are not available', + }, + upgradeRisksNotAvailableDesc: { + id: 'upgradeRisksNotAvailableDesc', + defaultMessage: + "This cluster has gone more than two hours without sending metrics. Check the cluster's web console if you think that this is incorrect.", + }, }); diff --git a/src/Services/SmartProxy.js b/src/Services/SmartProxy.js index 3fa7ff7b..e41957b4 100644 --- a/src/Services/SmartProxy.js +++ b/src/Services/SmartProxy.js @@ -37,6 +37,9 @@ export const SmartProxyApi = createApi({ query: ({ id }) => `v2/cluster/${id}/info`, transformResponse: (response) => response?.cluster, }), + getUpgradeRisks: builder.query({ + query: ({ id }) => `v2/cluster/${id}/upgrade-risks-prediction`, + }), }), }); @@ -50,4 +53,5 @@ export const { useLazyGetRecsQuery, useGetClustersQuery, useGetClusterInfoQuery, + useGetUpgradeRisksQuery, } = SmartProxyApi;