зеркало из https://github.com/mozilla/treeherder.git
Bug 1734324 - Allow defining conditions to flag alerts (#7291)
* Bug 1734324 - Allow defining conditions to flag alerts * Bug 1734324 - Added tests * Bug 1734324 - Address review changes
This commit is contained in:
Родитель
86d5d2d566
Коммит
3a4b09a54f
|
@ -282,6 +282,72 @@ test('Noise profile OK', async () => {
|
|||
expect(message).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('One flame icon for alert magnitude between 100 and 199 percentage', async () => {
|
||||
testAlert.is_regression = true;
|
||||
testAlert.amount_pct = 143;
|
||||
|
||||
const { getByTestId } = alertTableRowTest({
|
||||
alert: testAlert,
|
||||
tags: [],
|
||||
});
|
||||
|
||||
const flamesIconsList = await waitFor(() => getByTestId('flame-icons'));
|
||||
expect(flamesIconsList.children).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('Two flame icons for alert magnitude between 200 and 299 percentage', async () => {
|
||||
testAlert.is_regression = true;
|
||||
testAlert.amount_pct = 254;
|
||||
|
||||
const { getByTestId } = alertTableRowTest({
|
||||
alert: testAlert,
|
||||
tags: [],
|
||||
});
|
||||
|
||||
const flamesIconsList = await waitFor(() => getByTestId('flame-icons'));
|
||||
expect(flamesIconsList.children).toHaveLength(2);
|
||||
});
|
||||
|
||||
test('Three flame icons for alert magnitude of 300 percentage', async () => {
|
||||
testAlert.is_regression = true;
|
||||
testAlert.amount_pct = 300;
|
||||
|
||||
const { getByTestId } = alertTableRowTest({
|
||||
alert: testAlert,
|
||||
tags: [],
|
||||
});
|
||||
|
||||
const flamesIconsList = await waitFor(() => getByTestId('flame-icons'));
|
||||
expect(flamesIconsList.children).toHaveLength(3);
|
||||
});
|
||||
|
||||
test('Three flame icons and a plus icon for alert magnitude over 300 percentage', async () => {
|
||||
testAlert.is_regression = true;
|
||||
testAlert.amount_pct = 430;
|
||||
|
||||
const { getByTestId } = alertTableRowTest({
|
||||
alert: testAlert,
|
||||
tags: [],
|
||||
});
|
||||
|
||||
const flamesIconsList = await waitFor(() => getByTestId('flame-icons'));
|
||||
expect(flamesIconsList.children).toHaveLength(4);
|
||||
});
|
||||
|
||||
test('One green flame icon for alert magnitude equal to 100 percentage and new value equal to 0', async () => {
|
||||
testAlert.is_regression = false;
|
||||
testAlert.amount_pct = 100;
|
||||
testAlert.new_value = 0;
|
||||
|
||||
const { getByTestId } = alertTableRowTest({
|
||||
alert: testAlert,
|
||||
tags: [],
|
||||
});
|
||||
|
||||
const flamesIconsList = await waitFor(() => getByTestId('flame-icons'));
|
||||
expect(flamesIconsList.children).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('Documentation link is available for talos framework', async () => {
|
||||
const { getByTestId } = alertTableRowTest();
|
||||
expect(getByTestId('docs')).toHaveAttribute(
|
||||
|
|
|
@ -555,3 +555,29 @@ li.pagination-active.active > button {
|
|||
.cursor-pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.information-container {
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.information-container .option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.information-container .option .icon {
|
||||
margin: 0px 2px 5px 2px;
|
||||
color: #dc3545;
|
||||
}
|
||||
|
||||
.information-container .option .icon-green-flame {
|
||||
color: #2da745;
|
||||
}
|
||||
|
||||
.information-container .option .icon-plus {
|
||||
font-size: 12px;
|
||||
color: #dc3545;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ export default class AlertTable extends React.Component {
|
|||
currentSort: tableSort.default,
|
||||
},
|
||||
NoiseProfile: {
|
||||
name: 'Noise Profile',
|
||||
name: 'Information',
|
||||
sortValue: 'noise_profile',
|
||||
currentSort: tableSort.default,
|
||||
},
|
||||
|
|
|
@ -9,6 +9,8 @@ import {
|
|||
faUser,
|
||||
faCheck,
|
||||
faChartLine,
|
||||
faFire,
|
||||
faPlus,
|
||||
} from '@fortawesome/free-solid-svg-icons';
|
||||
import { faStar as faStarRegular } from '@fortawesome/free-regular-svg-icons';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
@ -44,9 +46,16 @@ export default class AlertTableRow extends React.Component {
|
|||
this.state = {
|
||||
starred: this.props.alert.starred,
|
||||
checkboxSelected: false,
|
||||
icons: [],
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { alert } = this.props;
|
||||
|
||||
this.showCriticalMagnitudeIcons(alert);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const { selectedAlerts, alert } = this.props;
|
||||
|
||||
|
@ -264,9 +273,75 @@ export default class AlertTableRow extends React.Component {
|
|||
return `./comparesubtest${createQueryParams(urlParameters)}`;
|
||||
};
|
||||
|
||||
showCriticalMagnitudeIcons(alert) {
|
||||
const alertMagnitude = Math.round(alert.amount_pct);
|
||||
const alertNewValue = alert.new_value;
|
||||
let numberOfIcons = 0;
|
||||
let exceedsMaximumIcons = false;
|
||||
|
||||
if (alert.is_regression) {
|
||||
if (
|
||||
alertMagnitude >= 100 &&
|
||||
alertNewValue !== 0 &&
|
||||
alertMagnitude < 200
|
||||
) {
|
||||
numberOfIcons = 1;
|
||||
} else if (alertMagnitude >= 200 && alertMagnitude < 300) {
|
||||
numberOfIcons = 2;
|
||||
} else if (alertMagnitude === 300) {
|
||||
numberOfIcons = 3;
|
||||
} else if (alertMagnitude > 300) {
|
||||
numberOfIcons = 3;
|
||||
exceedsMaximumIcons = true;
|
||||
}
|
||||
} else if (alertMagnitude === 100 && alertNewValue === 0) {
|
||||
this.setState((prevState) => ({
|
||||
icons: [
|
||||
...prevState.icons,
|
||||
<SimpleTooltip
|
||||
key={alert.id}
|
||||
text={
|
||||
<FontAwesomeIcon
|
||||
icon={faFire}
|
||||
className="icon-green-flame icon"
|
||||
/>
|
||||
}
|
||||
tooltipText="This should be treated as a regression"
|
||||
/>,
|
||||
],
|
||||
}));
|
||||
}
|
||||
|
||||
for (let i = 0; i < numberOfIcons; i++) {
|
||||
this.setState((prevState) => ({
|
||||
icons: [
|
||||
...prevState.icons,
|
||||
<SimpleTooltip
|
||||
key={i}
|
||||
text={<FontAwesomeIcon icon={faFire} className="icon" />}
|
||||
tooltipText="Magnitude"
|
||||
/>,
|
||||
],
|
||||
}));
|
||||
|
||||
if (exceedsMaximumIcons && i === numberOfIcons - 1) {
|
||||
this.setState((prevState) => ({
|
||||
icons: [
|
||||
...prevState.icons,
|
||||
<FontAwesomeIcon
|
||||
key={i + 1}
|
||||
icon={faPlus}
|
||||
className="icon-plus icon"
|
||||
/>,
|
||||
],
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { user, alert, alertSummary } = this.props;
|
||||
const { starred, checkboxSelected } = this.state;
|
||||
const { starred, checkboxSelected, icons } = this.state;
|
||||
const { repository, framework } = alertSummary;
|
||||
|
||||
const { tags, extra_options: options } = alert.series_signature;
|
||||
|
@ -361,12 +436,23 @@ export default class AlertTableRow extends React.Component {
|
|||
/>
|
||||
</td>
|
||||
<td className="table-width-lg">
|
||||
<BadgeTooltip
|
||||
textClass="detail-hint"
|
||||
text={noiseProfile}
|
||||
tooltipText={noiseProfileTooltip}
|
||||
autohide={false}
|
||||
/>
|
||||
<div className="information-container">
|
||||
<div className="option">
|
||||
<BadgeTooltip
|
||||
textClass="detail-hint"
|
||||
text={noiseProfile}
|
||||
tooltipText={noiseProfileTooltip}
|
||||
autohide={false}
|
||||
/>
|
||||
</div>
|
||||
{icons.length > 0 ? (
|
||||
<div className="option" data-testid="flame-icons">
|
||||
{icons}
|
||||
</div>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
</div>
|
||||
</td>
|
||||
<td className="table-width-lg">
|
||||
<AlertTableTagsOptions alertId={alert.id} items={items} />
|
||||
|
|
|
@ -51,7 +51,7 @@ export default class CollapsableRows extends React.Component {
|
|||
<td />
|
||||
<td />
|
||||
<td />
|
||||
<td className="text-right">
|
||||
<td className="text-right" colSpan="2">
|
||||
<span className="cursor-pointer">
|
||||
<FontAwesomeIcon icon={isOpen ? faAngleUp : faAngleDown} />{' '}
|
||||
{isOpen ? 'Show less alerts' : 'Show more alerts'}
|
||||
|
|
|
@ -179,11 +179,11 @@ export const permaLinkPrefix = 'tableLink';
|
|||
export const maximumVisibleAlertSummaryRows = 26;
|
||||
|
||||
export const noiseProfiles = {
|
||||
SKEWED: 'Samples are heavily found on one side of the mean.',
|
||||
SKEWED: 'Noise Profile: Samples are heavily found on one side of the mean.',
|
||||
OUTLIERS:
|
||||
'There are more outliers than should be expected from a normal distribution.',
|
||||
'Noise Profile: There are more outliers than should be expected from a normal distribution.',
|
||||
MODAL:
|
||||
'There are multiple areas where most values are found rather than only one.',
|
||||
OK: 'No issues were found.',
|
||||
NA: 'Could not compute a noise profile.',
|
||||
'Noise Profile: There are multiple areas where most values are found rather than only one.',
|
||||
OK: 'Noise Profile: No issues were found.',
|
||||
NA: 'Noise Profile: Could not compute a noise profile.',
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче