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:
Sorin Toma 2021-09-24 14:55:47 +03:00 коммит произвёл GitHub
Родитель 52914339c3
Коммит bbeace9e15
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
3 изменённых файлов: 124 добавлений и 65 удалений

Просмотреть файл

@ -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,
};