debian-mirror-gitlab/app/assets/javascripts/sidebar/components/assignees/assignees.vue

251 lines
7 KiB
Vue
Raw Normal View History

2018-03-27 19:54:05 +05:30
<script>
2019-09-30 21:07:59 +05:30
import { __, sprintf } from '~/locale';
2018-10-15 14:42:47 +05:30
import tooltip from '~/vue_shared/directives/tooltip';
2018-03-27 19:54:05 +05:30
export default {
2019-10-12 21:52:04 +05:30
// name: 'Assignees' is a false positive: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/26#possible-false-positives
// eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
2018-03-27 19:54:05 +05:30
name: 'Assignees',
2018-10-15 14:42:47 +05:30
directives: {
tooltip,
},
2018-03-27 19:54:05 +05:30
props: {
rootPath: {
type: String,
required: true,
},
users: {
type: Array,
required: true,
},
editable: {
type: Boolean,
required: true,
},
2018-10-15 14:42:47 +05:30
issuableType: {
type: String,
require: true,
default: 'issue',
},
2018-03-27 19:54:05 +05:30
},
data() {
return {
defaultRenderCount: 5,
defaultMaxCounter: 99,
showLess: true,
};
},
computed: {
firstUser() {
return this.users[0];
},
hasMoreThanTwoAssignees() {
return this.users.length > 2;
},
hasMoreThanOneAssignee() {
return this.users.length > 1;
},
hasAssignees() {
return this.users.length > 0;
},
hasNoUsers() {
return !this.users.length;
},
hasOneUser() {
return this.users.length === 1;
},
renderShowMoreSection() {
return this.users.length > this.defaultRenderCount;
},
numberOfHiddenAssignees() {
return this.users.length - this.defaultRenderCount;
},
isHiddenAssignees() {
return this.numberOfHiddenAssignees > 0;
},
hiddenAssigneesLabel() {
2019-09-30 21:07:59 +05:30
const { numberOfHiddenAssignees } = this;
return sprintf(__('+ %{numberOfHiddenAssignees} more'), { numberOfHiddenAssignees });
2018-03-27 19:54:05 +05:30
},
collapsedTooltipTitle() {
const maxRender = Math.min(this.defaultRenderCount, this.users.length);
const renderUsers = this.users.slice(0, maxRender);
const names = renderUsers.map(u => u.name);
if (this.users.length > maxRender) {
names.push(`+ ${this.users.length - maxRender} more`);
}
2018-10-15 14:42:47 +05:30
if (!this.users.length) {
2019-07-31 22:56:46 +05:30
const emptyTooltipLabel = __('Assignee(s)');
2018-10-15 14:42:47 +05:30
names.push(emptyTooltipLabel);
}
2018-03-27 19:54:05 +05:30
return names.join(', ');
},
sidebarAvatarCounter() {
let counter = `+${this.users.length - 1}`;
if (this.users.length > this.defaultMaxCounter) {
counter = `${this.defaultMaxCounter}+`;
}
return counter;
},
2019-07-31 22:56:46 +05:30
mergeNotAllowedTooltipMessage() {
const assigneesCount = this.users.length;
if (this.issuableType !== 'merge_request' || assigneesCount === 0) {
return null;
}
const cannotMergeCount = this.users.filter(u => u.can_merge === false).length;
const canMergeCount = assigneesCount - cannotMergeCount;
if (canMergeCount === assigneesCount) {
// Everyone can merge
return null;
} else if (cannotMergeCount === assigneesCount && assigneesCount > 1) {
2019-09-30 21:07:59 +05:30
return __('No one can merge');
2019-07-31 22:56:46 +05:30
} else if (assigneesCount === 1) {
2019-09-30 21:07:59 +05:30
return __('Cannot merge');
2019-07-31 22:56:46 +05:30
}
2019-09-30 21:07:59 +05:30
return sprintf(__('%{canMergeCount}/%{assigneesCount} can merge'), {
canMergeCount,
assigneesCount,
});
2019-07-31 22:56:46 +05:30
},
2018-03-27 19:54:05 +05:30
},
methods: {
assignSelf() {
this.$emit('assign-self');
},
toggleShowLess() {
this.showLess = !this.showLess;
},
renderAssignee(index) {
return !this.showLess || (index < this.defaultRenderCount && this.showLess);
},
avatarUrl(user) {
return user.avatar || user.avatar_url || gon.default_avatar_url;
},
assigneeUrl(user) {
return `${this.rootPath}${user.username}`;
},
assigneeAlt(user) {
2019-09-30 21:07:59 +05:30
return sprintf(__("%{userName}'s avatar"), { userName: user.name });
2018-03-27 19:54:05 +05:30
},
assigneeUsername(user) {
return `@${user.username}`;
},
shouldRenderCollapsedAssignee(index) {
const firstTwo = this.users.length <= 2 && index <= 2;
return index === 0 || firstTwo;
},
},
};
</script>
<template>
<div>
<div
2018-10-15 14:42:47 +05:30
v-tooltip
2018-11-08 19:23:39 +05:30
:class="{ 'multiple-users': hasMoreThanOneAssignee }"
:title="collapsedTooltipTitle"
class="sidebar-collapsed-icon sidebar-collapsed-user"
2018-03-27 19:54:05 +05:30
data-container="body"
data-placement="left"
2018-11-08 19:23:39 +05:30
data-boundary="viewport"
2018-03-27 19:54:05 +05:30
>
2019-09-30 21:07:59 +05:30
<i v-if="hasNoUsers" :aria-label="__('None')" class="fa fa-user"> </i>
2018-03-27 19:54:05 +05:30
<button
v-for="(user, index) in users"
v-if="shouldRenderCollapsedAssignee(index)"
:key="user.id"
2018-11-08 19:23:39 +05:30
type="button"
class="btn-link"
2018-03-27 19:54:05 +05:30
>
<img
:alt="assigneeAlt(user)"
:src="avatarUrl(user)"
2018-11-08 19:23:39 +05:30
width="24"
class="avatar avatar-inline s24"
2018-03-27 19:54:05 +05:30
/>
2019-02-15 15:39:39 +05:30
<span class="author"> {{ user.name }} </span>
2018-03-27 19:54:05 +05:30
</button>
2019-02-15 15:39:39 +05:30
<button v-if="hasMoreThanTwoAssignees" class="btn-link" type="button">
<span class="avatar-counter sidebar-avatar-counter"> {{ sidebarAvatarCounter }} </span>
2018-03-27 19:54:05 +05:30
</button>
</div>
<div class="value hide-collapsed">
2019-07-31 22:56:46 +05:30
<span
v-if="mergeNotAllowedTooltipMessage"
v-tooltip
:title="mergeNotAllowedTooltipMessage"
data-placement="left"
class="float-right cannot-be-merged"
>
<i aria-hidden="true" data-hidden="true" class="fa fa-exclamation-triangle"></i>
</span>
2018-03-27 19:54:05 +05:30
<template v-if="hasNoUsers">
2019-07-31 22:56:46 +05:30
<span class="assign-yourself no-value qa-assign-yourself">
2019-09-30 21:07:59 +05:30
{{ __('None') }}
2018-03-27 19:54:05 +05:30
<template v-if="editable">
2019-09-30 21:07:59 +05:30
-
<button type="button" class="btn-link" @click="assignSelf">
{{ __('assign yourself') }}
</button>
2018-03-27 19:54:05 +05:30
</template>
</span>
</template>
<template v-else-if="hasOneUser">
2019-02-15 15:39:39 +05:30
<a :href="assigneeUrl(firstUser)" class="author-link bold">
2018-03-27 19:54:05 +05:30
<img
:alt="assigneeAlt(firstUser)"
:src="avatarUrl(firstUser)"
2018-11-08 19:23:39 +05:30
width="32"
class="avatar avatar-inline s32"
2018-03-27 19:54:05 +05:30
/>
2019-02-15 15:39:39 +05:30
<span class="author"> {{ firstUser.name }} </span>
<span class="username"> {{ assigneeUsername(firstUser) }} </span>
2018-03-27 19:54:05 +05:30
</a>
</template>
<template v-else>
<div class="user-list">
<div
v-for="(user, index) in users"
v-if="renderAssignee(index)"
:key="user.id"
2018-11-08 19:23:39 +05:30
class="user-item"
2018-03-27 19:54:05 +05:30
>
<a
2018-11-08 19:23:39 +05:30
:href="assigneeUrl(user)"
:data-title="user.name"
2018-03-27 19:54:05 +05:30
class="user-link has-tooltip"
data-container="body"
data-placement="bottom"
>
<img
:alt="assigneeAlt(user)"
:src="avatarUrl(user)"
2018-11-08 19:23:39 +05:30
width="32"
class="avatar avatar-inline s32"
2018-03-27 19:54:05 +05:30
/>
</a>
</div>
</div>
2019-02-15 15:39:39 +05:30
<div v-if="renderShowMoreSection" class="user-list-more">
<button type="button" class="btn-link" @click="toggleShowLess">
2018-03-27 19:54:05 +05:30
<template v-if="showLess">
{{ hiddenAssigneesLabel }}
</template>
2019-09-30 21:07:59 +05:30
<template v-else>{{ __('- show less') }}</template>
2018-03-27 19:54:05 +05:30
</button>
</div>
</template>
</div>
</div>
</template>