Commit 18c3d927 authored by Kev's avatar Kev

Add user popup to CI pipeline header

Changelog: changed
parent dfe8ddea
...@@ -18,8 +18,11 @@ query getPipelineHeaderData($fullPath: ID!, $iid: ID!) { ...@@ -18,8 +18,11 @@ query getPipelineHeaderData($fullPath: ID!, $iid: ID!) {
} }
createdAt createdAt
user { user {
id
name name
username
webPath webPath
webUrl
email email
avatarUrl avatarUrl
status { status {
......
<script> <script>
import { GlTooltipDirective, GlLink, GlButton, GlTooltip, GlSafeHtmlDirective } from '@gitlab/ui'; import {
GlTooltipDirective,
GlButton,
GlSafeHtmlDirective,
GlAvatarLink,
GlAvatarLabeled,
} from '@gitlab/ui';
import { isGid, getIdFromGraphQLId } from '~/graphql_shared/utils';
import { glEmojiTag } from '../../emoji'; import { glEmojiTag } from '../../emoji';
import { __, sprintf } from '../../locale'; import { __, sprintf } from '../../locale';
import CiIconBadge from './ci_badge_link.vue'; import CiIconBadge from './ci_badge_link.vue';
import TimeagoTooltip from './time_ago_tooltip.vue'; import TimeagoTooltip from './time_ago_tooltip.vue';
import UserAvatarImage from './user_avatar/user_avatar_image.vue';
/** /**
* Renders header component for job and pipeline page based on UI mockups * Renders header component for job and pipeline page based on UI mockups
...@@ -17,10 +23,9 @@ export default { ...@@ -17,10 +23,9 @@ export default {
components: { components: {
CiIconBadge, CiIconBadge,
TimeagoTooltip, TimeagoTooltip,
UserAvatarImage,
GlLink,
GlButton, GlButton,
GlTooltip, GlAvatarLink,
GlAvatarLabeled,
}, },
directives: { directives: {
GlTooltip: GlTooltipDirective, GlTooltip: GlTooltipDirective,
...@@ -94,6 +99,9 @@ export default { ...@@ -94,6 +99,9 @@ export default {
return this.itemName; return this.itemName;
}, },
userId() {
return isGid(this.user?.id) ? getIdFromGraphQLId(this.user?.id) : this.user?.id;
},
}, },
methods: { methods: {
...@@ -124,15 +132,21 @@ export default { ...@@ -124,15 +132,21 @@ export default {
{{ __('by') }} {{ __('by') }}
<template v-if="user"> <template v-if="user">
<gl-link <gl-avatar-link
v-gl-tooltip :data-user-id="userId"
:href="userPath" :data-username="user.username"
:title="user.email" :data-name="user.name"
class="js-user-link commit-committer-link" :href="user.webUrl"
target="_blank"
class="js-user-link gl-vertical-align-middle gl-mx-2 gl-align-items-center"
> >
<user-avatar-image :img-src="avatarUrl" :img-alt="userAvatarAltText" :size="24" /> <gl-avatar-labeled
{{ user.name }} :size="24"
</gl-link> :src="avatarUrl"
:label="user.name"
class="d-none d-sm-inline-flex gl-mx-1"
/>
<strong class="author gl-display-inline gl-sm-display-none!">@{{ user.username }}</strong>
<gl-tooltip v-if="message" :target="() => $refs[$options.EMOJI_REF]"> <gl-tooltip v-if="message" :target="() => $refs[$options.EMOJI_REF]">
{{ message }} {{ message }}
</gl-tooltip> </gl-tooltip>
...@@ -140,8 +154,10 @@ export default { ...@@ -140,8 +154,10 @@ export default {
v-if="statusTooltipHTML" v-if="statusTooltipHTML"
:ref="$options.EMOJI_REF" :ref="$options.EMOJI_REF"
v-safe-html:[$options.safeHtmlConfig]="statusTooltipHTML" v-safe-html:[$options.safeHtmlConfig]="statusTooltipHTML"
class="gl-ml-2"
:data-testid="message" :data-testid="message"
></span> ></span>
</gl-avatar-link>
</template> </template>
</section> </section>
......
import { GlButton, GlLink } from '@gitlab/ui'; import { GlButton, GlAvatarLink } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import CiIconBadge from '~/vue_shared/components/ci_badge_link.vue'; import CiIconBadge from '~/vue_shared/components/ci_badge_link.vue';
...@@ -18,6 +18,7 @@ describe('Header CI Component', () => { ...@@ -18,6 +18,7 @@ describe('Header CI Component', () => {
}, },
time: '2017-05-08T14:57:39.781Z', time: '2017-05-08T14:57:39.781Z',
user: { user: {
id: 1234,
web_url: 'path', web_url: 'path',
name: 'Foo', name: 'Foo',
username: 'foobar', username: 'foobar',
...@@ -29,7 +30,7 @@ describe('Header CI Component', () => { ...@@ -29,7 +30,7 @@ describe('Header CI Component', () => {
const findIconBadge = () => wrapper.findComponent(CiIconBadge); const findIconBadge = () => wrapper.findComponent(CiIconBadge);
const findTimeAgo = () => wrapper.findComponent(TimeagoTooltip); const findTimeAgo = () => wrapper.findComponent(TimeagoTooltip);
const findUserLink = () => wrapper.findComponent(GlLink); const findUserLink = () => wrapper.findComponent(GlAvatarLink);
const findSidebarToggleBtn = () => wrapper.findComponent(GlButton); const findSidebarToggleBtn = () => wrapper.findComponent(GlButton);
const findActionButtons = () => wrapper.findByTestId('ci-header-action-buttons'); const findActionButtons = () => wrapper.findByTestId('ci-header-action-buttons');
const findHeaderItemText = () => wrapper.findByTestId('ci-header-item-text'); const findHeaderItemText = () => wrapper.findByTestId('ci-header-item-text');
...@@ -64,10 +65,6 @@ describe('Header CI Component', () => { ...@@ -64,10 +65,6 @@ describe('Header CI Component', () => {
expect(findTimeAgo().exists()).toBe(true); expect(findTimeAgo().exists()).toBe(true);
}); });
it('should render user icon and name', () => {
expect(findUserLink().text()).toContain(defaultProps.user.name);
});
it('should render sidebar toggle button', () => { it('should render sidebar toggle button', () => {
expect(findSidebarToggleBtn().exists()).toBe(true); expect(findSidebarToggleBtn().exists()).toBe(true);
}); });
...@@ -77,6 +74,45 @@ describe('Header CI Component', () => { ...@@ -77,6 +74,45 @@ describe('Header CI Component', () => {
}); });
}); });
describe('user avatar', () => {
beforeEach(() => {
createComponent({ itemName: 'Pipeline' });
});
it('contains the username', () => {
expect(findUserLink().text()).toContain(defaultProps.user.username);
});
it('has the correct data attributes', () => {
expect(findUserLink().attributes()).toMatchObject({
'data-user-id': defaultProps.user.id.toString(),
'data-username': defaultProps.user.username,
'data-name': defaultProps.user.name,
});
});
describe('with data from GraphQL', () => {
const userId = 1;
beforeEach(() => {
createComponent({
itemName: 'Pipeline',
user: { ...defaultProps.user, id: `gid://gitlab/User/${1}` },
});
});
it('has the correct user id', () => {
expect(findUserLink().attributes('data-user-id')).toBe(userId.toString());
});
});
describe('with data from REST', () => {
it('has the correct user id', () => {
expect(findUserLink().attributes('data-user-id')).toBe(defaultProps.user.id.toString());
});
});
});
describe('with item id', () => { describe('with item id', () => {
beforeEach(() => { beforeEach(() => {
createComponent({ itemName: 'Pipeline', itemId: '123' }); createComponent({ itemName: 'Pipeline', itemId: '123' });
......
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