зеркало из https://github.com/mozilla/treeherder.git
Bug 1718047 - Reorganize alerts view to show data more compact (#7193)
* Compact data in AlertTable * Add sort to Magnitude of Change * Abbreviate next/previous value, fix spacing tags&options * Add unit tests for new/previous value * Rename AlertTableMagnitude to Magnitude
This commit is contained in:
Родитель
8b581baa8d
Коммит
f642a7fd4e
|
@ -0,0 +1,31 @@
|
|||
import React from 'react';
|
||||
import { render, waitFor } from '@testing-library/react';
|
||||
|
||||
import testAlertSummaries from '../../mock/alert_summaries';
|
||||
import Magnitude from '../../../../ui/perfherder/alerts/Magnitude';
|
||||
|
||||
const testAlertSummary = testAlertSummaries[0];
|
||||
const testAlert = testAlertSummary.alerts[0];
|
||||
|
||||
testAlert.prev_value = 1383.38;
|
||||
testAlert.new_value = 1211.78;
|
||||
|
||||
const magnitude = () => {
|
||||
return render(<Magnitude alert={testAlert} />);
|
||||
};
|
||||
|
||||
test('Previous value is abbreviated', async () => {
|
||||
const { getByTestId } = magnitude();
|
||||
|
||||
const previousValue = await waitFor(() => getByTestId('previous-value'));
|
||||
|
||||
expect(previousValue.textContent).toBe('1.4K');
|
||||
});
|
||||
|
||||
test('New value is abbreviated', async () => {
|
||||
const { getByTestId } = magnitude();
|
||||
|
||||
const newValue = await waitFor(() => getByTestId('new-value'));
|
||||
|
||||
expect(newValue.textContent).toBe('1.2K');
|
||||
});
|
|
@ -53,24 +53,8 @@ export default class AlertTable extends React.Component {
|
|||
sortValue: 'tags',
|
||||
currentSort: tableSort.default,
|
||||
},
|
||||
PreviousValue: {
|
||||
name: 'Previous Value',
|
||||
sortValue: 'prev_value',
|
||||
currentSort: tableSort.default,
|
||||
},
|
||||
Comparison: { name: 'Comparison' },
|
||||
NewValue: {
|
||||
name: 'New Value',
|
||||
sortValue: 'new_value',
|
||||
currentSort: tableSort.default,
|
||||
},
|
||||
AbsoluteDifference: {
|
||||
name: 'Absolute Difference',
|
||||
sortValue: 'amount_pct',
|
||||
currentSort: tableSort.default,
|
||||
},
|
||||
Magnitude: {
|
||||
name: 'Magnitude of Difference',
|
||||
name: 'Magnitude of Change',
|
||||
sortValue: 'amount_pct',
|
||||
currentSort: tableSort.default,
|
||||
},
|
||||
|
@ -364,29 +348,10 @@ export default class AlertTable extends React.Component {
|
|||
onChangeSort={this.onChangeSort}
|
||||
/>
|
||||
</th>
|
||||
<th className="align-bottom">
|
||||
{tableConfig.TagsOptions.name}
|
||||
<th className="align-bottom text-nowrap">
|
||||
<span>{tableConfig.TagsOptions.name}</span>
|
||||
<SortButtonDisabled column={tableConfig.TagsOptions} />
|
||||
</th>
|
||||
<th className="align-bottom">
|
||||
<TableColumnHeader
|
||||
column={tableConfig.PreviousValue}
|
||||
onChangeSort={this.onChangeSort}
|
||||
/>
|
||||
</th>
|
||||
<th> </th>
|
||||
<th className="align-bottom">
|
||||
<TableColumnHeader
|
||||
column={tableConfig.NewValue}
|
||||
onChangeSort={this.onChangeSort}
|
||||
/>
|
||||
</th>
|
||||
<th className="align-bottom">
|
||||
<TableColumnHeader
|
||||
column={tableConfig.AbsoluteDifference}
|
||||
onChangeSort={this.onChangeSort}
|
||||
/>
|
||||
</th>
|
||||
<th className="align-bottom">
|
||||
<TableColumnHeader
|
||||
column={tableConfig.Magnitude}
|
||||
|
|
|
@ -22,7 +22,6 @@ import {
|
|||
getSplitTestTitle,
|
||||
} from '../perf-helpers/helpers';
|
||||
import SimpleTooltip from '../../shared/SimpleTooltip';
|
||||
import ProgressBar from '../../shared/ProgressBar';
|
||||
import {
|
||||
alertStatusMap,
|
||||
backfillRetriggeredTitle,
|
||||
|
@ -33,6 +32,7 @@ import {
|
|||
|
||||
import AlertTablePlatform from './AlertTablePlatform';
|
||||
import AlertTableTagsOptions from './AlertTableTagsOptions';
|
||||
import Magnitude from './Magnitude';
|
||||
|
||||
export default class AlertTableRow extends React.Component {
|
||||
constructor(props) {
|
||||
|
@ -145,7 +145,7 @@ export default class AlertTableRow extends React.Component {
|
|||
<span className={statusColor}>{alertStatus}</span>
|
||||
{alert.related_summary_id && this.getReassignment(alert)}
|
||||
{alert.backfill_record ? (
|
||||
<span className="text-darker-info">, important</span>
|
||||
<span className="text-darker-info">, important </span>
|
||||
) : null}
|
||||
)
|
||||
</React.Fragment>
|
||||
|
@ -186,16 +186,19 @@ export default class AlertTableRow extends React.Component {
|
|||
title={alert.backfill_record ? backfillRetriggeredTitle : ''}
|
||||
>
|
||||
{hasDocumentation && alert.title ? (
|
||||
<div className="alert-docs" data-testid={`alert ${alert.id} title`}>
|
||||
<span
|
||||
className="alert-docs"
|
||||
data-testid={`alert ${alert.id} title`}
|
||||
>
|
||||
<a data-testid="docs" href={url}>
|
||||
{suite}
|
||||
</a>{' '}
|
||||
{test}
|
||||
</div>
|
||||
</span>
|
||||
) : (
|
||||
<div data-testid={`alert ${alert.id} title`}>
|
||||
<span data-testid={`alert ${alert.id} title`}>
|
||||
{suite} {test}
|
||||
</div>
|
||||
</span>
|
||||
)}
|
||||
</span>{' '}
|
||||
{this.renderAlertStatus(alert, alertStatus, statusColor)}{' '}
|
||||
|
@ -307,38 +310,16 @@ export default class AlertTableRow extends React.Component {
|
|||
this.getTitleText(alert, alertStatus)
|
||||
)}
|
||||
</td>
|
||||
<td className="table-width-md">
|
||||
<td className="table-width-lg">
|
||||
<AlertTablePlatform
|
||||
platform={alert.series_signature.machine_platform}
|
||||
/>
|
||||
</td>
|
||||
<td className="table-width-md">
|
||||
<td className="table-width-lg">
|
||||
<AlertTableTagsOptions alertId={alert.id} items={items} />
|
||||
</td>
|
||||
<td className="table-width-md">{formatNumber(alert.prev_value)}</td>
|
||||
<td className="table-width-sm">
|
||||
<span
|
||||
className={alert.is_regression ? 'text-danger' : 'text-success'}
|
||||
>
|
||||
{alert.prev_value < alert.new_value && <span><</span>}
|
||||
{alert.prev_value > alert.new_value && <span>></span>}
|
||||
</span>
|
||||
</td>
|
||||
<td className="table-width-md">{formatNumber(alert.new_value)}</td>
|
||||
<td className="table-width-md">
|
||||
<SimpleTooltip
|
||||
textClass="detail-hint"
|
||||
text={`${alert.amount_pct}%`}
|
||||
tooltipText={`Absolute difference: ${alert.amount_abs}`}
|
||||
autohide={false}
|
||||
/>
|
||||
</td>
|
||||
<td className="table-width-lg">
|
||||
<ProgressBar
|
||||
magnitude={this.getCappedMagnitude(alert.amount_pct)}
|
||||
regression={alert.is_regression}
|
||||
color={!alert.is_regression ? 'success' : 'danger'}
|
||||
/>
|
||||
<Magnitude alert={alert} />
|
||||
</td>
|
||||
<td className="table-width-sm">
|
||||
<SimpleTooltip
|
||||
|
|
|
@ -32,7 +32,12 @@ export default class AlertTableTagsOptions extends React.Component {
|
|||
};
|
||||
|
||||
return items.map((item) => (
|
||||
<Badge color="light" key={`${item}`} data-testid={badgeId[type]}>
|
||||
<Badge
|
||||
className="mr-1"
|
||||
color="light"
|
||||
key={`${item}`}
|
||||
data-testid={badgeId[type]}
|
||||
>
|
||||
{item}
|
||||
</Badge>
|
||||
));
|
||||
|
@ -72,7 +77,9 @@ export default class AlertTableTagsOptions extends React.Component {
|
|||
this.showItems(items.slice(this.visibleItems[type]), type)}
|
||||
</div>
|
||||
) : (
|
||||
<Badge color="light">No {type}</Badge>
|
||||
<Badge className="mb-1" color="light">
|
||||
No {type}
|
||||
</Badge>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -80,10 +87,10 @@ export default class AlertTableTagsOptions extends React.Component {
|
|||
const { options, tags } = this.state;
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className="d-flex flex-column align-items-start">
|
||||
{this.displayItems(tags, this.itemsType.tags)}
|
||||
{this.displayItems(options, this.itemsType.options)}
|
||||
</React.Fragment>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import numeral from 'numeral';
|
||||
|
||||
import ProgressBar from '../../shared/ProgressBar';
|
||||
import SimpleTooltip from '../../shared/SimpleTooltip';
|
||||
import { formatNumber } from '../perf-helpers/helpers';
|
||||
|
||||
export default class Magnitude extends React.PureComponent {
|
||||
// arbitrary scale from 0-20% multiplied by 5, capped
|
||||
// at 100 (so 20% regression === 100% bad)
|
||||
getCappedMagnitude = (percent) => Math.min(Math.abs(percent) * 5, 100);
|
||||
|
||||
abbreviateNumber = (num) =>
|
||||
numeral(num).format('0.0a').toString().toUpperCase();
|
||||
|
||||
render() {
|
||||
const { alert } = this.props;
|
||||
return (
|
||||
<div className="d-flex align-items-end justify-content-center">
|
||||
<div
|
||||
className="w-50 text-right text-nowrap"
|
||||
data-testid="previous-value"
|
||||
>
|
||||
<SimpleTooltip
|
||||
textClass="detail-hint"
|
||||
text={this.abbreviateNumber(alert.prev_value)}
|
||||
tooltipText={`Previous value: ${formatNumber(alert.prev_value)}`}
|
||||
autohide={false}
|
||||
/>
|
||||
</div>
|
||||
<div className="d-flex flex-column">
|
||||
<div className="align-self-center pb-1">
|
||||
<SimpleTooltip
|
||||
textClass="detail-hint"
|
||||
text={`${alert.amount_pct}%`}
|
||||
tooltipText={`Absolute difference: ${alert.amount_abs}`}
|
||||
autohide={false}
|
||||
/>
|
||||
</div>
|
||||
<div className="px-2 table-width-lg align-self-center">
|
||||
<ProgressBar
|
||||
magnitude={this.getCappedMagnitude(alert.amount_pct)}
|
||||
regression={alert.is_regression}
|
||||
color={!alert.is_regression ? 'success' : 'danger'}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-50 text-nowrap" data-testid="new-value">
|
||||
<SimpleTooltip
|
||||
textClass="detail-hint"
|
||||
text={this.abbreviateNumber(alert.new_value)}
|
||||
tooltipText={`New value: ${formatNumber(alert.new_value)}`}
|
||||
autohide={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Magnitude.propTypes = {
|
||||
alert: PropTypes.shape({}).isRequired,
|
||||
};
|
|
@ -9,7 +9,7 @@ export default class TableColumnHeader extends React.Component {
|
|||
const { column, onChangeSort } = this.props;
|
||||
const { name } = column;
|
||||
return (
|
||||
<div className="d-flex align-items-end">
|
||||
<div className="d-flex align-items-end pl-1 flex-nowrap">
|
||||
<div>{name === 'Test name' ? '' : `${name}`}</div>
|
||||
<SortButton column={column} onChangeSort={onChangeSort} />
|
||||
</div>
|
||||
|
|
Загрузка…
Ссылка в новой задаче