Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-04-20 21:38:24 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-04-20 21:38:24 +0300
commit983a0bba5d2a042c4a3bbb22432ec192c7501d82 (patch)
treeb153cd387c14ba23bd5a07514c7c01fddf6a78a0 /app/assets/javascripts/vue_shared/components
parenta2bddee2cdb38673df0e004d5b32d9f77797de64 (diff)
Add latest changes from gitlab-org/gitlab@12-10-stable-ee
Diffstat (limited to 'app/assets/javascripts/vue_shared/components')
-rw-r--r--app/assets/javascripts/vue_shared/components/awards_list.vue178
-rw-r--r--app/assets/javascripts/vue_shared/components/clone_dropdown.vue12
-rw-r--r--app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/form/title.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/toggle_sidebar.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue40
6 files changed, 191 insertions, 45 deletions
diff --git a/app/assets/javascripts/vue_shared/components/awards_list.vue b/app/assets/javascripts/vue_shared/components/awards_list.vue
new file mode 100644
index 00000000000..848295cc984
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/awards_list.vue
@@ -0,0 +1,178 @@
+<script>
+import { groupBy } from 'lodash';
+import { GlIcon } from '@gitlab/ui';
+import tooltip from '~/vue_shared/directives/tooltip';
+import { glEmojiTag } from '../../emoji';
+import { __, sprintf } from '~/locale';
+
+// Internal constant, specific to this component, used when no `currentUserId` is given
+const NO_USER_ID = -1;
+
+export default {
+ components: {
+ GlIcon,
+ },
+ directives: {
+ tooltip,
+ },
+ props: {
+ awards: {
+ type: Array,
+ required: true,
+ },
+ canAwardEmoji: {
+ type: Boolean,
+ required: true,
+ },
+ currentUserId: {
+ type: Number,
+ required: false,
+ default: NO_USER_ID,
+ },
+ addButtonClass: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ },
+ computed: {
+ groupedAwards() {
+ const { thumbsup, thumbsdown, ...rest } = groupBy(this.awards, x => x.name);
+
+ return [
+ ...(thumbsup ? [this.createAwardList('thumbsup', thumbsup)] : []),
+ ...(thumbsdown ? [this.createAwardList('thumbsdown', thumbsdown)] : []),
+ ...Object.entries(rest).map(([name, list]) => this.createAwardList(name, list)),
+ ];
+ },
+ isAuthoredByMe() {
+ return this.noteAuthorId === this.currentUserId;
+ },
+ },
+ methods: {
+ getAwardClassBindings(awardList) {
+ return {
+ active: this.hasReactionByCurrentUser(awardList),
+ disabled: this.currentUserId === NO_USER_ID,
+ };
+ },
+ hasReactionByCurrentUser(awardList) {
+ if (this.currentUserId === NO_USER_ID) {
+ return false;
+ }
+
+ return awardList.some(award => award.user.id === this.currentUserId);
+ },
+ createAwardList(name, list) {
+ return {
+ name,
+ list,
+ title: this.getAwardListTitle(list),
+ classes: this.getAwardClassBindings(list),
+ html: glEmojiTag(name),
+ };
+ },
+ getAwardListTitle(awardsList) {
+ const hasReactionByCurrentUser = this.hasReactionByCurrentUser(awardsList);
+ const TOOLTIP_NAME_COUNT = hasReactionByCurrentUser ? 9 : 10;
+ let awardList = awardsList;
+
+ // Filter myself from list if I am awarded.
+ if (hasReactionByCurrentUser) {
+ awardList = awardList.filter(award => award.user.id !== this.currentUserId);
+ }
+
+ // Get only 9-10 usernames to show in tooltip text.
+ const namesToShow = awardList.slice(0, TOOLTIP_NAME_COUNT).map(award => award.user.name);
+
+ // Get the remaining list to use in `and x more` text.
+ const remainingAwardList = awardList.slice(TOOLTIP_NAME_COUNT, awardList.length);
+
+ // Add myself to the beginning of the list so title will start with You.
+ if (hasReactionByCurrentUser) {
+ namesToShow.unshift(__('You'));
+ }
+
+ let title = '';
+
+ // We have 10+ awarded user, join them with comma and add `and x more`.
+ if (remainingAwardList.length) {
+ title = sprintf(
+ __(`%{listToShow}, and %{awardsListLength} more.`),
+ {
+ listToShow: namesToShow.join(', '),
+ awardsListLength: remainingAwardList.length,
+ },
+ false,
+ );
+ } else if (namesToShow.length > 1) {
+ // Join all names with comma but not the last one, it will be added with and text.
+ title = namesToShow.slice(0, namesToShow.length - 1).join(', ');
+ // If we have more than 2 users we need an extra comma before and text.
+ title += namesToShow.length > 2 ? ',' : '';
+ title += sprintf(__(` and %{sliced}`), { sliced: namesToShow.slice(-1) }, false); // Append and text
+ } else {
+ // We have only 2 users so join them with and.
+ title = namesToShow.join(__(' and '));
+ }
+
+ return title;
+ },
+ handleAward(awardName) {
+ if (!this.canAwardEmoji) {
+ return;
+ }
+
+ // 100 and 1234 emoji are a number. Callback for v-for click sends it as a string
+ const parsedName = /^[0-9]+$/.test(awardName) ? Number(awardName) : awardName;
+
+ this.$emit('award', parsedName);
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="awards js-awards-block">
+ <button
+ v-for="awardList in groupedAwards"
+ :key="awardList.name"
+ v-tooltip
+ :class="awardList.classes"
+ :title="awardList.title"
+ data-boundary="viewport"
+ data-testid="award-button"
+ class="btn award-control"
+ type="button"
+ @click="handleAward(awardList.name)"
+ >
+ <span data-testid="award-html" v-html="awardList.html"></span>
+ <span class="award-control-text js-counter">{{ awardList.list.length }}</span>
+ </button>
+ <div v-if="canAwardEmoji" class="award-menu-holder">
+ <button
+ v-tooltip
+ :class="addButtonClass"
+ class="award-control btn js-add-award"
+ title="Add reaction"
+ :aria-label="__('Add reaction')"
+ data-boundary="viewport"
+ type="button"
+ >
+ <span class="award-control-icon award-control-icon-neutral">
+ <gl-icon aria-hidden="true" name="slight-smile" />
+ </span>
+ <span class="award-control-icon award-control-icon-positive">
+ <gl-icon aria-hidden="true" name="smiley" />
+ </span>
+ <span class="award-control-icon award-control-icon-super-positive">
+ <gl-icon aria-hidden="true" name="smiley" />
+ </span>
+ <i
+ aria-hidden="true"
+ class="fa fa-spinner fa-spin award-control-icon award-control-icon-loading"
+ ></i>
+ </button>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/clone_dropdown.vue b/app/assets/javascripts/vue_shared/components/clone_dropdown.vue
index 3b9b9f37f52..7826c179889 100644
--- a/app/assets/javascripts/vue_shared/components/clone_dropdown.vue
+++ b/app/assets/javascripts/vue_shared/components/clone_dropdown.vue
@@ -3,7 +3,7 @@ import {
GlNewDropdown,
GlNewDropdownHeader,
GlFormInputGroup,
- GlNewButton,
+ GlButton,
GlIcon,
GlTooltipDirective,
} from '@gitlab/ui';
@@ -15,7 +15,7 @@ export default {
GlNewDropdown,
GlNewDropdownHeader,
GlFormInputGroup,
- GlNewButton,
+ GlButton,
GlIcon,
},
directives: {
@@ -55,13 +55,13 @@ export default {
<div class="mx-3">
<gl-form-input-group :value="sshLink" readonly select-on-click>
<template #append>
- <gl-new-button
+ <gl-button
v-gl-tooltip.hover
:title="$options.copyURLTooltip"
:data-clipboard-text="sshLink"
>
<gl-icon name="copy-to-clipboard" :title="$options.copyURLTooltip" />
- </gl-new-button>
+ </gl-button>
</template>
</gl-form-input-group>
</div>
@@ -73,13 +73,13 @@ export default {
<div class="mx-3">
<gl-form-input-group :value="httpLink" readonly select-on-click>
<template #append>
- <gl-new-button
+ <gl-button
v-gl-tooltip.hover
:title="$options.copyURLTooltip"
:data-clipboard-text="httpLink"
>
<gl-icon name="copy-to-clipboard" :title="$options.copyURLTooltip" />
- </gl-new-button>
+ </gl-button>
</template>
</gl-form-input-group>
</div>
diff --git a/app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker.vue b/app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker.vue
index cdcd5cdef7f..ffc616d7309 100644
--- a/app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker.vue
+++ b/app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker.vue
@@ -158,7 +158,7 @@ export default {
<template>
<tooltip-on-truncate
:title="timeWindowText"
- :truncate-target="elem => elem.querySelector('.date-time-picker-toggle')"
+ :truncate-target="elem => elem.querySelector('.gl-dropdown-toggle-text')"
placement="top"
class="d-inline-block"
>
diff --git a/app/assets/javascripts/vue_shared/components/form/title.vue b/app/assets/javascripts/vue_shared/components/form/title.vue
index f8f70529bd1..fad69dc1e24 100644
--- a/app/assets/javascripts/vue_shared/components/form/title.vue
+++ b/app/assets/javascripts/vue_shared/components/form/title.vue
@@ -10,6 +10,6 @@ export default {
</script>
<template>
<gl-form-group :label="__('Title')" label-for="title-field-edit">
- <gl-form-input id="title-field-edit" v-bind="$attrs" v-on="$listeners" />
+ <gl-form-input v-bind="$attrs" v-on="$listeners" />
</gl-form-group>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/toggle_sidebar.vue b/app/assets/javascripts/vue_shared/components/sidebar/toggle_sidebar.vue
index 913c971a512..040a15406e0 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/toggle_sidebar.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/toggle_sidebar.vue
@@ -37,7 +37,7 @@ export default {
:title="tooltipLabel"
:class="cssClasses"
type="button"
- class="btn btn-blank gutter-toggle btn-sidebar-action"
+ class="btn btn-blank gutter-toggle btn-sidebar-action js-sidebar-vue-toggle"
data-container="body"
data-placement="left"
data-boundary="viewport"
diff --git a/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue b/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue
index 602d4ab89e1..595baeeb14f 100644
--- a/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue
+++ b/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue
@@ -1,10 +1,8 @@
<script>
-import { GlPopover, GlSkeletonLoading, GlSprintf } from '@gitlab/ui';
+import { GlPopover, GlSkeletonLoading } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
import UserAvatarImage from '../user_avatar/user_avatar_image.vue';
import { glEmojiTag } from '../../../emoji';
-import { s__ } from '~/locale';
-import { isString } from 'lodash';
export default {
name: 'UserPopover',
@@ -12,7 +10,6 @@ export default {
Icon,
GlPopover,
GlSkeletonLoading,
- GlSprintf,
UserAvatarImage,
},
props: {
@@ -49,26 +46,7 @@ export default {
return !this.user.name;
},
workInformationIsLoading() {
- return !this.user.loaded && this.workInformation === null;
- },
- workInformation() {
- const { jobTitle, organization } = this.user;
-
- if (organization && jobTitle) {
- return {
- message: s__('Profile|%{job_title} at %{organization}'),
- placeholders: { job_title: jobTitle, organization },
- };
- } else if (organization) {
- return organization;
- } else if (jobTitle) {
- return jobTitle;
- }
-
- return null;
- },
- workInformationShouldUseSprintf() {
- return !isString(this.workInformation);
+ return !this.user.loaded && this.user.workInformation === null;
},
locationIsLoading() {
return !this.user.loaded && this.user.location === null;
@@ -98,23 +76,13 @@ export default {
<icon name="profile" class="category-icon flex-shrink-0" />
<span ref="bio" class="ml-1">{{ user.bio }}</span>
</div>
- <div v-if="workInformation" class="d-flex mb-1">
+ <div v-if="user.workInformation" class="d-flex mb-1">
<icon
v-show="!workInformationIsLoading"
name="work"
class="category-icon flex-shrink-0"
/>
- <span ref="workInformation" class="ml-1">
- <gl-sprintf v-if="workInformationShouldUseSprintf" :message="workInformation.message">
- <template
- v-for="(placeholder, slotName) in workInformation.placeholders"
- v-slot:[slotName]
- >
- <span :key="slotName">{{ placeholder }}</span>
- </template>
- </gl-sprintf>
- <span v-else>{{ workInformation }}</span>
- </span>
+ <span ref="workInformation" class="ml-1">{{ user.workInformation }}</span>
</div>
<gl-skeleton-loading
v-if="workInformationIsLoading"