Commit 0b5bc45e authored by Jose Ivan Vargas's avatar Jose Ivan Vargas

Merge branch '291008-default-emoji-persists-in-group-members-list' into 'master'

Fix how busy is displayed in group/project members list

See merge request gitlab-org/gitlab!79780
parents e02b3c46 953da37d
......@@ -8,10 +8,14 @@ import {
import { generateBadges } from 'ee_else_ce/members/utils';
import { glEmojiTag } from '~/emoji';
import { __ } from '~/locale';
import { isUserBusy } from '~/set_status_modal/utils';
import { AVATAR_SIZE } from '../../constants';
export default {
name: 'UserAvatar',
i18n: {
busy: __('Busy'),
},
avatarSize: AVATAR_SIZE,
orphanedUserLabel: __('Orphaned member'),
safeHtmlConfig: { ADD_TAGS: ['gl-emoji'] },
......@@ -46,7 +50,10 @@ export default {
}).filter((badge) => badge.show);
},
statusEmoji() {
return this.user?.status?.emoji;
return this.user?.showStatus && this.user?.status?.emoji;
},
isUserBusy() {
return isUserBusy(this.user?.availability || '');
},
},
methods: {
......@@ -73,6 +80,11 @@ export default {
:entity-id="user.id"
>
<template #meta>
<div v-if="isUserBusy" class="gl-p-1">
<span class="gl-text-gray-500 gl-font-sm gl-font-weight-normal"
>({{ $options.i18n.busy }})</span
>
</div>
<div v-if="statusEmoji" class="gl-p-1">
<span
v-safe-html:[$options.safeHtmlConfig]="glEmojiTag(statusEmoji)"
......
# frozen_string_literal: true
class MemberUserEntity < UserEntity
unexpose :show_status
unexpose :path
unexpose :state
unexpose :status_tooltip_html
......
{
"type": "object",
"required": ["id", "name", "username", "avatar_url", "web_url", "blocked", "two_factor_enabled"],
"required": ["id", "name", "username", "avatar_url", "web_url", "blocked", "two_factor_enabled", "show_status"],
"properties": {
"id": { "type": "integer" },
"name": { "type": "string" },
......@@ -17,6 +17,7 @@
"emoji": { "type": "string" }
},
"additionalProperties": false
}
},
"show_status": { "type": "boolean" }
}
}
import { GlAvatarLink, GlBadge } from '@gitlab/ui';
import { within } from '@testing-library/dom';
import { mount, createWrapper } from '@vue/test-utils';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import UserAvatar from '~/members/components/avatars/user_avatar.vue';
import { AVAILABILITY_STATUS } from '~/set_status_modal/utils';
import { member as memberMock, member2faEnabled, orphanedMember } from '../../mock_data';
describe('UserAvatar', () => {
......@@ -10,7 +11,7 @@ describe('UserAvatar', () => {
const { user } = memberMock;
const createComponent = (propsData = {}, provide = {}) => {
wrapper = mount(UserAvatar, {
wrapper = mountExtended(UserAvatar, {
propsData: {
member: memberMock,
isCurrentUser: false,
......@@ -23,9 +24,6 @@ describe('UserAvatar', () => {
});
};
const getByText = (text, options) =>
createWrapper(within(wrapper.element).findByText(text, options));
const findStatusEmoji = (emoji) => wrapper.find(`gl-emoji[data-name="${emoji}"]`);
afterEach(() => {
......@@ -48,13 +46,13 @@ describe('UserAvatar', () => {
it("renders user's name", () => {
createComponent();
expect(getByText(user.name).exists()).toBe(true);
expect(wrapper.findByText(user.name).exists()).toBe(true);
});
it("renders user's username", () => {
createComponent();
expect(getByText(`@${user.username}`).exists()).toBe(true);
expect(wrapper.findByText(`@${user.username}`).exists()).toBe(true);
});
it("renders user's avatar", () => {
......@@ -67,7 +65,7 @@ describe('UserAvatar', () => {
it('displays an orphaned user', () => {
createComponent({ member: orphanedMember });
expect(getByText('Orphaned member').exists()).toBe(true);
expect(wrapper.findByText('Orphaned member').exists()).toBe(true);
});
});
......@@ -85,13 +83,13 @@ describe('UserAvatar', () => {
it('renders the "It\'s you" badge when member is current user', () => {
createComponent({ isCurrentUser: true });
expect(getByText("It's you").exists()).toBe(true);
expect(wrapper.findByText("It's you").exists()).toBe(true);
});
it('does not render 2FA badge when `canManageMembers` is `false`', () => {
createComponent({ member: member2faEnabled }, { canManageMembers: false });
expect(within(wrapper.element).queryByText('2FA')).toBe(null);
expect(wrapper.findByText('2FA').exists()).toBe(false);
});
});
......@@ -112,6 +110,23 @@ describe('UserAvatar', () => {
expect(findStatusEmoji(emoji).exists()).toBe(true);
});
describe('when `user.showStatus` is `false', () => {
it('does not display status emoji', () => {
createComponent({
member: {
...memberMock,
user: {
...memberMock.user,
showStatus: false,
status: { emoji, messageHtml: 'On vacation' },
},
},
});
expect(findStatusEmoji(emoji).exists()).toBe(false);
});
});
});
describe('when not set', () => {
......@@ -122,4 +137,30 @@ describe('UserAvatar', () => {
});
});
});
describe('user availability', () => {
describe('when `user.availability` is `null`', () => {
it("does not show `(Busy)` next to user's name", () => {
createComponent();
expect(wrapper.findByText('(Busy)').exists()).toBe(false);
});
});
describe(`when user.availability is ${AVAILABILITY_STATUS.BUSY}`, () => {
it("shows `(Busy)` next to user's name", () => {
createComponent({
member: {
...memberMock,
user: {
...memberMock.user,
availability: AVAILABILITY_STATUS.BUSY,
},
},
});
expect(wrapper.findByText('(Busy)').exists()).toBe(true);
});
});
});
});
......@@ -25,6 +25,8 @@ export const member = {
twoFactorEnabled: false,
oncallSchedules: [{ name: 'schedule 1' }],
escalationPolicies: [{ name: 'policy 1' }],
availability: null,
showStatus: true,
},
id: 238,
createdAt: '2020-07-17T16:22:46.923Z',
......
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