Commit 9fd6d4e3 authored by Paul Slaughter's avatar Paul Slaughter

Merge branch 'refactor-analytics-group-dropdown-filter' into 'master'

Refactor analytics group dropdown filter

See merge request gitlab-org/gitlab-ee!14869
parents 38b7a483 3a391bd5
<script> <script>
import { __ } from '~/locale'; import { s__, __ } from '~/locale';
import $ from 'jquery'; import $ from 'jquery';
import _ from 'underscore'; import _ from 'underscore';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import { GlLoadingIcon, GlButton, GlAvatar } from '@gitlab/ui'; import { GlLoadingIcon, GlButton, GlAvatar } from '@gitlab/ui';
import Api from '~/api'; import Api from '~/api';
import { getIdenticonBackgroundClass, getIdenticonTitle } from '~/helpers/avatar_helper'; import { renderAvatar, renderIdenticon } from '~/helpers/avatar_helper';
export default { export default {
name: 'GroupsDropdownFilter', name: 'GroupsDropdownFilter',
...@@ -15,6 +15,13 @@ export default { ...@@ -15,6 +15,13 @@ export default {
GlButton, GlButton,
GlAvatar, GlAvatar,
}, },
props: {
label: {
type: String,
required: false,
default: s__('CycleAnalytics|group dropdown filter'),
},
},
data() { data() {
return { return {
loading: true, loading: true,
...@@ -35,22 +42,17 @@ export default { ...@@ -35,22 +42,17 @@ export default {
search: { search: {
fields: ['full_name'], fields: ['full_name'],
}, },
clicked: this.onClick, clicked: this.onClick.bind(this),
data: this.fetchData, data: this.fetchData.bind(this),
renderRow: group => this.rowTemplate(group), renderRow: group => this.rowTemplate(group),
text: group => group.name, text: group => group.name,
opened: e => e.target.querySelector('.dropdown-input-field').focus(), opened: e => e.target.querySelector('.dropdown-input-field').focus(),
}); });
}, },
methods: { methods: {
onClick({ $el, e }) { onClick({ selectedObj, e }) {
e.preventDefault(); e.preventDefault();
this.selectedGroup = { this.selectedGroup = selectedObj;
id: $el.data('id'),
name: $el.data('name'),
path: $el.data('path'),
avatar_url: $el.data('avatar-url'),
};
this.$emit('selected', this.selectedGroup); this.$emit('selected', this.selectedGroup);
}, },
fetchData(term, callback) { fetchData(term, callback) {
...@@ -63,9 +65,7 @@ export default { ...@@ -63,9 +65,7 @@ export default {
rowTemplate(group) { rowTemplate(group) {
return ` return `
<li> <li>
<a href='#' class='dropdown-menu-link' data-id="${group.id}" data-name="${_.escape( <a href='#' class='dropdown-menu-link'>
group.name,
)}" data-path="${group.path}" data-avatar-url="${group.avatar_url}">
${this.avatarTemplate(group)} ${this.avatarTemplate(group)}
<div class="align-middle">${_.escape(group.name)}</div> <div class="align-middle">${_.escape(group.name)}</div>
</a> </a>
...@@ -74,10 +74,10 @@ export default { ...@@ -74,10 +74,10 @@ export default {
}, },
avatarTemplate(group) { avatarTemplate(group) {
return group.avatar_url !== null return group.avatar_url !== null
? `<img src="${group.avatar_url}" alt="${this.groupAvatarAltText}" class="avatar rect-avatar s16"/>` ? renderAvatar(group, { sizeClass: 's16 rect-avatar' })
: `<div class="avatar identicon s16 rect-avatar d-flex justify-content-center flex-column ${getIdenticonBackgroundClass( : renderIdenticon(group, {
group.id, sizeClass: 's16 rect-avatar d-flex justify-content-center flex-column',
)}">${getIdenticonTitle(group.name)}</div>`; });
}, },
}, },
}; };
...@@ -91,7 +91,7 @@ export default { ...@@ -91,7 +91,7 @@ export default {
type="button" type="button"
data-toggle="dropdown" data-toggle="dropdown"
aria-expanded="false" aria-expanded="false"
:aria-label="selectedGroupName" :aria-label="label"
> >
<gl-avatar <gl-avatar
v-if="selectedGroup.name" v-if="selectedGroup.name"
...@@ -100,7 +100,7 @@ export default { ...@@ -100,7 +100,7 @@ export default {
:entity-name="selectedGroup.name" :entity-name="selectedGroup.name"
:size="16" :size="16"
shape="rect" shape="rect"
:alt="s__('CycleAnalytics|group avatar')" :alt="selectedGroup.name"
class="prepend-top-2" class="prepend-top-2"
/> />
{{ selectedGroupName }} {{ selectedGroupName }}
......
import { mount } from '@vue/test-utils';
import $ from 'jquery'; import $ from 'jquery';
import Vue from 'vue'; import 'bootstrap';
import GLDropdown from '~/gl_dropdown'; // eslint-disable-line no-unused-vars import '~/gl_dropdown';
import GroupsDropdownFilter from 'ee/analytics/shared/components/groups_dropdown_filter.vue'; import GroupsDropdownFilter from 'ee/analytics/shared/components/groups_dropdown_filter.vue';
import mountComponent from 'helpers/vue_mount_component_helper'; import Api from '~/api';
import { TEST_HOST } from 'helpers/test_constants';
jest.mock('~/api', () => ({
groups: jest.fn(),
}));
const groups = [
{
id: 1,
name: 'foo',
avatar_url: `${TEST_HOST}/images/home/nasa.svg`,
},
{
id: 2,
name: 'foobar',
avatar_url: null,
},
];
describe('GroupsDropdownFilter component', () => { describe('GroupsDropdownFilter component', () => {
const Component = Vue.extend(GroupsDropdownFilter); let wrapper;
let vm;
afterEach(() => { afterEach(() => {
vm.$destroy(); wrapper.destroy();
}); });
beforeEach(() => { beforeEach(() => {
jest.spyOn($.fn, 'glDropdown'); jest.spyOn($.fn, 'glDropdown');
vm = mountComponent(Component); Api.groups.mockImplementation((term, options, callback) => {
callback(groups);
});
wrapper = mount(GroupsDropdownFilter);
}); });
const findDropdown = () => wrapper.find('.dropdown');
const openDropdown = () => {
$(findDropdown().element)
.parent()
.trigger('shown.bs.dropdown');
};
const findDropdownItems = () => findDropdown().findAll('a');
const findDropdownButton = () => findDropdown().find('button');
it('should call glDropdown', () => { it('should call glDropdown', () => {
expect($.fn.glDropdown).toHaveBeenCalled(); expect($.fn.glDropdown).toHaveBeenCalled();
}); });
describe('onClick', () => { describe('it renders the items correctly', () => {
const group = { beforeEach(() => {
id: 1, openDropdown();
name: 'foo',
path: 'bar', return wrapper.vm.$nextTick();
}; });
const $el = $('<a></a>').data(group);
const e = new Event('click'); it('should contain 2 items', () => {
expect(findDropdownItems().length).toEqual(2);
});
it('renders an avatar when the group has an avatar_url', () => {
expect(
findDropdownItems()
.at(0)
.contains('img.avatar'),
).toBe(true);
expect(
findDropdownItems()
.at(0)
.contains('div.identicon'),
).toBe(false);
});
it('should emit the "selected" event', () => { it("renders an identicon when the group doesn't have an avatar_url", () => {
jest.spyOn(vm, '$emit'); expect(
findDropdownItems()
.at(1)
.contains('img.avatar'),
).toBe(false);
expect(
findDropdownItems()
.at(1)
.contains('div.identicon'),
).toBe(true);
});
});
describe('on group click', () => {
beforeEach(() => {
openDropdown();
return wrapper.vm.$nextTick();
});
it('should emit the "selected" event with the selected group', () => {
findDropdownItems()
.at(0)
.trigger('click');
expect(wrapper.emittedByOrder()).toEqual([
{
name: 'selected',
args: [groups[0]],
},
]);
});
vm.onClick({ $el, e }); it('should change selection when new group is clicked', () => {
findDropdownItems()
.at(1)
.trigger('click');
expect(vm.$emit).toHaveBeenCalledWith('selected', group); expect(wrapper.emittedByOrder()).toEqual([
{
name: 'selected',
args: [groups[1]],
},
]);
});
it('renders an avatar in the dropdown button when the group has an avatar_url', done => {
findDropdownItems()
.at(0)
.trigger('click');
wrapper.vm.$nextTick(() => {
expect(findDropdownButton().contains('img.avatar')).toBe(true);
expect(findDropdownButton().contains('div.identicon')).toBe(false);
done();
});
});
it("renders an identicon in the dropdown button when the group doesn't have an avatar_url", done => {
findDropdownItems()
.at(1)
.trigger('click');
wrapper.vm.$nextTick(() => {
expect(findDropdownButton().contains('img.avatar')).toBe(false);
expect(findDropdownButton().contains('div.identicon')).toBe(true);
done();
});
}); });
}); });
}); });
...@@ -4356,7 +4356,7 @@ msgid_plural "CycleAnalytics|%d projects selected" ...@@ -4356,7 +4356,7 @@ msgid_plural "CycleAnalytics|%d projects selected"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
msgid "CycleAnalytics|group avatar" msgid "CycleAnalytics|group dropdown filter"
msgstr "" msgstr ""
msgid "DNS" msgid "DNS"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment