182 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Vue
		
	
	
	
			
		
		
	
	
			182 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Vue
		
	
	
	
| <script>
 | |
| import {
 | |
|   GlTooltipDirective,
 | |
|   GlButton,
 | |
|   GlSafeHtmlDirective,
 | |
|   GlAvatarLink,
 | |
|   GlAvatarLabeled,
 | |
|   GlTooltip,
 | |
| } from '@gitlab/ui';
 | |
| import { isGid, getIdFromGraphQLId } from '~/graphql_shared/utils';
 | |
| import { glEmojiTag } from '../../emoji';
 | |
| import { __, sprintf } from '../../locale';
 | |
| import CiIconBadge from './ci_badge_link.vue';
 | |
| import TimeagoTooltip from './time_ago_tooltip.vue';
 | |
| 
 | |
| /**
 | |
|  * Renders header component for job and pipeline page based on UI mockups
 | |
|  *
 | |
|  * Used in:
 | |
|  * - job show page
 | |
|  * - pipeline show page
 | |
|  */
 | |
| export default {
 | |
|   components: {
 | |
|     CiIconBadge,
 | |
|     TimeagoTooltip,
 | |
|     GlButton,
 | |
|     GlAvatarLink,
 | |
|     GlAvatarLabeled,
 | |
|     GlTooltip,
 | |
|   },
 | |
|   directives: {
 | |
|     GlTooltip: GlTooltipDirective,
 | |
|     SafeHtml: GlSafeHtmlDirective,
 | |
|   },
 | |
|   EMOJI_REF: 'EMOJI_REF',
 | |
|   props: {
 | |
|     status: {
 | |
|       type: Object,
 | |
|       required: true,
 | |
|     },
 | |
|     itemName: {
 | |
|       type: String,
 | |
|       required: true,
 | |
|     },
 | |
|     itemId: {
 | |
|       type: String,
 | |
|       required: false,
 | |
|       default: '',
 | |
|     },
 | |
|     time: {
 | |
|       type: String,
 | |
|       required: true,
 | |
|     },
 | |
|     user: {
 | |
|       type: Object,
 | |
|       required: false,
 | |
|       default: () => ({}),
 | |
|     },
 | |
|     hasSidebarButton: {
 | |
|       type: Boolean,
 | |
|       required: false,
 | |
|       default: false,
 | |
|     },
 | |
|     shouldRenderTriggeredLabel: {
 | |
|       type: Boolean,
 | |
|       required: false,
 | |
|       default: true,
 | |
|     },
 | |
|   },
 | |
| 
 | |
|   computed: {
 | |
|     userAvatarAltText() {
 | |
|       return sprintf(__(`%{username}'s avatar`), { username: this.user.name });
 | |
|     },
 | |
|     userPath() {
 | |
|       // GraphQL returns `webPath` and Rest `path`
 | |
|       return this.user?.webPath || this.user?.path;
 | |
|     },
 | |
|     avatarUrl() {
 | |
|       // GraphQL returns `avatarUrl` and Rest `avatar_url`
 | |
|       return this.user?.avatarUrl || this.user?.avatar_url;
 | |
|     },
 | |
|     statusTooltipHTML() {
 | |
|       // Rest `status_tooltip_html` which is a ready to work
 | |
|       // html for the emoji and the status text inside a tooltip.
 | |
|       // GraphQL returns `status.emoji` and `status.message` which
 | |
|       // needs to be combined to make the html we want.
 | |
|       const { emoji } = this.user?.status || {};
 | |
|       const emojiHtml = emoji ? glEmojiTag(emoji) : '';
 | |
| 
 | |
|       return emojiHtml || this.user?.status_tooltip_html;
 | |
|     },
 | |
|     message() {
 | |
|       return this.user?.status?.message;
 | |
|     },
 | |
|     item() {
 | |
|       if (this.itemId) {
 | |
|         return `${this.itemName} #${this.itemId}`;
 | |
|       }
 | |
| 
 | |
|       return this.itemName;
 | |
|     },
 | |
|     userId() {
 | |
|       return isGid(this.user?.id) ? getIdFromGraphQLId(this.user?.id) : this.user?.id;
 | |
|     },
 | |
|   },
 | |
| 
 | |
|   methods: {
 | |
|     onClickSidebarButton() {
 | |
|       this.$emit('clickedSidebarButton');
 | |
|     },
 | |
|   },
 | |
|   safeHtmlConfig: { ADD_TAGS: ['gl-emoji'] },
 | |
| };
 | |
| </script>
 | |
| 
 | |
| <template>
 | |
|   <header
 | |
|     class="page-content-header gl-display-flex gl-min-h-7"
 | |
|     data-qa-selector="pipeline_header"
 | |
|     data-testid="ci-header-content"
 | |
|   >
 | |
|     <section class="header-main-content gl-mr-3">
 | |
|       <ci-icon-badge :status="status" />
 | |
| 
 | |
|       <strong data-testid="ci-header-item-text">{{ item }}</strong>
 | |
| 
 | |
|       <template v-if="shouldRenderTriggeredLabel">{{ __('triggered') }}</template>
 | |
|       <template v-else>{{ __('created') }}</template>
 | |
| 
 | |
|       <timeago-tooltip :time="time" />
 | |
| 
 | |
|       {{ __('by') }}
 | |
| 
 | |
|       <template v-if="user">
 | |
|         <gl-avatar-link
 | |
|           :data-user-id="userId"
 | |
|           :data-username="user.username"
 | |
|           :data-name="user.name"
 | |
|           :href="user.webUrl"
 | |
|           target="_blank"
 | |
|           class="js-user-link gl-vertical-align-middle gl-mx-2 gl-align-items-center"
 | |
|         >
 | |
|           <gl-avatar-labeled
 | |
|             :size="24"
 | |
|             :src="avatarUrl"
 | |
|             :label="user.name"
 | |
|             class="gl-display-none gl-sm-display-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]">
 | |
|             {{ message }}
 | |
|           </gl-tooltip>
 | |
|           <span
 | |
|             v-if="statusTooltipHTML"
 | |
|             :ref="$options.EMOJI_REF"
 | |
|             v-safe-html:[$options.safeHtmlConfig]="statusTooltipHTML"
 | |
|             class="gl-ml-2"
 | |
|             :data-testid="message"
 | |
|           ></span>
 | |
|         </gl-avatar-link>
 | |
|       </template>
 | |
|     </section>
 | |
| 
 | |
|     <section
 | |
|       v-if="$slots.default"
 | |
|       data-testid="ci-header-action-buttons"
 | |
|       class="gl-display-flex gl-mr-3"
 | |
|     >
 | |
|       <slot></slot>
 | |
|     </section>
 | |
|     <gl-button
 | |
|       v-if="hasSidebarButton"
 | |
|       class="gl-md-display-none gl-ml-auto gl-align-self-start js-sidebar-build-toggle"
 | |
|       icon="chevron-double-lg-left"
 | |
|       :aria-label="__('Toggle sidebar')"
 | |
|       @click="onClickSidebarButton"
 | |
|     />
 | |
|   </header>
 | |
| </template>
 |