summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/issuable/components/issue_assignees.vue
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/issuable/components/issue_assignees.vue')
-rw-r--r--app/assets/javascripts/issuable/components/issue_assignees.vue107
1 files changed, 107 insertions, 0 deletions
diff --git a/app/assets/javascripts/issuable/components/issue_assignees.vue b/app/assets/javascripts/issuable/components/issue_assignees.vue
new file mode 100644
index 00000000000..5955f31fc70
--- /dev/null
+++ b/app/assets/javascripts/issuable/components/issue_assignees.vue
@@ -0,0 +1,107 @@
+<script>
+import { GlTooltipDirective } from '@gitlab/ui';
+import { __, sprintf } from '~/locale';
+import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
+
+export default {
+ components: {
+ UserAvatarLink,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ assignees: {
+ type: Array,
+ required: true,
+ },
+ iconSize: {
+ type: Number,
+ required: false,
+ default: 24,
+ },
+ imgCssClasses: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ maxVisible: {
+ type: Number,
+ required: false,
+ default: 3,
+ },
+ },
+ data() {
+ return {
+ maxAssignees: 99,
+ };
+ },
+ computed: {
+ assigneesToShow() {
+ const numShownAssignees = this.assignees.length - this.numHiddenAssignees;
+ return this.assignees.slice(0, numShownAssignees);
+ },
+ assigneesCounterTooltip() {
+ return sprintf(__('%{count} more assignees'), { count: this.numHiddenAssignees });
+ },
+ numHiddenAssignees() {
+ if (this.assignees.length > this.maxVisible) {
+ return this.assignees.length - this.maxVisible + 1;
+ }
+ return 0;
+ },
+ assigneeCounterLabel() {
+ if (this.numHiddenAssignees > this.maxAssignees) {
+ return `${this.maxAssignees}+`;
+ }
+
+ return `+${this.numHiddenAssignees}`;
+ },
+ },
+ methods: {
+ avatarUrlTitle(assignee) {
+ return sprintf(__('Assigned to %{assigneeName}'), {
+ assigneeName: assignee.name,
+ });
+ },
+ // This method is for backward compat
+ // since Graph query would return camelCase
+ // props while Rails would return snake_case
+ webUrl(assignee) {
+ return assignee.web_url || assignee.webUrl;
+ },
+ avatarUrl(assignee) {
+ return assignee.avatar_url || assignee.avatarUrl;
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <user-avatar-link
+ v-for="assignee in assigneesToShow"
+ :key="assignee.id"
+ :link-href="webUrl(assignee)"
+ :img-alt="avatarUrlTitle(assignee)"
+ :img-css-classes="imgCssClasses"
+ :img-src="avatarUrl(assignee)"
+ :img-size="iconSize"
+ class="js-no-trigger author-link"
+ tooltip-placement="bottom"
+ data-qa-selector="assignee_link"
+ >
+ <span class="js-assignee-tooltip">
+ <span class="bold d-block">{{ __('Assignee') }}</span> {{ assignee.name }}
+ <span v-if="assignee.username" class="text-white-50">@{{ assignee.username }}</span>
+ </span>
+ </user-avatar-link>
+ <span
+ v-if="numHiddenAssignees > 0"
+ v-gl-tooltip.bottom
+ :title="assigneesCounterTooltip"
+ class="avatar-counter"
+ data-qa-selector="avatar_counter_content"
+ >{{ assigneeCounterLabel }}</span
+ >
+ </div>
+</template>