Skip to content

Commit 74918e2

Browse files
author
Julien MEZIERE
committed
ui/dashboard: Add network plane health in Network panel
Remove the ServiceItem from DashboardServices and create the HealthItem component with it Add DashboardPlane component containing 2 HealthItems Add tests for the new DashbordPlane component history.push replaced by history.replace in the HealthItem component useless comment removed in HealthItem component Ref: #3511
1 parent 6fd226b commit 74918e2

File tree

10 files changed

+408
-154
lines changed

10 files changed

+408
-154
lines changed

shell-ui/src/alerts/alertHooks.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export const getVolumesAlertSelectors = (): FilterLabels => {
1919

2020
export const getNetworksAlertSelectors = (): FilterLabels => {
2121
return {
22-
alertname: ['ControlPlaneNetworkDegraded', 'WorkloadPlaneNetworkDegraded'],
22+
alertname: ['NetworkDegraded'],
2323
};
2424
};
2525

ui/src/components/DashboardNetwork.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import React from 'react';
2+
import styled from 'styled-components';
3+
import { useIntl } from 'react-intl';
4+
5+
import { spacing } from '@scality/core-ui/dist/style/theme';
6+
import { PageSubtitle } from '../components/style/CommonLayoutStyle';
7+
8+
import DashboardPlane from './DashboardPlane';
9+
10+
export const NetworkContainer = styled.div`
11+
padding: ${spacing.sp2} ${spacing.sp4};
12+
display: flex;
13+
flex-direction: column;
14+
flex-grow: 1;
15+
`;
16+
17+
export const PanelActions = styled.div`
18+
display: flex;
19+
padding: ${spacing.sp4};
20+
align-items: center;
21+
justify-content: space-between;
22+
`;
23+
24+
const DashboardNetwork = () => {
25+
const intl = useIntl();
26+
27+
return (
28+
<NetworkContainer>
29+
<PanelActions>
30+
<PageSubtitle>{intl.formatMessage({ id: 'network' })}</PageSubtitle>
31+
</PanelActions>
32+
<DashboardPlane />
33+
</NetworkContainer>
34+
);
35+
};
36+
37+
export default DashboardNetwork;

ui/src/components/DashboardPlane.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import React from 'react';
2+
import { useIntl } from 'react-intl';
3+
import styled from 'styled-components';
4+
import {
5+
useAlertLibrary,
6+
useHighestSeverityAlerts,
7+
highestAlertToStatus,
8+
} from '../containers/AlertProvider';
9+
import { PageSubtitle } from './style/CommonLayoutStyle';
10+
import { PanelActions, NetworkContainer } from './DashboardNetwork';
11+
import HealthItem from './HealthItem.js';
12+
import { spacing } from '@scality/core-ui/dist/style/theme';
13+
14+
const PlanesContainer = styled.div`
15+
padding-left: ${spacing.sp8};
16+
display: flex;
17+
flex-direction: row;
18+
`;
19+
20+
const PlaneContainer = styled.div`
21+
display: flex;
22+
flex-direction: row;
23+
margin-right: ${spacing.sp40};
24+
`;
25+
26+
const DashboardPlane = () => {
27+
const intl = useIntl();
28+
const alertsLibrary = useAlertLibrary();
29+
30+
const planesHighestSecurityAlert = useHighestSeverityAlerts(
31+
alertsLibrary.getNetworksAlertSelectors(),
32+
);
33+
const planesStatus = highestAlertToStatus(planesHighestSecurityAlert);
34+
35+
return (
36+
<NetworkContainer>
37+
<PanelActions>
38+
<PageSubtitle>Planes</PageSubtitle>
39+
</PanelActions>
40+
<PlanesContainer>
41+
<PlaneContainer>
42+
<HealthItem
43+
label={intl.formatMessage({ id: 'control_plane' })}
44+
status={planesStatus}
45+
alerts={planesHighestSecurityAlert}
46+
showArrow={false}
47+
/>
48+
</PlaneContainer>
49+
<PlaneContainer>
50+
<HealthItem
51+
label={intl.formatMessage({ id: 'workload_plane' })}
52+
status={planesStatus}
53+
alerts={planesHighestSecurityAlert}
54+
showArrow={false}
55+
/>
56+
</PlaneContainer>
57+
</PlanesContainer>
58+
</NetworkContainer>
59+
);
60+
};
61+
62+
export default DashboardPlane;
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
//@flow
2+
import React from 'react';
3+
import { screen } from '@testing-library/react';
4+
import DashboardPlane from './DashboardPlane';
5+
import { render } from './__TEST__/util';
6+
import type { Alert } from '../services/alertUtils';
7+
import { useHighestSeverityAlerts } from '../containers/AlertProvider';
8+
import {
9+
STATUS_WARNING,
10+
STATUS_CRITICAL,
11+
STATUS_HEALTH,
12+
} from '../constants.js';
13+
14+
const alertsCritical = [
15+
{
16+
id: 'alert1',
17+
severity: STATUS_CRITICAL,
18+
startsAt: '2021-07-28T10:36:24.293Z',
19+
},
20+
];
21+
const alertsWarning = [
22+
{
23+
id: 'alert2',
24+
severity: STATUS_WARNING,
25+
startsAt: '2021-07-28T10:36:24.293Z',
26+
},
27+
];
28+
const noAlerts = [];
29+
30+
jest.mock('../containers/AlertProvider', () => ({
31+
__esModule: true,
32+
default: ({ children }) => <>{children}</>,
33+
useHighestSeverityAlerts: jest.fn(),
34+
useAlertLibrary: () => ({
35+
getNetworksAlertSelectors: () => {},
36+
}),
37+
highestAlertToStatus: (alerts?: Alert[]): string => {
38+
return (alerts?.[0] && ((alerts[0].severity: any): string)) || 'healthy';
39+
},
40+
}));
41+
42+
jest.mock('../containers/ConfigProvider', () => ({
43+
__esModule: true,
44+
default: ({ children }) => <>{children}</>,
45+
useLinkOpener: () => ({
46+
openLink: jest.fn(),
47+
}),
48+
useDiscoveredViews: () => [
49+
{
50+
app: {
51+
kind: '',
52+
name: '',
53+
version: '',
54+
url: '',
55+
appHistoryBasePath: '',
56+
},
57+
isFederated: true,
58+
view: { path: '/alerts' },
59+
},
60+
],
61+
}));
62+
63+
const NB_ITEMS = 2;
64+
65+
describe("the dashboard network's plane panel", () => {
66+
test("displays the network's plane panel and display 2 green statuses when no alerts are present", async () => {
67+
// Have to any type jest.fn function to avoid Flow warning for mockImplementation()
68+
(useHighestSeverityAlerts: any).mockImplementation(() => noAlerts);
69+
render(<DashboardPlane />);
70+
expect(screen.getAllByLabelText(`status ${STATUS_HEALTH}`)).toHaveLength(
71+
NB_ITEMS,
72+
);
73+
});
74+
75+
test('displays 2 warning statuses when warning alerts are present as well as link to the alerts page', async () => {
76+
// Have to any type jest.fn function to avoid Flow warning for mockImplementation()
77+
(useHighestSeverityAlerts: any).mockImplementation(() => alertsWarning);
78+
79+
// Render
80+
render(<DashboardPlane />);
81+
82+
// Verify
83+
expect(screen.getAllByLabelText(`status ${STATUS_WARNING}`)).toHaveLength(
84+
NB_ITEMS,
85+
);
86+
expect(screen.getAllByTestId('alert-link')).toHaveLength(NB_ITEMS);
87+
});
88+
89+
test('displays 2 critical statuses when warning alerts are present as well as link to the alerts page', async () => {
90+
// Have to any type jest.fn function to avoid Flow warning for mockImplementation()
91+
(useHighestSeverityAlerts: any).mockImplementation(() => alertsCritical);
92+
93+
// Render
94+
render(<DashboardPlane />);
95+
96+
// Verify
97+
expect(screen.getAllByLabelText(`status ${STATUS_CRITICAL}`)).toHaveLength(
98+
NB_ITEMS,
99+
);
100+
expect(screen.getAllByTestId('alert-link')).toHaveLength(NB_ITEMS);
101+
});
102+
});

0 commit comments

Comments
 (0)