Skip to content

Commit 6f89b1b

Browse files
committed
Merge remote-tracking branch 'upstream/main' into RHINENG-20701
2 parents 6f6b4aa + 645607b commit 6f89b1b

File tree

12 files changed

+569
-241
lines changed

12 files changed

+569
-241
lines changed

web/src/components/Incidents/AlertsChart/AlertsChart.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { IncidentsTooltip } from '../IncidentsTooltip';
2727
import { createAlertsChartBars, generateDateArray, generateAlertsDateArray } from '../utils';
2828
import { dateTimeFormatter } from '../../console/utils/datetime';
2929
import { useTranslation } from 'react-i18next';
30+
import { AlertsChartBar } from '../model';
3031
import { setAlertsAreLoading } from '../../../store/actions';
3132
import { MonitoringState } from '../../../store/store';
3233

@@ -56,7 +57,7 @@ const AlertsChart = ({ theme }: { theme: 'light' | 'dark' }) => {
5657
return generateAlertsDateArray(alertsData);
5758
}, [alertsData]);
5859

59-
const chartData = useMemo(() => {
60+
const chartData: AlertsChartBar[][] = useMemo(() => {
6061
if (!Array.isArray(alertsData) || alertsData.length === 0) return [];
6162
return alertsData.map((alert) => createAlertsChartBars(alert));
6263
}, [alertsData]);
@@ -89,6 +90,11 @@ const AlertsChart = ({ theme }: { theme: 'light' | 'dark' }) => {
8990
return () => observer();
9091
}, [handleResize]);
9192

93+
const getOpacity = useCallback((datum) => {
94+
const opacity = datum.silenced ? 0.3 : 1;
95+
return opacity;
96+
}, []);
97+
9298
return (
9399
<Card className="alerts-chart-card" style={{ overflow: 'visible' }}>
94100
<div ref={containerRef}>
@@ -128,7 +134,8 @@ const AlertsChart = ({ theme }: { theme: 'light' | 'dark' }) => {
128134
Layer: ${datum.layer ? datum.layer : '---'}
129135
Component: ${datum.component}
130136
Start: ${startDate}
131-
End: ${endDate}`;
137+
End: ${endDate};
138+
Silenced: ${datum.silenced}`;
132139
}}
133140
/>
134141
}
@@ -193,7 +200,7 @@ const AlertsChart = ({ theme }: { theme: 'light' | 'dark' }) => {
193200
data: {
194201
fill: ({ datum }) => datum.fill,
195202
stroke: ({ datum }) => datum.fill,
196-
fillOpacity: ({ datum }) => (datum.nodata ? 0 : 1),
203+
fillOpacity: ({ datum }) => (datum.nodata ? 0 : getOpacity(datum)),
197204
cursor: 'pointer',
198205
},
199206
}}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import React from 'react';
2+
import { Tooltip } from '@patternfly/react-core';
3+
import { BellIcon, CheckIcon, BellSlashIcon } from '@patternfly/react-icons';
4+
import { GroupedAlert, IncidentsDetailsAlert } from './model';
5+
6+
interface IncidentAlertStateIconProps {
7+
alertDetails: IncidentsDetailsAlert;
8+
showTooltip?: boolean;
9+
}
10+
11+
const getAlertState = (alertDetails: IncidentsDetailsAlert): 'firing' | 'resolved' | 'silenced' => {
12+
if (alertDetails.silenced) {
13+
return 'silenced';
14+
}
15+
if (alertDetails.resolved) {
16+
return 'resolved';
17+
}
18+
19+
return 'firing';
20+
};
21+
22+
export const IncidentAlertStateIcon: React.FC<IncidentAlertStateIconProps> = ({
23+
alertDetails,
24+
showTooltip = true,
25+
}) => {
26+
const state = getAlertState(alertDetails);
27+
28+
const getIconAndTooltip = () => {
29+
switch (state) {
30+
case 'firing':
31+
return {
32+
icon: <BellIcon />,
33+
tooltip: 'Firing',
34+
};
35+
case 'resolved':
36+
return {
37+
icon: <CheckIcon />,
38+
tooltip: 'Resolved',
39+
};
40+
case 'silenced':
41+
return {
42+
icon: <BellSlashIcon style={{ color: 'var(--pf-t--global--icon--color--disabled)' }} />,
43+
tooltip: 'Silenced',
44+
};
45+
default:
46+
return {
47+
icon: <BellIcon />,
48+
tooltip: 'Unknown',
49+
};
50+
}
51+
};
52+
53+
const { icon, tooltip } = getIconAndTooltip();
54+
55+
if (showTooltip) {
56+
return <Tooltip content={tooltip}>{icon}</Tooltip>;
57+
}
58+
59+
return icon;
60+
};
61+
62+
interface GroupedAlertStateIconProps {
63+
groupedAlert: GroupedAlert;
64+
showTooltip?: boolean;
65+
}
66+
const getGroupedAlertState = (groupedAlert: GroupedAlert): 'firing' | 'resolved' | 'silenced' => {
67+
if (groupedAlert.alertstate === 'silenced') {
68+
return 'silenced';
69+
}
70+
if (groupedAlert.alertstate === 'resolved') {
71+
return 'resolved';
72+
}
73+
return 'firing';
74+
};
75+
76+
export const GroupedAlertStateIcon: React.FC<GroupedAlertStateIconProps> = ({
77+
groupedAlert,
78+
showTooltip = true,
79+
}) => {
80+
const state = getGroupedAlertState(groupedAlert);
81+
82+
const getIconAndTooltip = () => {
83+
switch (state) {
84+
case 'firing':
85+
return {
86+
icon: <BellIcon />,
87+
tooltip: 'Firing',
88+
};
89+
case 'resolved':
90+
return {
91+
icon: <CheckIcon />,
92+
tooltip: 'Resolved',
93+
};
94+
case 'silenced':
95+
return {
96+
icon: <BellSlashIcon style={{ color: 'var(--pf-t--global--icon--color--disabled)' }} />,
97+
tooltip: 'Silenced',
98+
};
99+
default:
100+
return {
101+
icon: <BellIcon />,
102+
tooltip: 'Unknown',
103+
};
104+
}
105+
};
106+
107+
const { icon, tooltip } = getIconAndTooltip();
108+
109+
if (showTooltip) {
110+
return <Tooltip content={tooltip}>{icon}</Tooltip>;
111+
}
112+
113+
return icon;
114+
};

web/src/components/Incidents/IncidentsDetailsRowTable.tsx

Lines changed: 60 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,79 @@
11
import { Table, Thead, Tr, Th, Tbody, Td } from '@patternfly/react-table';
2-
import {
3-
GreenCheckCircleIcon,
4-
ResourceIcon,
5-
Timestamp,
6-
useActiveNamespace,
7-
} from '@openshift-console/dynamic-plugin-sdk';
8-
import { BellIcon } from '@patternfly/react-icons';
2+
import { ResourceIcon, Timestamp, useActiveNamespace } from '@openshift-console/dynamic-plugin-sdk';
93
import { Bullseye, Spinner } from '@patternfly/react-core';
104
import { Link } from 'react-router-dom';
115
import { ALL_NAMESPACES_KEY, RuleResource } from '../utils';
126
import { useTranslation } from 'react-i18next';
137
import { getRuleUrl, usePerspective } from '../hooks/usePerspective';
148
import './incidents-styles.css';
159
import { SeverityBadge } from '../alerting/AlertUtils';
10+
import { Alert, IncidentsDetailsAlert } from './model';
11+
import { IncidentAlertStateIcon } from './IncidentAlertStateIcon';
12+
import { useMemo } from 'react';
1613

17-
const IncidentsDetailsRowTable = ({ alerts }) => {
14+
interface IncidentsDetailsRowTableProps {
15+
alerts: Alert[];
16+
}
17+
18+
const IncidentsDetailsRowTable = ({ alerts }: IncidentsDetailsRowTableProps) => {
1819
const [namespace, setNamespace] = useActiveNamespace();
1920
const { perspective } = usePerspective();
2021
const { t } = useTranslation(process.env.I18N_NAMESPACE);
2122

23+
const sortedAndMappedAlerts = useMemo(() => {
24+
if (alerts && alerts.length > 0) {
25+
return [...alerts]
26+
.sort(
27+
(a: IncidentsDetailsAlert, b: IncidentsDetailsAlert) =>
28+
a.alertsStartFiring - b.alertsStartFiring,
29+
)
30+
.map((alertDetails: IncidentsDetailsAlert, rowIndex) => {
31+
return (
32+
<Tr key={rowIndex}>
33+
<Td dataLabel="expanded-details-alertname">
34+
<ResourceIcon kind={RuleResource.kind} />
35+
<Link
36+
to={getRuleUrl(perspective, alertDetails?.rule, namespace)}
37+
onClick={() => setNamespace(ALL_NAMESPACES_KEY)}
38+
>
39+
{alertDetails.alertname}
40+
</Link>
41+
</Td>
42+
<Td dataLabel="expanded-details-namespace">{alertDetails.namespace || '---'}</Td>
43+
<Td dataLabel="expanded-details-severity">
44+
<SeverityBadge severity={alertDetails.severity} />
45+
</Td>
46+
<Td dataLabel="expanded-details-firingstart">
47+
<Timestamp timestamp={alertDetails.alertsStartFiring} />
48+
</Td>
49+
<Td dataLabel="expanded-details-firingend">
50+
{!alertDetails.resolved ? (
51+
'---'
52+
) : (
53+
<Timestamp timestamp={alertDetails.alertsEndFiring} />
54+
)}
55+
</Td>
56+
<Td dataLabel="expanded-details-alertstate">
57+
<IncidentAlertStateIcon alertDetails={alertDetails} />
58+
</Td>
59+
</Tr>
60+
);
61+
});
62+
}
63+
64+
return null;
65+
}, [alerts, perspective, namespace, setNamespace]);
66+
2267
return (
2368
<Table borders={false} variant="compact">
2469
<Thead>
2570
<Tr>
26-
<Th width={25}>{t('Alert Rule')}</Th>
27-
<Th width={15}>{t('Namespace')}</Th>
28-
<Th width={10}>{t('Severity')}</Th>
29-
<Th width={10}>{t('State')}</Th>
30-
<Th width={20}>{t('Start')}</Th>
31-
<Th width={20}>{t('End')}</Th>
71+
<Th width={25}>{t('Alert')}</Th>
72+
<Th>{t('Namespace')}</Th>
73+
<Th>{t('Severity')}</Th>
74+
<Th>{t('Start')}</Th>
75+
<Th>{t('End')}</Th>
76+
<Th>{t('State')}</Th>
3277
</Tr>
3378
</Thead>
3479
<Tbody>
@@ -37,49 +82,7 @@ const IncidentsDetailsRowTable = ({ alerts }) => {
3782
<Spinner aria-label="incidents-chart-spinner" />
3883
</Bullseye>
3984
) : (
40-
alerts?.map((alertDetails, rowIndex) => {
41-
return (
42-
<Tr key={rowIndex}>
43-
<Td dataLabel="expanded-details-alertname">
44-
<ResourceIcon kind={RuleResource.kind} />
45-
<Link
46-
to={getRuleUrl(perspective, alertDetails?.rule, namespace)}
47-
// Set to ALL_NAMESPACES to ensure that the alert rule is found
48-
onClick={() => setNamespace(ALL_NAMESPACES_KEY)}
49-
>
50-
{alertDetails.alertname}
51-
</Link>
52-
</Td>
53-
<Td dataLabel="expanded-details-namespace">{alertDetails.namespace || '---'}</Td>
54-
<Td dataLabel="expanded-details-severity">
55-
<SeverityBadge severity={alertDetails.severity} />
56-
</Td>
57-
<Td dataLabel="expanded-details-alertstate">
58-
{!alertDetails.resolved ? (
59-
<>
60-
<BellIcon />
61-
<span className="expanded-details-text-margin">Firing</span>
62-
</>
63-
) : (
64-
<>
65-
<GreenCheckCircleIcon />
66-
<span className="expanded-details-text-margin">Resolved</span>
67-
</>
68-
)}
69-
</Td>
70-
<Td dataLabel="expanded-details-firingstart">
71-
<Timestamp simple={true} timestamp={alertDetails.alertsStartFiring} />
72-
</Td>
73-
<Td dataLabel="expanded-details-firingend">
74-
{!alertDetails.resolved ? (
75-
'---'
76-
) : (
77-
<Timestamp simple={true} timestamp={alertDetails.alertsEndFiring} />
78-
)}
79-
</Td>
80-
</Tr>
81-
);
82-
})
85+
sortedAndMappedAlerts
8386
)}
8487
</Tbody>
8588
</Table>

web/src/components/Incidents/IncidentsPage.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,11 +136,12 @@ const IncidentsPage = () => {
136136
(state: MonitoringState) => state.plugins.mcp.incidentsData.filteredIncidentsData,
137137
);
138138

139+
const selectedGroupId = incidentsActiveFilters.groupId?.[0] ?? undefined;
140+
139141
const incidentPageFilterTypeSelected = useSelector(
140142
(state: MonitoringState) => state.plugins.mcp.incidentsData.incidentPageFilterType,
141143
);
142144

143-
const selectedGroupId = incidentsActiveFilters.groupId?.[0] ?? undefined;
144145
useEffect(() => {
145146
const hasUrlParams = Object.keys(urlParams).length > 0;
146147
if (hasUrlParams) {
@@ -218,7 +219,7 @@ const IncidentsPage = () => {
218219
const aggregatedData = results.flat();
219220
dispatch(
220221
setAlertsData({
221-
alertsData: processAlerts(aggregatedData, incidentForAlertProcessing),
222+
alertsData: processAlerts(aggregatedData, incidentForAlertProcessing, rules),
222223
}),
223224
);
224225
if (!isEmpty(filteredData)) {

0 commit comments

Comments
 (0)