diff --git a/sass/components/ClusterOverview/compliance.scss b/sass/components/ClusterOverview/compliance.scss index 2a2f337fa..65d83046c 100644 --- a/sass/components/ClusterOverview/compliance.scss +++ b/sass/components/ClusterOverview/compliance.scss @@ -1,4 +1,6 @@ .kubevirt-compliance__body { - text-align: center; - max-height: 130px; + display: flex; + flex-wrap: wrap; + align-items: center; + height: 2.3em; } diff --git a/sass/components/ClusterOverview/health.scss b/sass/components/ClusterOverview/health.scss index 1674a17bb..4cd0b140c 100644 --- a/sass/components/ClusterOverview/health.scss +++ b/sass/components/ClusterOverview/health.scss @@ -4,9 +4,3 @@ grid-gap: 0; } } - -.kubevirt-compliance__body { - display: flex; - flex-wrap: wrap; - align-items: center; -} diff --git a/sass/components/Dashboard/health.scss b/sass/components/Dashboard/health.scss index e12a93574..f0821af99 100644 --- a/sass/components/Dashboard/health.scss +++ b/sass/components/Dashboard/health.scss @@ -1,14 +1,44 @@ -.kubevirt-health__body { +.kubevirt-health__item { display: flex; flex-wrap: wrap; align-items: center; } +.kubevirt-health__body { + height: 2.3em; +} + +/* stylelint-disable plugin/selector-bem-pattern */ +.kubevirt-health__subsystem-body { + display: flex; + flex-wrap: wrap; + flex-direction: column; + height: auto; + + .kubevirt-health__item { + padding-top: 5px; + } + + .kubevirt-health__separator { + border-bottom: 1px solid #ededed; + } +} +/* stylelint-enable */ + .kubevirt-health__text { font-size: 0.875rem; margin-left: 1rem; } +.kubevirt-health__title { + padding-left: 0.6rem; +} + +.kubevirt-health__subtitle { + font-size: 0.7rem; + color: grey; +} + .kubevirt-health__icon { font-size: 1.5rem; } diff --git a/src/components/ClusterOverview/ClusterOverview.js b/src/components/ClusterOverview/ClusterOverview.js index 274fd7796..dc9c91e99 100644 --- a/src/components/ClusterOverview/ClusterOverview.js +++ b/src/components/ClusterOverview/ClusterOverview.js @@ -7,7 +7,7 @@ import { Dashboard, DashboardBody } from '../Dashboard'; import { MEDIA_QUERY_EXCLUSIVE_DEVIATION, MEDIA_QUERY_LG } from '../../utils'; import { DetailsConnected } from './Details/Details'; -import HealthConnected from './Health/Health'; +import { HealthConnected } from './Health/Health'; import ComplianceConnected from './Compliance/Compliance'; import EventsConnected from './Events/Events'; import { InventoryConnected } from './Inventory/Inventory'; diff --git a/src/components/ClusterOverview/Compliance/Compliance.js b/src/components/ClusterOverview/Compliance/Compliance.js index 453988775..b311921ff 100644 --- a/src/components/ClusterOverview/Compliance/Compliance.js +++ b/src/components/ClusterOverview/Compliance/Compliance.js @@ -16,8 +16,8 @@ export const Compliance = ({ data, loaded }) => ( Cluster Compliance - - + + ); diff --git a/src/components/ClusterOverview/Compliance/tests/__snapshots__/Compliance.test.js.snap b/src/components/ClusterOverview/Compliance/tests/__snapshots__/Compliance.test.js.snap index c279a4a5a..2fedf897f 100644 --- a/src/components/ClusterOverview/Compliance/tests/__snapshots__/Compliance.test.js.snap +++ b/src/components/ClusterOverview/Compliance/tests/__snapshots__/Compliance.test.js.snap @@ -14,21 +14,25 @@ exports[` renders correctly 1`] = `
+
+
- - All nodes compliant -
`; diff --git a/src/components/ClusterOverview/Health/Health.js b/src/components/ClusterOverview/Health/Health.js index 4197eb48d..50ba43fd0 100644 --- a/src/components/ClusterOverview/Health/Health.js +++ b/src/components/ClusterOverview/Health/Health.js @@ -6,31 +6,93 @@ import { DashboardCardBody, DashboardCardHeader, DashboardCardTitle, + DashboardCardTitleSeeAll, } from '../../Dashboard/DashboardCard'; -import HealthBody from './HealthBody'; -import { ClusterOverviewContextGenericConsumer } from '../ClusterOverviewContext'; +import { ClusterOverviewContext } from '../ClusterOverviewContext'; import { InlineLoading } from '../../Loading'; +import { SubsystemHealth } from '../../Dashboard/SubsystemHealth'; +import { HealthItem, OK_STATE, ERROR_STATE, WARNING_STATE } from '../../Dashboard/Health/HealthItem'; +import { HealthBody } from '../../Dashboard/Health/HealthBody'; +import { getK8sHealthState, getKubevirtHealthState, getOCSHealthState } from '../../Dashboard/Health/utils'; -export const Health = ({ data, loaded }) => ( - - - Cluster Health - - - - - -); +const getClusterHealth = subsystemStates => { + let healthState = { state: OK_STATE, message: 'Cluster is healthy' }; + const sortedStates = { + errorStates: [], + warningStates: [], + }; + + subsystemStates.forEach(state => { + switch (state.state) { + case ERROR_STATE: + sortedStates.errorStates.push(state); + break; + case WARNING_STATE: + sortedStates.warningStates.push(state); + break; + default: + break; + } + }); + + if (sortedStates.errorStates.length > 0) { + healthState = + sortedStates.errorStates.length === 1 + ? sortedStates.errorStates[0] + : { state: ERROR_STATE, message: 'Multiple errors', details: 'Cluster health is degrated' }; + } else if (sortedStates.warningStates.length > 0) { + healthState = + sortedStates.warningStates.length === 1 + ? sortedStates.warningStates[0] + : { state: WARNING_STATE, message: 'Multiple warnings', details: 'Cluster health is degrated' }; + } + + return healthState; +}; + +export const Health = ({ k8sHealth, kubevirtHealth, cephHealth, LoadingComponent }) => { + const k8sHealthState = getK8sHealthState(k8sHealth); + const kubevirtHealthState = getKubevirtHealthState(kubevirtHealth); + const cephHealthState = getOCSHealthState(cephHealth); + + const healthState = getClusterHealth([k8sHealthState, kubevirtHealthState, cephHealthState]); + + return ( + + + Cluster Health + + + + + + + + + + + ); +}; Health.defaultProps = { - loaded: false, + k8sHealth: null, + kubevirtHealth: null, + cephHealth: null, + LoadingComponent: InlineLoading, }; Health.propTypes = { - data: PropTypes.object.isRequired, - loaded: PropTypes.bool, + k8sHealth: PropTypes.object, + kubevirtHealth: PropTypes.object, + cephHealth: PropTypes.object, + LoadingComponent: PropTypes.oneOfType([PropTypes.node, PropTypes.func]), }; -const HealthConnected = () => ; - -export default HealthConnected; +export const HealthConnected = () => ( + {props => } +); diff --git a/src/components/ClusterOverview/Health/HealthBody.js b/src/components/ClusterOverview/Health/HealthBody.js index a295cc843..0801e607f 100644 --- a/src/components/ClusterOverview/Health/HealthBody.js +++ b/src/components/ClusterOverview/Health/HealthBody.js @@ -14,15 +14,20 @@ const errorIcon = ( ); -const HealthBody = ({ data }) => ( - +const HealthBody = ({ data, className }) => ( +
{data.healthy ? healtyIcon : errorIcon} {data.message} - +
); +HealthBody.defaultProps = { + className: null, +}; + HealthBody.propTypes = { data: PropTypes.object.isRequired, + className: PropTypes.string, }; export default HealthBody; diff --git a/src/components/ClusterOverview/Health/fixtures/Health.fixture.js b/src/components/ClusterOverview/Health/fixtures/Health.fixture.js index e958803c3..a7bfe51a5 100644 --- a/src/components/ClusterOverview/Health/fixtures/Health.fixture.js +++ b/src/components/ClusterOverview/Health/fixtures/Health.fixture.js @@ -1,11 +1,39 @@ import { Health } from '../Health'; export const healthData = { - data: { - healthy: false, - message: 'Error message', + k8sHealth: { + response: 'ok', + }, + cephHealth: { + result: [ + { + value: [null, 0], + }, + ], + }, + kubevirtHealth: { + apiserver: { + connectivity: 'ok', + }, + }, +}; + +export const healthDataErrors = { + k8sHealth: { + response: 'error', + }, + cephHealth: { + result: [ + { + value: [null, 0], + }, + ], + }, + kubevirtHealth: { + apiserver: { + connectivity: 'error', + }, }, - loaded: true, }; export default [ @@ -13,4 +41,8 @@ export default [ component: Health, props: { ...healthData }, }, + { + component: Health, + props: { ...healthDataErrors }, + }, ]; diff --git a/src/components/ClusterOverview/Health/tests/Health.test.js b/src/components/ClusterOverview/Health/tests/Health.test.js index 1f3618a0a..a1ea4338b 100644 --- a/src/components/ClusterOverview/Health/tests/Health.test.js +++ b/src/components/ClusterOverview/Health/tests/Health.test.js @@ -5,10 +5,15 @@ import { Health } from '../Health'; import { default as HealthFixtures } from '../fixtures/Health.fixture'; const testHealthOverview = () => ; +const testHealthErrorsOverview = () => ; describe('', () => { it('renders correctly', () => { const component = render(testHealthOverview()); expect(component).toMatchSnapshot(); }); + it('renders multiple erros correctly', () => { + const component = render(testHealthErrorsOverview()); + expect(component).toMatchSnapshot(); + }); }); diff --git a/src/components/ClusterOverview/Health/tests/__snapshots__/Health.test.js.snap b/src/components/ClusterOverview/Health/tests/__snapshots__/Health.test.js.snap index 1ebd88f39..3747c9236 100644 --- a/src/components/ClusterOverview/Health/tests/__snapshots__/Health.test.js.snap +++ b/src/components/ClusterOverview/Health/tests/__snapshots__/Health.test.js.snap @@ -12,23 +12,93 @@ exports[` renders correctly 1`] = ` > Cluster Health +
-
- +
+`; + +exports[` renders multiple erros correctly 1`] = ` +
+
+

+ Cluster Health +

+ +
+
+
+
+
+
+
+ + Multiple errors + +
+ Cluster health is degrated +
+
+
+
`; diff --git a/src/components/ClusterOverview/Health/tests/__snapshots__/HealthBody.test.js.snap b/src/components/ClusterOverview/Health/tests/__snapshots__/HealthBody.test.js.snap index 1ebd88f39..64d3aa6b4 100644 --- a/src/components/ClusterOverview/Health/tests/__snapshots__/HealthBody.test.js.snap +++ b/src/components/ClusterOverview/Health/tests/__snapshots__/HealthBody.test.js.snap @@ -12,23 +12,39 @@ exports[` renders correctly 1`] = ` > Cluster Health +
-
- - Error message -
`; diff --git a/src/components/ClusterOverview/fixtures/ClusterOverview.fixture.js b/src/components/ClusterOverview/fixtures/ClusterOverview.fixture.js index 15b3d6ce6..a93b5bb9a 100644 --- a/src/components/ClusterOverview/fixtures/ClusterOverview.fixture.js +++ b/src/components/ClusterOverview/fixtures/ClusterOverview.fixture.js @@ -1,7 +1,7 @@ import React from 'react'; import { ClusterOverview as ClusterOverviewComponent } from '../ClusterOverview'; -import { healthData } from '../Health/fixtures/Health.fixture'; +import { healthData, healthDataErrors } from '../Health/fixtures/Health.fixture'; import { eventsData } from '../Events/fixtures/Events.fixture'; import { consumersData } from '../TopConsumers/fixtures/TopConsumers.fixture'; import { capacityStats } from '../Capacity/fixtures/Capacity.fixture'; @@ -38,7 +38,7 @@ export default [ component: ClusterOverview, props: { ...clusterDetailsData, - healthData, + ...healthData, ...capacityStats, complianceData, eventsData, @@ -56,19 +56,37 @@ export default [ component: ClusterOverview, name: 'Loading overview', props: { - healthData: { loaded: false }, complianceData: { loaded: false }, eventsData: { loaded: false }, utilizationStats: { loaded: false }, inventoryData: { loaded: false }, }, }, + { + component: ClusterOverview, + name: 'Overview with multiple health errors', + props: { + ...clusterDetailsData, + ...healthDataErrors, + ...capacityStats, + complianceData, + eventsData, + utilizationStats, + ...consumersData, + nodes, + pvcs, + pods, + vms, + vmis, + migrations, + }, + }, { component: ClusterOverview, name: 'Overview with alerts', props: { ...clusterDetailsData, - healthData, + ...healthData, ...capacityStats, complianceData, eventsData, diff --git a/src/components/Dashboard/DashboardCard/DashboardCardTitleSeeAll.js b/src/components/Dashboard/DashboardCard/DashboardCardTitleSeeAll.js new file mode 100644 index 000000000..7599419df --- /dev/null +++ b/src/components/Dashboard/DashboardCard/DashboardCardTitleSeeAll.js @@ -0,0 +1,30 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Button, OverlayTrigger, Popover } from 'patternfly-react'; + +const SEE_ALL = 'See all'; + +export const DashboardCardTitleSeeAll = ({ title, children }) => { + if (React.Children.count(children) === 0) { + return null; + } + const overlay = ( + + {children} + + ); + return ( + + + + ); +}; + +DashboardCardTitleSeeAll.defaultProps = { + children: null, +}; + +DashboardCardTitleSeeAll.propTypes = { + children: PropTypes.node, + title: PropTypes.string.isRequired, +}; diff --git a/src/components/Dashboard/DashboardCard/fixtures/DashboardCardTitleSeeAll.fixture.js b/src/components/Dashboard/DashboardCard/fixtures/DashboardCardTitleSeeAll.fixture.js new file mode 100644 index 000000000..2a19faef4 --- /dev/null +++ b/src/components/Dashboard/DashboardCard/fixtures/DashboardCardTitleSeeAll.fixture.js @@ -0,0 +1,6 @@ +import { DashboardCardTitleSeeAll } from '../DashboardCardTitleSeeAll'; + +export default { + component: DashboardCardTitleSeeAll, + props: { children: ['content'] }, +}; diff --git a/src/components/Dashboard/DashboardCard/index.js b/src/components/Dashboard/DashboardCard/index.js index a05fd9a96..8e9513754 100644 --- a/src/components/Dashboard/DashboardCard/index.js +++ b/src/components/Dashboard/DashboardCard/index.js @@ -3,3 +3,4 @@ export { default as DashboardCardBody } from './DashboardCardBody'; export { default as DashboardCardHeader } from './DashboardCardHeader'; export { default as DashboardCardTitle } from './DashboardCardTitle'; export { default as DashboardCardTitleHelp } from './DashboardCardTitleHelp'; +export { DashboardCardTitleSeeAll } from './DashboardCardTitleSeeAll'; diff --git a/src/components/Dashboard/DashboardCard/tests/DashboardCardTitleSeeAll.test.js b/src/components/Dashboard/DashboardCard/tests/DashboardCardTitleSeeAll.test.js new file mode 100644 index 000000000..e9f41085a --- /dev/null +++ b/src/components/Dashboard/DashboardCard/tests/DashboardCardTitleSeeAll.test.js @@ -0,0 +1,13 @@ +import React from 'react'; +import { shallow } from 'enzyme'; + +import { DashboardCardTitleSeeAll } from '../DashboardCardTitleSeeAll'; + +const testDashboardCardTitleSeeAll = () => content; + +describe('', () => { + it('renders correctly', () => { + const component = shallow(testDashboardCardTitleSeeAll()); + expect(component).toMatchSnapshot(); + }); +}); diff --git a/src/components/Dashboard/DashboardCard/tests/__snapshots__/DashboardCardTitleSeeAll.test.js.snap b/src/components/Dashboard/DashboardCard/tests/__snapshots__/DashboardCardTitleSeeAll.test.js.snap new file mode 100644 index 000000000..9a4bade51 --- /dev/null +++ b/src/components/Dashboard/DashboardCard/tests/__snapshots__/DashboardCardTitleSeeAll.test.js.snap @@ -0,0 +1,33 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` renders correctly 1`] = ` + + content + + } + placement="right" + rootClose={true} + trigger={ + Array [ + "click", + ] + } +> + + +`; diff --git a/src/components/Dashboard/Health/HealthBody.js b/src/components/Dashboard/Health/HealthBody.js index e51696f8b..cc45ac0df 100644 --- a/src/components/Dashboard/Health/HealthBody.js +++ b/src/components/Dashboard/Health/HealthBody.js @@ -1,8 +1,16 @@ import React from 'react'; import PropTypes from 'prop-types'; +import classNames from 'classnames'; -export const HealthBody = ({ children }) =>
{children}
; +export const HealthBody = ({ children, className }) => ( +
{children}
+); + +HealthBody.defaultProps = { + className: null, +}; HealthBody.propTypes = { + className: PropTypes.string, children: PropTypes.oneOfType([PropTypes.node, PropTypes.func]).isRequired, }; diff --git a/src/components/Dashboard/Health/HealthItem.js b/src/components/Dashboard/Health/HealthItem.js index 78a0b69b1..266719584 100644 --- a/src/components/Dashboard/Health/HealthItem.js +++ b/src/components/Dashboard/Health/HealthItem.js @@ -2,15 +2,56 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Icon } from 'patternfly-react'; -export const HealthItem = ({ icon, classname, message }) => ( -
- - {message} +import { InlineLoading } from '../../Loading'; + +export const OK_STATE = 'OK_STATE'; +export const ERROR_STATE = 'ERROR_STATE'; +export const WARNING_STATE = 'WARNING_STATE'; +export const LOADING_STATE = 'LOADING_STATE'; + +const getIcon = state => { + let icon; + let className; + switch (state) { + case OK_STATE: + icon = 'check-circle'; + className = 'ok'; + break; + case ERROR_STATE: + icon = 'exclamation-circle'; + className = 'error'; + break; + case WARNING_STATE: + default: + icon = 'exclamation-triangle'; + className = 'warning'; + } + return ( +
+ +
+ ); +}; + +export const HealthItem = ({ state, LoadingComponent, message, details }) => ( +
+ {state === LOADING_STATE ? : getIcon(state)} +
+ {message} + {details &&
{details}
} +
); +HealthItem.defaultProps = { + details: null, + state: null, + LoadingComponent: InlineLoading, +}; + HealthItem.propTypes = { message: PropTypes.string.isRequired, - icon: PropTypes.string.isRequired, - classname: PropTypes.string.isRequired, + details: PropTypes.string, + state: PropTypes.string, + LoadingComponent: PropTypes.oneOfType([PropTypes.node, PropTypes.func]), }; diff --git a/src/components/Dashboard/Health/strings.js b/src/components/Dashboard/Health/strings.js new file mode 100644 index 000000000..d7e5a4a3f --- /dev/null +++ b/src/components/Dashboard/Health/strings.js @@ -0,0 +1,10 @@ +export const OCS_HEALTHY = 'OCS is healthy'; +export const OCS_DEGRADED = 'OCS health is degraded'; +export const OCS_ERROR = 'OCS health is in error state'; +export const OCS_UNKNOWN = 'OCS is not available'; + +export const CNV_HEALTHY = 'CNV is healthy'; +export const CNV_ERROR = 'CNV is in error state'; + +export const OCP_HEALTHY = 'OpenShift is healthy'; +export const OCP_ERROR = 'Openshift is in error state'; diff --git a/src/components/Dashboard/Health/tests/__snapshots__/HealthBody.test.js.snap b/src/components/Dashboard/Health/tests/__snapshots__/HealthBody.test.js.snap index 8d1d5c332..d67d8556a 100644 --- a/src/components/Dashboard/Health/tests/__snapshots__/HealthBody.test.js.snap +++ b/src/components/Dashboard/Health/tests/__snapshots__/HealthBody.test.js.snap @@ -5,9 +5,12 @@ exports[` renders correctly 1`] = ` className="kubevirt-health__body" >
`; diff --git a/src/components/Dashboard/Health/tests/__snapshots__/HealthItem.test.js.snap b/src/components/Dashboard/Health/tests/__snapshots__/HealthItem.test.js.snap index 2fe582593..d54217e57 100644 --- a/src/components/Dashboard/Health/tests/__snapshots__/HealthItem.test.js.snap +++ b/src/components/Dashboard/Health/tests/__snapshots__/HealthItem.test.js.snap @@ -2,18 +2,22 @@ exports[` renders correctly 1`] = `
- - - OCS is Healthy - + +
+
+ + OCS is Healthy + +
`; diff --git a/src/components/Dashboard/Health/utils.js b/src/components/Dashboard/Health/utils.js new file mode 100644 index 000000000..5a9aa0cc3 --- /dev/null +++ b/src/components/Dashboard/Health/utils.js @@ -0,0 +1,58 @@ +import { get } from 'lodash'; + +import { LOADING_STATE, OK_STATE, ERROR_STATE, WARNING_STATE } from './HealthItem'; +import { + OCS_HEALTHY, + OCS_DEGRADED, + OCS_ERROR, + OCS_UNKNOWN, + OCP_HEALTHY, + OCP_ERROR, + CNV_HEALTHY, + CNV_ERROR, +} from './strings'; + +export const getKubevirtHealthState = kubevirtHealth => { + if (!kubevirtHealth) { + return { state: LOADING_STATE }; + } + return get(kubevirtHealth, 'apiserver.connectivity') === 'ok' + ? { message: CNV_HEALTHY, state: OK_STATE } + : { message: CNV_ERROR, state: ERROR_STATE }; +}; + +export const getK8sHealthState = k8sHealth => { + if (!k8sHealth) { + return { state: LOADING_STATE }; + } + return get(k8sHealth, 'response') === 'ok' + ? { message: OCP_HEALTHY, state: OK_STATE } + : { message: OCP_ERROR, state: ERROR_STATE }; +}; + +const OCSHealthStatus = { + 0: { + message: OCS_HEALTHY, + state: OK_STATE, + }, + 1: { + message: OCS_DEGRADED, + state: WARNING_STATE, + }, + 2: { + message: OCS_ERROR, + state: ERROR_STATE, + }, + 3: { + message: OCS_UNKNOWN, + state: ERROR_STATE, + }, +}; + +export const getOCSHealthState = ocsResponse => { + if (!ocsResponse) { + return { state: LOADING_STATE }; + } + const value = get(ocsResponse, 'result[0].value[1]'); + return OCSHealthStatus[value] || OCSHealthStatus[3]; +}; diff --git a/src/components/Dashboard/SubsystemHealth/SubsystemHealth.js b/src/components/Dashboard/SubsystemHealth/SubsystemHealth.js new file mode 100644 index 000000000..0ee4da29b --- /dev/null +++ b/src/components/Dashboard/SubsystemHealth/SubsystemHealth.js @@ -0,0 +1,48 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import { HealthItem } from '../Health/HealthItem'; +import { HealthBody } from '../Health/HealthBody'; + +import { InlineLoading } from '../../Loading'; + +export const SubsystemHealth = ({ k8sHealth, kubevirtHealth, cephHealth, LoadingComponent }) => ( +
+ + +
+ +
+ + +
+); + +SubsystemHealth.defaultProps = { + k8sHealth: null, + kubevirtHealth: null, + cephHealth: null, + LoadingComponent: InlineLoading, +}; + +SubsystemHealth.propTypes = { + k8sHealth: PropTypes.object, + kubevirtHealth: PropTypes.object, + cephHealth: PropTypes.object, + LoadingComponent: PropTypes.oneOfType([PropTypes.node, PropTypes.func]), +}; diff --git a/src/components/Dashboard/SubsystemHealth/fixtures/SubsystemHealth.fixture.js b/src/components/Dashboard/SubsystemHealth/fixtures/SubsystemHealth.fixture.js new file mode 100644 index 000000000..10b90fffa --- /dev/null +++ b/src/components/Dashboard/SubsystemHealth/fixtures/SubsystemHealth.fixture.js @@ -0,0 +1,25 @@ +import { SubsystemHealth } from '../SubsystemHealth'; +import { OK_STATE, WARNING_STATE, ERROR_STATE } from '../../Health/HealthItem'; +import { OCP_HEALTHY, CNV_ERROR, OCS_DEGRADED } from '../../Health/strings'; + +export const healthData = { + k8sHealth: { + state: OK_STATE, + message: OCP_HEALTHY, + }, + cephHealth: { + message: OCS_DEGRADED, + state: WARNING_STATE, + }, + kubevirtHealth: { + state: ERROR_STATE, + message: CNV_ERROR, + }, +}; + +export default [ + { + component: SubsystemHealth, + props: { ...healthData }, + }, +]; diff --git a/src/components/Dashboard/SubsystemHealth/index.js b/src/components/Dashboard/SubsystemHealth/index.js new file mode 100644 index 000000000..1c59be775 --- /dev/null +++ b/src/components/Dashboard/SubsystemHealth/index.js @@ -0,0 +1 @@ +export { SubsystemHealth } from './SubsystemHealth'; diff --git a/src/components/Dashboard/SubsystemHealth/tests/SubsystemHealth.test.js b/src/components/Dashboard/SubsystemHealth/tests/SubsystemHealth.test.js new file mode 100644 index 000000000..25de261f0 --- /dev/null +++ b/src/components/Dashboard/SubsystemHealth/tests/SubsystemHealth.test.js @@ -0,0 +1,14 @@ +import React from 'react'; +import { render } from 'enzyme'; + +import { SubsystemHealth } from '../SubsystemHealth'; +import { default as HealthFixtures } from '../fixtures/SubsystemHealth.fixture'; + +const testHealthOverview = () => ; + +describe('', () => { + it('renders correctly', () => { + const component = render(testHealthOverview()); + expect(component).toMatchSnapshot(); + }); +}); diff --git a/src/components/Dashboard/SubsystemHealth/tests/__snapshots__/SubsystemHealth.test.js.snap b/src/components/Dashboard/SubsystemHealth/tests/__snapshots__/SubsystemHealth.test.js.snap new file mode 100644 index 000000000..f09b061ab --- /dev/null +++ b/src/components/Dashboard/SubsystemHealth/tests/__snapshots__/SubsystemHealth.test.js.snap @@ -0,0 +1,88 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` renders correctly 1`] = ` +
+
+
+
+
+
+ + OpenShift + +
+ OpenShift is healthy +
+
+
+
+
+
+
+
+ + CNV + +
+ CNV is in error state +
+
+
+
+
+
+
+
+ + Ceph + +
+ OCS health is degraded +
+
+
+
+
+`; diff --git a/src/components/StorageOverview/OCSHealth/Health.js b/src/components/StorageOverview/OCSHealth/Health.js index 5b8b0637e..44767d157 100644 --- a/src/components/StorageOverview/OCSHealth/Health.js +++ b/src/components/StorageOverview/OCSHealth/Health.js @@ -1,6 +1,5 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { get } from 'lodash'; import { DashboardCard, @@ -9,50 +8,21 @@ import { DashboardCardTitle, } from '../../Dashboard/DashboardCard'; import { StorageOverviewContextGenericConsumer } from '../StorageOverviewContext'; -import { HealthItem } from '../../Dashboard/Health/HealthItem'; +import { HealthItem, LOADING_STATE } from '../../Dashboard/Health/HealthItem'; import { HealthBody } from '../../Dashboard/Health/HealthBody'; - -import { HEALTHY, DEGRADED, ERROR, UNKNOWN } from './strings'; import { InlineLoading } from '../../Loading'; +import { getOCSHealthState } from '../../Dashboard/Health/utils'; -const OCSHealthStatus = { - 0: { - message: HEALTHY, - iconname: 'check-circle', - classname: 'ok', - }, - 1: { - message: DEGRADED, - iconname: 'exclamation-circle', - classname: 'warning', - }, - 2: { - message: ERROR, - iconname: 'exclamation-triangle', - classname: 'error', - }, - 3: { - message: UNKNOWN, - iconname: 'exclamation-triangle', - classname: 'error', - }, -}; - -export const OCSHealth = ({ data, loaded }) => { - const value = get(data, 'healthy.data.result[0].value[1]'); - const status = OCSHealthStatus[value] || OCSHealthStatus[3]; +export const OCSHealth = ({ response, LoadingComponent }) => { + const state = getOCSHealthState(response); return ( Health - + - + @@ -60,12 +30,13 @@ export const OCSHealth = ({ data, loaded }) => { }; OCSHealth.defaultProps = { - loaded: false, + response: null, + LoadingComponent: InlineLoading, }; OCSHealth.propTypes = { - data: PropTypes.object.isRequired, - loaded: PropTypes.bool, + response: PropTypes.object, + LoadingComponent: PropTypes.oneOfType([PropTypes.node, PropTypes.func]), }; const OCSHealthConnected = () => ( diff --git a/src/components/StorageOverview/OCSHealth/strings.js b/src/components/StorageOverview/OCSHealth/strings.js deleted file mode 100644 index e7095a562..000000000 --- a/src/components/StorageOverview/OCSHealth/strings.js +++ /dev/null @@ -1,4 +0,0 @@ -export const HEALTHY = 'OCS is Healthy'; -export const DEGRADED = 'OCS health is Degraded'; -export const ERROR = 'OCS health is in Error State'; -export const UNKNOWN = 'Not available'; diff --git a/src/components/StorageOverview/OCSHealth/tests/__snapshots__/Health.test.js.snap b/src/components/StorageOverview/OCSHealth/tests/__snapshots__/Health.test.js.snap index fa24a021f..1a2bf5f18 100644 --- a/src/components/StorageOverview/OCSHealth/tests/__snapshots__/Health.test.js.snap +++ b/src/components/StorageOverview/OCSHealth/tests/__snapshots__/Health.test.js.snap @@ -16,22 +16,10 @@ exports[` renders correctly 1`] = `
-
+
-
+ class="spinner spinner-md blank-slate-pf-icon" + />