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>
import { __ } from '~/locale';
import { s__, __ } from '~/locale';
import $ from 'jquery';
import _ from 'underscore';
import Icon from '~/vue_shared/components/icon.vue';
import { GlLoadingIcon, GlButton, GlAvatar } from '@gitlab/ui';
import Api from '~/api';
import { getIdenticonBackgroundClass, getIdenticonTitle } from '~/helpers/avatar_helper';
import { renderAvatar, renderIdenticon } from '~/helpers/avatar_helper';
export default {
name: 'GroupsDropdownFilter',
......@@ -15,6 +15,13 @@ export default {
GlButton,
GlAvatar,
},
props: {
label: {
type: String,
required: false,
default: s__('CycleAnalytics|group dropdown filter'),
},
},
data() {
return {
loading: true,
......@@ -35,22 +42,17 @@ export default {
search: {
fields: ['full_name'],
},
clicked: this.onClick,
data: this.fetchData,
clicked: this.onClick.bind(this),
data: this.fetchData.bind(this),
renderRow: group => this.rowTemplate(group),
text: group => group.name,
opened: e => e.target.querySelector('.dropdown-input-field').focus(),
});
},
methods: {
onClick({ $el, e }) {
onClick({ selectedObj, e }) {
e.preventDefault();
this.selectedGroup = {
id: $el.data('id'),
name: $el.data('name'),
path: $el.data('path'),
avatar_url: $el.data('avatar-url'),
};
this.selectedGroup = selectedObj;
this.$emit('selected', this.selectedGroup);
},
fetchData(term, callback) {
......@@ -63,9 +65,7 @@ export default {
rowTemplate(group) {
return `
<li>
<a href='#' class='dropdown-menu-link' data-id="${group.id}" data-name="${_.escape(
group.name,
)}" data-path="${group.path}" data-avatar-url="${group.avatar_url}">
<a href='#' class='dropdown-menu-link'>
${this.avatarTemplate(group)}
<div class="align-middle">${_.escape(group.name)}</div>
</a>
......@@ -74,10 +74,10 @@ export default {
},
avatarTemplate(group) {
return group.avatar_url !== null
? `<img src="${group.avatar_url}" alt="${this.groupAvatarAltText}" class="avatar rect-avatar s16"/>`
: `<div class="avatar identicon s16 rect-avatar d-flex justify-content-center flex-column ${getIdenticonBackgroundClass(
group.id,
)}">${getIdenticonTitle(group.name)}</div>`;
? renderAvatar(group, { sizeClass: 's16 rect-avatar' })
: renderIdenticon(group, {
sizeClass: 's16 rect-avatar d-flex justify-content-center flex-column',
});
},
},
};
......@@ -91,7 +91,7 @@ export default {
type="button"
data-toggle="dropdown"
aria-expanded="false"
:aria-label="selectedGroupName"
:aria-label="label"
>
<gl-avatar
v-if="selectedGroup.name"
......@@ -100,7 +100,7 @@ export default {
:entity-name="selectedGroup.name"
:size="16"
shape="rect"
:alt="s__('CycleAnalytics|group avatar')"
:alt="selectedGroup.name"
class="prepend-top-2"
/>
{{ selectedGroupName }}
......
import { mount } from '@vue/test-utils';
import $ from 'jquery';
import Vue from 'vue';
import GLDropdown from '~/gl_dropdown'; // eslint-disable-line no-unused-vars
import 'bootstrap';
import '~/gl_dropdown';
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', () => {
const Component = Vue.extend(GroupsDropdownFilter);
let vm;
let wrapper;
afterEach(() => {
vm.$destroy();
wrapper.destroy();
});
beforeEach(() => {
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', () => {
expect($.fn.glDropdown).toHaveBeenCalled();
});
describe('onClick', () => {
const group = {
id: 1,
name: 'foo',
path: 'bar',
};
const $el = $('<a></a>').data(group);
const e = new Event('click');
describe('it renders the items correctly', () => {
beforeEach(() => {
openDropdown();
return wrapper.vm.$nextTick();
});
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', () => {
jest.spyOn(vm, '$emit');
it("renders an identicon when the group doesn't have an avatar_url", () => {
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"
msgstr[0] ""
msgstr[1] ""
msgid "CycleAnalytics|group avatar"
msgid "CycleAnalytics|group dropdown filter"
msgstr ""
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