зеркало из https://github.com/mozilla/treeherder.git
Bug 1730892 - Remove duplication from tags/options from alerts view (#7270)
* Bug 1730892 - Remove duplication from tags/options from alerts view * Bug 1730892 - Added tests + new tooltip for tags and options * Address review changes
This commit is contained in:
Родитель
52914339c3
Коммит
bbeace9e15
|
@ -93,10 +93,14 @@ test(`Platform column contains alerts's platform`, async () => {
|
|||
expect(alertPlatform.textContent).toBe(machinePlatform);
|
||||
});
|
||||
|
||||
test("Alert item with no tags displays 'No tags'", async () => {
|
||||
const { getByText } = alertTableRowTest({ alert: testAlert, tags: [''] });
|
||||
test("Alert item with no tags or options displays 'No tags or options'", async () => {
|
||||
const { getByText } = alertTableRowTest({
|
||||
alert: testAlert,
|
||||
tags: [''],
|
||||
options: [''],
|
||||
});
|
||||
|
||||
const message = await waitFor(() => getByText('No tags'));
|
||||
const message = await waitFor(() => getByText('No tags or options'));
|
||||
expect(message).toBeInTheDocument();
|
||||
});
|
||||
|
||||
|
@ -112,14 +116,18 @@ test('Alert item with 2 tags displays 2 tags', async () => {
|
|||
expect(tags).toHaveLength(testTags.length);
|
||||
});
|
||||
|
||||
test("Alert item with more than 2 tags displays '...' button", async () => {
|
||||
test("Alert item with more than 2 tags or options displays '...' button", async () => {
|
||||
const testTags = ['tag1', 'tag2', 'tag3'];
|
||||
const testOptions = ['option1', 'option2'];
|
||||
const { getByTestId } = alertTableRowTest({
|
||||
alert: testAlert,
|
||||
tags: testTags,
|
||||
options: testOptions,
|
||||
});
|
||||
|
||||
const showMoreButton = await waitFor(() => getByTestId('show-more-tags'));
|
||||
const showMoreButton = await waitFor(() =>
|
||||
getByTestId('show-more-tags-options'),
|
||||
);
|
||||
|
||||
expect(showMoreButton.textContent).toBe('...');
|
||||
});
|
||||
|
@ -135,7 +143,9 @@ test("Button '...' displays all the tags for an alert item", async () => {
|
|||
|
||||
expect(visibleTags).toHaveLength(2);
|
||||
|
||||
const showMoreButton = await waitFor(() => getByTestId('show-more-tags'));
|
||||
const showMoreButton = await waitFor(() =>
|
||||
getByTestId('show-more-tags-options'),
|
||||
);
|
||||
|
||||
expect(showMoreButton.textContent).toBe('...');
|
||||
|
||||
|
@ -146,22 +156,11 @@ test("Button '...' displays all the tags for an alert item", async () => {
|
|||
expect(visibleTags).toHaveLength(testTags.length);
|
||||
});
|
||||
|
||||
test("Alert item with no options displays 'No options'", async () => {
|
||||
const { getByText } = alertTableRowTest({
|
||||
alert: testAlert,
|
||||
tags: false,
|
||||
options: [''],
|
||||
});
|
||||
|
||||
const message = await waitFor(() => getByText('No options'));
|
||||
expect(message).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('Alert item with 2 options displays 2 options', async () => {
|
||||
const testOptions = ['option1', 'option2'];
|
||||
const { getAllByTestId } = alertTableRowTest({
|
||||
alert: testAlert,
|
||||
tags: false,
|
||||
tags: [],
|
||||
options: testOptions,
|
||||
});
|
||||
|
||||
|
@ -178,7 +177,9 @@ test("Alert item with more than 2 options displays '...' button", async () => {
|
|||
options: testOptions,
|
||||
});
|
||||
|
||||
const showMoreButton = await waitFor(() => getByTestId('show-more-options'));
|
||||
const showMoreButton = await waitFor(() =>
|
||||
getByTestId('show-more-tags-options'),
|
||||
);
|
||||
|
||||
expect(showMoreButton.textContent).toBe('...');
|
||||
});
|
||||
|
@ -187,7 +188,7 @@ test("Button '...' displays all options for an alert item", async () => {
|
|||
const testOptions = ['option1', 'option2', 'option3'];
|
||||
const { getByTestId, getAllByTestId } = alertTableRowTest({
|
||||
alert: testAlert,
|
||||
tags: false,
|
||||
tags: [],
|
||||
options: testOptions,
|
||||
});
|
||||
|
||||
|
@ -195,7 +196,9 @@ test("Button '...' displays all options for an alert item", async () => {
|
|||
|
||||
expect(visibleOptions).toHaveLength(2);
|
||||
|
||||
const showMoreButton = await waitFor(() => getByTestId('show-more-options'));
|
||||
const showMoreButton = await waitFor(() =>
|
||||
getByTestId('show-more-tags-options'),
|
||||
);
|
||||
|
||||
expect(showMoreButton.textContent).toBe('...');
|
||||
|
||||
|
@ -206,6 +209,48 @@ test("Button '...' displays all options for an alert item", async () => {
|
|||
expect(visibleOptions).toHaveLength(testOptions.length);
|
||||
});
|
||||
|
||||
test('Duplicated tags and option are displayed only once, options and tags are the same', async () => {
|
||||
const testOptions = ['cold', 'live'];
|
||||
const testTags = ['cold', 'live'];
|
||||
|
||||
const { getAllByTestId } = alertTableRowTest({
|
||||
alert: testAlert,
|
||||
tags: testTags,
|
||||
options: testOptions,
|
||||
});
|
||||
|
||||
const allTagsAndOptions = await waitFor(() =>
|
||||
getAllByTestId('alert-tag-and-option'),
|
||||
);
|
||||
|
||||
expect(allTagsAndOptions).toHaveLength(2);
|
||||
});
|
||||
|
||||
test('Duplicated tags and option are displayed only once, options and tags have elements in common ', async () => {
|
||||
const testOptions = ['cold', 'live', 'web'];
|
||||
const testTags = ['cold', 'live'];
|
||||
|
||||
const { getByTestId } = alertTableRowTest({
|
||||
alert: testAlert,
|
||||
tags: testTags,
|
||||
options: testOptions,
|
||||
});
|
||||
|
||||
const showMoreButton = await waitFor(() =>
|
||||
getByTestId('show-more-tags-options'),
|
||||
);
|
||||
|
||||
expect(showMoreButton.textContent).toBe('...');
|
||||
|
||||
fireEvent.click(showMoreButton);
|
||||
|
||||
const allTagsAndOptions = await waitFor(() =>
|
||||
getByTestId('all-tags-and-options'),
|
||||
);
|
||||
|
||||
expect(allTagsAndOptions.children).toHaveLength(3);
|
||||
});
|
||||
|
||||
test('Documentation link is available for talos framework', async () => {
|
||||
const { getByTestId } = alertTableRowTest();
|
||||
expect(getByTestId('docs')).toHaveAttribute(
|
||||
|
|
|
@ -268,7 +268,15 @@ export default class AlertTableRow extends React.Component {
|
|||
const { repository, framework } = alertSummary;
|
||||
|
||||
const { tags, extra_options: options } = alert.series_signature;
|
||||
const items = { tags, options };
|
||||
|
||||
const tagsAndOptions = tags.concat(options);
|
||||
const stripDuplicates = new Set(tagsAndOptions.filter((item) => item));
|
||||
const items = Array.from(stripDuplicates).map((element) => ({
|
||||
name: element,
|
||||
tag: tags.includes(element),
|
||||
option: options.includes(element),
|
||||
tagAndOption: tags.includes(element) && options.includes(element),
|
||||
}));
|
||||
|
||||
const timeRange = this.getTimeRange();
|
||||
|
||||
|
|
|
@ -4,101 +4,107 @@ import UncontrolledTooltip from 'reactstrap/lib/UncontrolledTooltip';
|
|||
import Button from 'reactstrap/lib/Button';
|
||||
import Badge from 'reactstrap/lib/Badge';
|
||||
|
||||
export default class AlertTableTagsOptions extends React.Component {
|
||||
itemsType = { tags: 'tags', options: 'options' };
|
||||
import SimpleTooltip from '../../shared/SimpleTooltip';
|
||||
|
||||
visibleItems = {
|
||||
tags: 2,
|
||||
options: 2,
|
||||
};
|
||||
export default class AlertTableTagsOptions extends React.Component {
|
||||
visibleItems = 2;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const { tags, options } = this.props.items;
|
||||
|
||||
this.state = {
|
||||
displayAllItems: {
|
||||
tags: false,
|
||||
options: false,
|
||||
},
|
||||
options,
|
||||
tags,
|
||||
displayAllItems: false,
|
||||
};
|
||||
}
|
||||
|
||||
showItems = (items, type) => {
|
||||
showItems = (items) => {
|
||||
const badgeId = {
|
||||
tags: 'alert-tag',
|
||||
options: 'alert-option',
|
||||
tag: 'alert-tag',
|
||||
option: 'alert-option',
|
||||
'tag & option': 'alert-tag-and-option',
|
||||
};
|
||||
|
||||
return items.map((item) => (
|
||||
<Badge
|
||||
className="mr-1"
|
||||
className="mr-1 custom-tooltip"
|
||||
color="light"
|
||||
key={`${item}`}
|
||||
data-testid={badgeId[type]}
|
||||
key={`${item.name}`}
|
||||
data-testid={badgeId[this.getBadgeType(item)]}
|
||||
>
|
||||
{item}
|
||||
<SimpleTooltip text={item.name} tooltipText={this.getBadgeType(item)} />
|
||||
</Badge>
|
||||
));
|
||||
};
|
||||
|
||||
displayItems = (items, type) => {
|
||||
getBadgeType = (item) => {
|
||||
if (item.tagAndOption) {
|
||||
return 'tag & option';
|
||||
}
|
||||
|
||||
if (item.tag) {
|
||||
return 'tag';
|
||||
}
|
||||
|
||||
if (item.option) {
|
||||
return 'option';
|
||||
}
|
||||
};
|
||||
|
||||
displayItems = (items) => {
|
||||
const { alertId } = this.props;
|
||||
const { displayAllItems } = this.state;
|
||||
|
||||
return items.length && items[0] !== '' ? (
|
||||
<div>
|
||||
{this.showItems(items.slice(0, this.visibleItems[type]), type)}
|
||||
{!displayAllItems[type] && items.length > this.visibleItems[type] && (
|
||||
return items.length ? (
|
||||
<div data-testid="all-tags-and-options">
|
||||
{this.showItems(items.slice(0, this.visibleItems))}
|
||||
{!displayAllItems && items.length > this.visibleItems && (
|
||||
<Button
|
||||
color="link"
|
||||
size="sm"
|
||||
id={`alert-${alertId}-${type}`}
|
||||
id={`alert-${alertId}-tags-options`}
|
||||
onClick={() =>
|
||||
this.setState((prevState) => ({
|
||||
displayAllItems: {
|
||||
...prevState.displayAllItems,
|
||||
[type]: !prevState.displayAllItems[type],
|
||||
},
|
||||
displayAllItems: !prevState.displayAllItems,
|
||||
}))
|
||||
}
|
||||
>
|
||||
<span data-testid={`show-more-${type}`}>...</span>
|
||||
<span data-testid="show-more-tags-options">...</span>
|
||||
<UncontrolledTooltip
|
||||
placement="top"
|
||||
target={`alert-${alertId}-${type}`}
|
||||
target={`alert-${alertId}-tags-options`}
|
||||
>
|
||||
Show more {type}
|
||||
Show more
|
||||
</UncontrolledTooltip>
|
||||
</Button>
|
||||
)}
|
||||
{displayAllItems[type] &&
|
||||
this.showItems(items.slice(this.visibleItems[type]), type)}
|
||||
{displayAllItems && this.showItems(items.slice(this.visibleItems))}
|
||||
</div>
|
||||
) : (
|
||||
<Badge className="mb-1" color="light">
|
||||
No {type}
|
||||
No tags or options
|
||||
</Badge>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { options, tags } = this.state;
|
||||
const { items } = this.props;
|
||||
|
||||
return (
|
||||
<div className="d-flex flex-column align-items-start">
|
||||
{this.displayItems(tags, this.itemsType.tags)}
|
||||
{this.displayItems(options, this.itemsType.options)}
|
||||
{this.displayItems(items)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
AlertTableTagsOptions.propTypes = {
|
||||
items: PropTypes.shape({
|
||||
tags: PropTypes.array.isRequired,
|
||||
options: PropTypes.array.isRequired,
|
||||
}).isRequired,
|
||||
items: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
name: PropTypes.string.isRequired,
|
||||
tag: PropTypes.bool.isRequired,
|
||||
option: PropTypes.bool.isRequired,
|
||||
tagAndOption: PropTypes.bool.isRequired,
|
||||
}),
|
||||
).isRequired,
|
||||
alertId: PropTypes.number.isRequired,
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче