Skip to content
Snippets Groups Projects
Verified Commit f0557d53 authored by Daniele Rossetti's avatar Daniele Rossetti :palm_tree: Committed by GitLab
Browse files

Improve metrics group-by filter

- Show selected attributes in dropdown
- Remove selected label
- Add label to function dropdown
parent 123d0aef
No related branches found
No related tags found
1 merge request!145532Improve metrics group-by filter
......@@ -7,9 +7,10 @@ export default {
GlCollapsibleListbox,
},
i18n: {
groupByPlaceholderMultipleSelect: s__('ObservabilityMetrics|multiple'),
groupByPlaceholderAllSelect: s__('ObservabilityMetrics|all'),
groupByPlaceholder: s__('ObservabilityMetrics|Select attributes'),
noAttributesSelectedLabel: s__('ObservabilityMetrics|Select attributes'),
noFunctionSelectedLabel: s__('ObservabilityMetrics|Select function'),
selectedAttributesHeader: s__('ObservabilityMetrics|Selected attributes'),
availableAttributesHeader: s__('ObservabilityMetrics|Attributes'),
},
props: {
supportedFunctions: {
......@@ -22,11 +23,13 @@ export default {
},
selectedAttributes: {
type: Array,
required: true,
required: false,
default: () => [],
},
selectedFunction: {
type: String,
required: true,
required: false,
default: undefined,
},
},
data() {
......@@ -39,23 +42,38 @@ export default {
availableGroupByFunctions() {
return this.supportedFunctions.map((func) => ({ value: func, text: func }));
},
availableGroupByAttributes() {
return this.supportedAttributes.map((d) => ({ value: d, text: d }));
},
groupByLabel() {
return this.groupByAttributes.length > 1 ? this.groupByAttributes.join(', ') : '';
attributesItems() {
const notSelected = (option) => !this.groupByAttributes.includes(option);
return [
{
text: this.$options.i18n.selectedAttributesHeader,
options: this.groupByAttributes.map((attribute) => ({
value: attribute,
text: attribute,
})),
},
{
text: this.$options.i18n.availableAttributesHeader,
options: this.supportedAttributes
.filter(notSelected)
.map((attribute) => ({ value: attribute, text: attribute })),
},
].filter((group) => group.options.length);
},
groupByToggleText() {
groupByAttributesToggleText() {
if (this.groupByAttributes.length > 0) {
if (this.groupByAttributes.length === 1) {
return this.groupByAttributes[0];
if (this.groupByAttributes.length > 1) {
return `${this.groupByAttributes[0]} +${this.groupByAttributes.length - 1}`;
}
if (this.groupByAttributes.length === this.supportedAttributes.length) {
return this.$options.i18n.groupByPlaceholderAllSelect;
}
return this.$options.i18n.groupByPlaceholderMultipleSelect;
return this.groupByAttributes[0];
}
return this.$options.i18n.noAttributesSelectedLabel;
},
groupByFunctionToggleText() {
if (this.groupByFunction) {
return this.groupByFunction;
}
return this.$options.i18n.groupByPlaceholder;
return this.$options.i18n.noFunctionSelectedLabel;
},
},
methods: {
......@@ -75,17 +93,17 @@ export default {
v-model="groupByFunction"
data-testid="group-by-function-dropdown"
:items="availableGroupByFunctions"
:toggle-text="groupByFunctionToggleText"
@select="onSelect"
/>
<span>{{ __('by') }}</span>
<gl-collapsible-listbox
v-model="groupByAttributes"
data-testid="group-by-attributes-dropdown"
:toggle-text="groupByToggleText"
:toggle-text="groupByAttributesToggleText"
multiple
:items="availableGroupByAttributes"
:items="attributesItems"
@select="onSelect"
/>
<span data-testid="group-by-label">{{ groupByLabel }}</span>
</div>
</template>
......@@ -8,6 +8,23 @@ import { OPERATORS_LIKE_NOT } from '~/observability/constants';
import DateRangeFilter from './date_range_filter.vue';
import GroupByFilter from './groupby_filter.vue';
function defaultGroupByFunction(searchMetadata) {
let defaultFunction;
if (searchMetadata.supported_functions.includes(searchMetadata.default_group_by_function)) {
defaultFunction = searchMetadata.default_group_by_function;
}
return defaultFunction;
}
function defaultGroupByAttributes(searchMetadata) {
let defaultAttributes = (searchMetadata.default_group_by_attributes ?? []).filter(
(attribute) => attribute === '*' || searchMetadata.attribute_keys.includes(attribute),
);
if (defaultAttributes.length === 1 && defaultAttributes[0] === '*') {
defaultAttributes = [...(searchMetadata.attribute_keys ?? [])];
}
return defaultAttributes;
}
export default {
components: {
FilteredSearch,
......@@ -48,17 +65,13 @@ export default {
},
},
data() {
let defaultGroupByAttributes = this.searchMetadata.default_group_by_attributes ?? [];
if (defaultGroupByAttributes.length === 1 && defaultGroupByAttributes[0] === '*') {
defaultGroupByAttributes = [...(this.searchMetadata.attribute_keys ?? [])];
}
return {
shouldShowDateRangePicker: false,
filters: this.attributeFilters,
dateRange: this.dateRangeFilter,
groupBy: {
attributes: this.groupByFilter?.attributes ?? defaultGroupByAttributes,
func: this.groupByFilter?.func ?? this.searchMetadata.default_group_by_function,
attributes: this.groupByFilter?.attributes ?? defaultGroupByAttributes(this.searchMetadata),
func: this.groupByFilter?.func ?? defaultGroupByFunction(this.searchMetadata),
},
};
},
......
......@@ -4,16 +4,17 @@ import GroupByFilter from 'ee/metrics/details/filter_bar/groupby_filter.vue';
describe('GroupByFilter', () => {
let wrapper;
const props = {
supportedAttributes: ['attribute_one', 'attributes_two', 'attributes_three'],
const defaultProps = {
supportedAttributes: ['attribute_one', 'attribute_two', 'attribute_three'],
supportedFunctions: ['sum', 'avg'],
selectedAttributes: ['attribute_one'],
selectedFunction: 'sum',
};
const mount = () => {
const mount = (props = {}) => {
wrapper = shallowMountExtended(GroupByFilter, {
propsData: {
...defaultProps,
...props,
},
});
......@@ -25,23 +26,63 @@ describe('GroupByFilter', () => {
const findGroupByFunctionDropdown = () => wrapper.findByTestId('group-by-function-dropdown');
const findGroupByAttributesDropdown = () => wrapper.findByTestId('group-by-attributes-dropdown');
const findGroupByLabel = () => wrapper.findByTestId('group-by-label');
it('renders the group by function dropdown', () => {
expect(findGroupByFunctionDropdown().props('items')).toEqual([
{ value: 'sum', text: 'sum' },
{ value: 'avg', text: 'avg' },
]);
expect(findGroupByFunctionDropdown().props('selected')).toEqual(props.selectedFunction);
expect(findGroupByFunctionDropdown().props('selected')).toEqual(defaultProps.selectedFunction);
});
it('renders the group by attributes dropdown', () => {
it('renders the group by attributes dropdown in groups', () => {
expect(findGroupByAttributesDropdown().props('items')).toEqual([
{ value: 'attribute_one', text: 'attribute_one' },
{ value: 'attributes_two', text: 'attributes_two' },
{ value: 'attributes_three', text: 'attributes_three' },
{
text: 'Selected attributes',
options: [{ value: 'attribute_one', text: 'attribute_one' }],
},
{
text: 'Attributes',
options: [
{ value: 'attribute_two', text: 'attribute_two' },
{ value: 'attribute_three', text: 'attribute_three' },
],
},
]);
expect(findGroupByAttributesDropdown().props('selected')).toEqual(
defaultProps.selectedAttributes,
);
});
it('does not show the selected group if nothing is selected', () => {
mount({ selectedAttributes: [] });
expect(findGroupByAttributesDropdown().props('items')).toEqual([
{
text: 'Attributes',
options: [
{ value: 'attribute_one', text: 'attribute_one' },
{ value: 'attribute_two', text: 'attribute_two' },
{ value: 'attribute_three', text: 'attribute_three' },
],
},
]);
expect(findGroupByAttributesDropdown().props('selected')).toEqual([]);
});
it('does not show the attributes group if everything is selected', () => {
mount({ selectedAttributes: [...defaultProps.supportedAttributes] });
expect(findGroupByAttributesDropdown().props('items')).toEqual([
{
text: 'Selected attributes',
options: [
{ value: 'attribute_one', text: 'attribute_one' },
{ value: 'attribute_two', text: 'attribute_two' },
{ value: 'attribute_three', text: 'attribute_three' },
],
},
]);
expect(findGroupByAttributesDropdown().props('selected')).toEqual(props.selectedAttributes);
});
it('emits groupBy on function change', async () => {
......@@ -50,7 +91,7 @@ describe('GroupByFilter', () => {
expect(wrapper.emitted('groupBy')).toEqual([
[
{
attributes: props.selectedAttributes,
attributes: defaultProps.selectedAttributes,
func: 'avg',
},
],
......@@ -64,13 +105,13 @@ describe('GroupByFilter', () => {
[
{
attributes: ['attribute_two'],
func: props.selectedFunction,
func: defaultProps.selectedFunction,
},
],
]);
});
it('updates the group-by toggle text depending on value', async () => {
it('updates the attributes dropdown toggle text depending on value', async () => {
expect(findGroupByAttributesDropdown().props('toggleText')).toBe('attribute_one');
await findGroupByAttributesDropdown().vm.$emit('select', ['attribute_two']);
......@@ -79,7 +120,7 @@ describe('GroupByFilter', () => {
await findGroupByAttributesDropdown().vm.$emit('select', ['attribute_two', 'attributes_one']);
expect(findGroupByAttributesDropdown().props('toggleText')).toBe('multiple');
expect(findGroupByAttributesDropdown().props('toggleText')).toBe('attribute_two +1');
await findGroupByAttributesDropdown().vm.$emit('select', [
'attribute_two',
......@@ -87,22 +128,20 @@ describe('GroupByFilter', () => {
'attributes_threww',
]);
expect(findGroupByAttributesDropdown().props('toggleText')).toBe('all');
expect(findGroupByAttributesDropdown().props('toggleText')).toBe('attribute_two +2');
await findGroupByAttributesDropdown().vm.$emit('select', []);
expect(findGroupByAttributesDropdown().props('toggleText')).toBe('Select attributes');
});
it('updates the group-by label depending on value', async () => {
expect(findGroupByLabel().text()).toBe('');
it('updates the function dropdown text depending on value', async () => {
mount({ selectedFunction: undefined });
await findGroupByAttributesDropdown().vm.$emit('select', ['attribute_two']);
expect(findGroupByLabel().text()).toBe('');
expect(findGroupByFunctionDropdown().props('toggleText')).toBe('Select function');
await findGroupByAttributesDropdown().vm.$emit('select', ['attribute_two', 'attributes_one']);
await findGroupByFunctionDropdown().vm.$emit('select', 'avg');
expect(findGroupByLabel().text()).toBe('attribute_two, attributes_one');
expect(findGroupByFunctionDropdown().props('toggleText')).toBe('avg');
});
});
......@@ -18,7 +18,7 @@ describe('MetricsFilteredSearch', () => {
attribute_keys: ['attribute_one', 'attribute_two'],
supported_aggregations: ['1m', '1h'],
supported_functions: ['avg', 'sum', 'p50'],
default_group_by_attributes: ['host.name'],
default_group_by_attributes: ['attribute_one'],
default_group_by_function: 'avg',
};
......@@ -102,7 +102,7 @@ describe('MetricsFilteredSearch', () => {
});
describe('group-by filter', () => {
it('renders the group-by filter with defaults from search metadata', () => {
it('renders the group-by filter with list of supported values from search metadata', () => {
const groupBy = findGroupByFilter();
expect(groupBy.exists()).toBe(true);
expect(groupBy.props('supportedAttributes')).toEqual(defaultSearchMetadata.attribute_keys);
......@@ -112,35 +112,59 @@ describe('MetricsFilteredSearch', () => {
});
it('sets selectedFunction to searchMetadata.default_group_by_function', () => {
expect(findGroupByFilter().props('selectedFunction')).toBe(
expect(findGroupByFilter().props('selectedFunction')).toEqual(
defaultSearchMetadata.default_group_by_function,
);
});
it('ignores invalid default_group_by_function', () => {
mount({
searchMetadata: {
...defaultSearchMetadata,
default_group_by_function: 'not-valid',
},
});
expect(findGroupByFilter().props('selectedFunction')).toBeUndefined();
});
it('handles missing default_group_by_function', () => {
mount({
searchMetadata: {
...defaultSearchMetadata,
default_group_by_function: undefined,
},
});
expect(findGroupByFilter().props('selectedFunction')).toBeUndefined();
});
it('sets selectedAttributes to searchMetadata.default_group_by_attributes', () => {
expect(findGroupByFilter().props('selectedAttributes')).toBe(
expect(findGroupByFilter().props('selectedAttributes')).toEqual(
defaultSearchMetadata.default_group_by_attributes,
);
});
it('sets GroupByFilter selectedFunction prop to groupByFilter.func', () => {
it('ignores invalid default_group_by_attributes', () => {
mount({
groupByFilter: {
func: 'sum',
searchMetadata: {
...defaultSearchMetadata,
default_group_by_attributes: ['', ' ', 'not-valid'],
},
});
expect(findGroupByFilter().props('selectedFunction')).toBe('sum');
expect(findGroupByFilter().props('selectedAttributes')).toEqual([]);
});
it('sets GroupByFilter selectedAttributes prop to groupByFilter.attributes', () => {
it('handles missing default_group_by_attributes', () => {
mount({
groupByFilter: {
attributes: ['attribute_one'],
searchMetadata: {
...defaultSearchMetadata,
default_group_by_attributes: undefined,
},
});
expect(findGroupByFilter().props('selectedAttributes')).toEqual(['attribute_one']);
expect(findGroupByFilter().props('selectedAttributes')).toEqual([]);
});
it(`handles default_group_by_attributes=['*']`, () => {
......@@ -155,6 +179,26 @@ describe('MetricsFilteredSearch', () => {
...defaultSearchMetadata.attribute_keys,
]);
});
it('sets GroupByFilter selectedFunction prop to groupByFilter.func', () => {
mount({
groupByFilter: {
func: 'sum',
},
});
expect(findGroupByFilter().props('selectedFunction')).toEqual('sum');
});
it('sets GroupByFilter selectedAttributes prop to groupByFilter.attributes', () => {
mount({
groupByFilter: {
attributes: ['attribute_one'],
},
});
expect(findGroupByFilter().props('selectedAttributes')).toEqual(['attribute_one']);
});
});
it('emits the submit event when the attributes filter is changed and submit button is clicked', async () => {
......@@ -251,7 +295,7 @@ describe('MetricsFilteredSearch', () => {
},
],
]);
expect(findGroupByFilter().props('selectedFunction')).toBe(groupBy.func);
expect(findGroupByFilter().props('selectedFunction')).toEqual(groupBy.func);
expect(findGroupByFilter().props('selectedAttributes')).toEqual(groupBy.attributes);
});
});
......@@ -33914,6 +33914,9 @@ msgstr ""
msgid "ObservabilityLogs|Warning"
msgstr ""
 
msgid "ObservabilityMetrics|Attributes"
msgstr ""
msgid "ObservabilityMetrics|Cancel"
msgstr ""
 
......@@ -33959,13 +33962,16 @@ msgstr ""
msgid "ObservabilityMetrics|Select attributes"
msgstr ""
 
msgid "ObservabilityMetrics|Type"
msgid "ObservabilityMetrics|Select function"
msgstr ""
 
msgid "ObservabilityMetrics|Value"
msgid "ObservabilityMetrics|Selected attributes"
msgstr ""
msgid "ObservabilityMetrics|Type"
msgstr ""
 
msgid "ObservabilityMetrics|all"
msgid "ObservabilityMetrics|Value"
msgstr ""
 
msgid "ObservabilityMetrics|is like"
......@@ -33974,9 +33980,6 @@ msgstr ""
msgid "ObservabilityMetrics|is not like"
msgstr ""
 
msgid "ObservabilityMetrics|multiple"
msgstr ""
msgid "Observability|Enable"
msgstr ""
 
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment