diff options
Diffstat (limited to 'app/assets/javascripts/issuables_list/components/issuable.vue')
-rw-r--r-- | app/assets/javascripts/issuables_list/components/issuable.vue | 121 |
1 files changed, 80 insertions, 41 deletions
diff --git a/app/assets/javascripts/issuables_list/components/issuable.vue b/app/assets/javascripts/issuables_list/components/issuable.vue index 947c7518289..b7f4292a126 100644 --- a/app/assets/javascripts/issuables_list/components/issuable.vue +++ b/app/assets/javascripts/issuables_list/components/issuable.vue @@ -3,8 +3,11 @@ * This is tightly coupled to projects/issues/_issue.html.haml, * any changes done to the haml need to be reflected here. */ + +// TODO: need to move this component to graphql - https://gitlab.com/gitlab-org/gitlab/-/issues/221246 import { escape, isNumber } from 'lodash'; -import { GlLink, GlTooltipDirective as GlTooltip, GlSprintf } from '@gitlab/ui'; +import { GlLink, GlTooltipDirective as GlTooltip, GlSprintf, GlLabel, GlIcon } from '@gitlab/ui'; +import jiraLogo from '@gitlab/svgs/dist/illustrations/logos/jira.svg'; import { dateInWords, formatDate, @@ -16,22 +19,26 @@ import { import { sprintf, __ } from '~/locale'; import initUserPopovers from '~/user_popovers'; import { mergeUrlParams } from '~/lib/utils/url_utility'; -import Icon from '~/vue_shared/components/icon.vue'; import IssueAssignees from '~/vue_shared/components/issue/issue_assignees.vue'; +import { isScopedLabel } from '~/lib/utils/common_utils'; +import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; export default { i18n: { openedAgo: __('opened %{timeAgoString} by %{user}'), + openedAgoJira: __('opened %{timeAgoString} by %{user} in Jira'), }, components: { - Icon, IssueAssignees, GlLink, + GlLabel, + GlIcon, GlSprintf, }, directives: { GlTooltip, }, + mixins: [glFeatureFlagsMixin()], props: { issuable: { type: Object, @@ -55,14 +62,19 @@ export default { }, }, }, + data() { + return { + jiraLogo, + }; + }, computed: { milestoneLink() { const { title } = this.issuable.milestone; return this.issuableLink({ milestone_title: title }); }, - hasLabels() { - return Boolean(this.issuable.labels && this.issuable.labels.length); + scopedLabelsAvailable() { + return this.glFeatures.scopedLabels; }, hasWeight() { return isNumber(this.issuable.weight); @@ -82,6 +94,12 @@ export default { isClosed() { return this.issuable.state === 'closed'; }, + isJiraIssue() { + return this.issuable.external_tracker === 'jira'; + }, + linkTarget() { + return this.isJiraIssue ? '_blank' : null; + }, issueCreatedToday() { return getDayDifference(new Date(this.issuable.created_at), new Date()) < 1; }, @@ -147,14 +165,14 @@ export default { value: this.issuable.upvotes, title: __('Upvotes'), class: 'js-upvotes', - faicon: 'fa-thumbs-up', + icon: 'thumb-up', }, { key: 'downvotes', value: this.issuable.downvotes, title: __('Downvotes'), class: 'js-downvotes', - faicon: 'fa-thumbs-down', + icon: 'thumb-down', }, ]; }, @@ -165,16 +183,17 @@ export default { initUserPopovers([this.$refs.openedAgoByContainer.$el]); }, methods: { - labelStyle(label) { - return { - backgroundColor: label.color, - color: label.text_color, - }; - }, issuableLink(params) { return mergeUrlParams(params, this.baseUrl); }, + isScoped({ name }) { + return isScopedLabel({ title: name }) && this.scopedLabelsAvailable; + }, labelHref({ name }) { + if (this.isJiraIssue) { + return this.issuableLink({ 'labels[]': name }); + } + return this.issuableLink({ 'label_name[]': name }); }, onSelect(ev) { @@ -214,14 +233,23 @@ export default { <div class="flex-grow-1"> <div class="title"> <span class="issue-title-text"> - <i + <gl-icon v-if="issuable.confidential" v-gl-tooltip - class="fa fa-eye-slash" + name="eye-slash" + class="gl-vertical-align-text-bottom" + :size="16" :title="$options.confidentialTooltipText" :aria-label="$options.confidentialTooltipText" - ></i> - <gl-link :href="issuable.web_url">{{ issuable.title }}</gl-link> + /> + <gl-link :href="issuable.web_url" :target="linkTarget" data-testid="issuable-title"> + {{ issuable.title }} + <gl-icon + v-if="isJiraIssue" + name="external-link" + class="gl-vertical-align-text-bottom" + /> + </gl-link> </span> <span v-if="issuable.has_tasks" class="ml-1 task-status d-none d-sm-inline-block"> {{ issuable.task_status }} @@ -229,11 +257,21 @@ export default { </div> <div class="issuable-info"> - <span class="js-ref-path">{{ referencePath }}</span> + <span class="js-ref-path"> + <span + v-if="isJiraIssue" + class="svg-container jira-logo-container" + data-testid="jira-logo" + v-html="jiraLogo" + ></span> + {{ referencePath }} + </span> <span data-testid="openedByMessage" class="d-none d-sm-inline-block mr-1"> · - <gl-sprintf :message="$options.i18n.openedAgo"> + <gl-sprintf + :message="isJiraIssue ? $options.i18n.openedAgoJira : $options.i18n.openedAgo" + > <template #timeAgoString> <span>{{ issuableCreatedAt }}</span> </template> @@ -242,6 +280,7 @@ export default { ref="openedAgoByContainer" v-bind="popoverDataAttrs" :href="issuableAuthor.web_url" + :target="linkTarget" > {{ issuableAuthor.name }} </gl-link> @@ -271,30 +310,29 @@ export default { {{ dueDateWords }} </span> - <span v-if="hasLabels" class="js-labels"> - <gl-link - v-for="label in issuable.labels" - :key="label.id" - class="label-link mr-1" - :href="labelHref(label)" - > - <span - v-gl-tooltip - class="badge color-label" - :style="labelStyle(label)" - :title="label.description" - >{{ label.name }}</span - > - </gl-link> - </span> + <gl-label + v-for="label in issuable.labels" + :key="label.id" + data-qa-selector="issuable-label" + :target="labelHref(label)" + :background-color="label.color" + :description="label.description" + :color="label.text_color" + :title="label.name" + :scoped="isScoped(label)" + size="sm" + class="mr-1" + >{{ label.name }}</gl-label + > <span v-if="hasWeight" v-gl-tooltip :title="__('Weight')" class="d-none d-sm-inline-block js-weight" + data-testid="weight" > - <icon name="weight" class="align-text-bottom" /> + <gl-icon name="weight" class="align-text-bottom" /> {{ issuable.weight }} </span> </div> @@ -303,7 +341,8 @@ export default { <!-- Issuable meta --> <div class="flex-shrink-0 d-flex flex-column align-items-end justify-content-center"> <div class="controls d-flex"> - <span v-if="isClosed" class="issuable-status">{{ __('CLOSED') }}</span> + <span v-if="isJiraIssue" data-testid="issuable-status">{{ issuable.status }}</span> + <span v-else-if="isClosed" class="issuable-status">{{ __('CLOSED') }}</span> <issue-assignees :assignees="issuable.assignees" @@ -318,23 +357,23 @@ export default { v-if="meta.value" :key="meta.key" v-gl-tooltip - :class="['d-none d-sm-inline-block ml-2', meta.class]" + :class="['d-none d-sm-inline-block ml-2 vertical-align-middle', meta.class]" :title="meta.title" > - <icon v-if="meta.icon" :name="meta.icon" /> - <i v-else :class="['fa', meta.faicon]"></i> + <gl-icon v-if="meta.icon" :name="meta.icon" /> {{ meta.value }} </span> </template> <gl-link + v-if="!isJiraIssue" v-gl-tooltip class="ml-2 js-notes" :href="`${issuable.web_url}#notes`" :title="__('Comments')" :class="{ 'no-comments': hasNoComments }" > - <i class="fa fa-comments"></i> + <gl-icon name="comments" class="gl-vertical-align-text-bottom" /> {{ userNotesCount }} </gl-link> </div> |