diff options
Diffstat (limited to 'app/assets/javascripts/vue_shared/components')
26 files changed, 225 insertions, 208 deletions
diff --git a/app/assets/javascripts/vue_shared/components/awards_list.vue b/app/assets/javascripts/vue_shared/components/awards_list.vue index ce67d33d4a1..82b3545117f 100644 --- a/app/assets/javascripts/vue_shared/components/awards_list.vue +++ b/app/assets/javascripts/vue_shared/components/awards_list.vue @@ -2,7 +2,9 @@ /* eslint-disable vue/no-v-html */ import { GlIcon, GlButton, GlTooltipDirective } from '@gitlab/ui'; import { groupBy } from 'lodash'; +import EmojiPicker from '~/emoji/components/picker.vue'; import { __, sprintf } from '~/locale'; +import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import { glEmojiTag } from '../../emoji'; // Internal constant, specific to this component, used when no `currentUserId` is given @@ -12,10 +14,12 @@ export default { components: { GlButton, GlIcon, + EmojiPicker, }, directives: { GlTooltip: GlTooltipDirective, }, + mixins: [glFeatureFlagsMixin()], props: { awards: { type: Array, @@ -166,7 +170,25 @@ export default { <span class="js-counter">{{ awardList.list.length }}</span> </gl-button> <div v-if="canAwardEmoji" class="award-menu-holder"> + <emoji-picker + v-if="glFeatures.improvedEmojiPicker" + toggle-class="add-reaction-button gl-relative!" + @click="handleAward" + > + <template #button-content> + <span class="reaction-control-icon reaction-control-icon-neutral"> + <gl-icon name="slight-smile" /> + </span> + <span class="reaction-control-icon reaction-control-icon-positive"> + <gl-icon name="smiley" /> + </span> + <span class="reaction-control-icon reaction-control-icon-super-positive"> + <gl-icon name="smile" /> + </span> + </template> + </emoji-picker> <gl-button + v-else v-gl-tooltip.viewport :class="addButtonClass" class="add-reaction-button js-add-award" diff --git a/app/assets/javascripts/vue_shared/components/changed_file_icon.vue b/app/assets/javascripts/vue_shared/components/changed_file_icon.vue index 14e99977a85..4b53f55b856 100644 --- a/app/assets/javascripts/vue_shared/components/changed_file_icon.vue +++ b/app/assets/javascripts/vue_shared/components/changed_file_icon.vue @@ -82,7 +82,13 @@ export default { data-qa-selector="changed_file_icon_content" :data-qa-title="tooltipTitle" > - <gl-icon v-if="showIcon" :name="changedIcon" :size="size" :class="changedIconClass" /> + <gl-icon + v-if="showIcon" + :name="changedIcon" + :size="size" + :class="changedIconClass" + use-deprecated-sizes + /> </span> </template> diff --git a/app/assets/javascripts/vue_shared/components/ci_icon.vue b/app/assets/javascripts/vue_shared/components/ci_icon.vue index 07bd6019b80..dbf459cb289 100644 --- a/app/assets/javascripts/vue_shared/components/ci_icon.vue +++ b/app/assets/javascripts/vue_shared/components/ci_icon.vue @@ -64,6 +64,12 @@ export default { </script> <template> <span :class="cssClass"> - <gl-icon :name="icon" :size="size" :class="cssClasses" :aria-label="status.icon" /> + <gl-icon + :name="icon" + :size="size" + :class="cssClasses" + :aria-label="status.icon" + use-deprecated-sizes + /> </span> </template> diff --git a/app/assets/javascripts/vue_shared/components/clipboard_button.vue b/app/assets/javascripts/vue_shared/components/clipboard_button.vue index bf1361f1a6a..fe329b18f30 100644 --- a/app/assets/javascripts/vue_shared/components/clipboard_button.vue +++ b/app/assets/javascripts/vue_shared/components/clipboard_button.vue @@ -46,6 +46,11 @@ export default { required: false, default: false, }, + tooltipBoundary: { + type: String, + required: false, + default: null, + }, cssClass: { type: String, required: false, @@ -75,8 +80,11 @@ export default { <template> <gl-button - v-gl-tooltip="{ placement: tooltipPlacement, container: tooltipContainer }" - v-gl-tooltip.hover.blur + v-gl-tooltip.hover.blur.viewport="{ + placement: tooltipPlacement, + container: tooltipContainer, + boundary: tooltipBoundary, + }" :class="cssClass" :title="title" :data-clipboard-text="clipboardText" diff --git a/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/renamed.vue b/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/renamed.vue index d6f99e9a049..b3edd05b0ee 100644 --- a/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/renamed.vue +++ b/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/renamed.vue @@ -37,9 +37,11 @@ export default { required: true, }, }, - data: () => ({ - state: STATE_IDLING, - }), + data() { + return { + state: STATE_IDLING, + }; + }, computed: { shortSha() { return truncateSha(this.diffFile.content_sha); diff --git a/app/assets/javascripts/vue_shared/components/file_icon.vue b/app/assets/javascripts/vue_shared/components/file_icon.vue index 8ac8a3beb7d..4244cab902a 100644 --- a/app/assets/javascripts/vue_shared/components/file_icon.vue +++ b/app/assets/javascripts/vue_shared/components/file_icon.vue @@ -86,7 +86,7 @@ export default { <template> <span> <gl-loading-icon v-if="loading" :inline="true" /> - <gl-icon v-else-if="isSymlink" name="symlink" :size="size" /> + <gl-icon v-else-if="isSymlink" name="symlink" :size="size" use-deprecated-sizes /> <svg v-else-if="!folder" :key="spriteHref" :class="[iconSizeClass, cssClasses]"> <use v-bind="{ 'xlink:href': spriteHref }" /> </svg> @@ -95,6 +95,7 @@ export default { :name="folderIconName" :size="size" class="folder-icon" + use-deprecated-sizes data-qa-selector="folder_icon_content" /> </span> diff --git a/app/assets/javascripts/vue_shared/components/header_ci_component.vue b/app/assets/javascripts/vue_shared/components/header_ci_component.vue index 80ca62a0e9b..b4cac13168a 100644 --- a/app/assets/javascripts/vue_shared/components/header_ci_component.vue +++ b/app/assets/javascripts/vue_shared/components/header_ci_component.vue @@ -102,7 +102,7 @@ export default { data-qa-selector="pipeline_header" data-testid="ci-header-content" > - <section class="header-main-content"> + <section class="header-main-content gl-mr-3"> <ci-icon-badge :status="status" /> <strong data-testid="ci-header-item-text"> {{ itemName }} #{{ itemId }} </strong> @@ -142,12 +142,16 @@ export default { </template> </section> - <section v-if="$slots.default" data-testid="ci-header-action-buttons" class="gl-display-flex"> + <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="d-sm-none js-sidebar-build-toggle gl-ml-auto" + 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" diff --git a/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue b/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue index 4c6fa71398d..7c28e74e256 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue @@ -62,9 +62,6 @@ export default { canBeBatched() { return Boolean(this.glFeatures.batchSuggestions); }, - canAddCustomCommitMessage() { - return this.glFeatures.suggestionsCustomCommit; - }, isApplying() { return this.isApplyingSingle || this.isApplyingBatch; }, @@ -89,11 +86,7 @@ export default { if (!this.canApply) return; this.isApplyingSingle = true; - this.$emit( - 'apply', - this.applySuggestionCallback, - gon.features?.suggestionsCustomCommit ? message : undefined, - ); + this.$emit('apply', this.applySuggestionCallback, message); }, applySuggestionCallback() { this.isApplyingSingle = false; @@ -114,7 +107,7 @@ export default { <template> <div class="md-suggestion-header border-bottom-0 mt-2"> - <div class="qa-suggestion-diff-header js-suggestion-diff-header font-weight-bold"> + <div class="js-suggestion-diff-header font-weight-bold"> {{ __('Suggested change') }} <a v-if="helpPagePath" :href="helpPagePath" :aria-label="__('Help')" class="js-help-btn"> <gl-icon name="question-o" css-classes="link-highlight" /> @@ -158,23 +151,12 @@ export default { {{ __('Add suggestion to batch') }} </gl-button> <apply-suggestion - v-if="canAddCustomCommitMessage" + v-if="isLoggedIn" :disabled="isDisableButton" :default-commit-message="defaultCommitMessage" class="gl-ml-3" @apply="applySuggestion" /> - <span v-else v-gl-tooltip.viewport="tooltipMessage" tabindex="0"> - <gl-button - v-if="isLoggedIn" - class="btn-inverted js-apply-btn btn-grouped" - :disabled="isDisableButton" - variant="success" - @click="applySuggestion" - > - {{ __('Apply suggestion') }} - </gl-button> - </span> </div> </div> </template> diff --git a/app/assets/javascripts/vue_shared/components/notes/timeline_icon.vue b/app/assets/javascripts/vue_shared/components/notes/timeline_icon.vue new file mode 100644 index 00000000000..35f9ac14681 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/notes/timeline_icon.vue @@ -0,0 +1,3 @@ +<template> + <div class="timeline-icon"><slot></slot></div> +</template> diff --git a/app/assets/javascripts/vue_shared/components/registry/code_instruction.vue b/app/assets/javascripts/vue_shared/components/registry/code_instruction.vue index bc7f8a2b17a..1a85a641dd1 100644 --- a/app/assets/javascripts/vue_shared/components/registry/code_instruction.vue +++ b/app/assets/javascripts/vue_shared/components/registry/code_instruction.vue @@ -56,27 +56,29 @@ export default { </script> <template> - <div v-if="!multiline" class="gl-mb-3"> + <div> <label v-if="label" :for="generateFormId('instruction-input')">{{ label }}</label> - <div class="input-group gl-mb-3"> - <input - :id="generateFormId('instruction-input')" - :value="instruction" - type="text" - class="form-control gl-font-monospace" - data-testid="instruction-input" - readonly - @copy="trackCopy" - /> - <span class="input-group-append" data-testid="instruction-button" @click="trackCopy"> - <clipboard-button :text="instruction" :title="copyText" class="input-group-text" /> - </span> + <div v-if="!multiline" class="gl-mb-3"> + <div class="input-group gl-mb-3"> + <input + :id="generateFormId('instruction-input')" + :value="instruction" + type="text" + class="form-control gl-font-monospace" + data-testid="instruction-input" + readonly + @copy="trackCopy" + /> + <span class="input-group-append" data-testid="instruction-button" @click="trackCopy"> + <clipboard-button :text="instruction" :title="copyText" class="input-group-text" /> + </span> + </div> </div> - </div> - <div v-else> - <pre class="gl-font-monospace" data-testid="multiline-instruction" @copy="trackCopy">{{ - instruction - }}</pre> + <div v-else> + <pre class="gl-font-monospace" data-testid="multiline-instruction" @copy="trackCopy">{{ + instruction + }}</pre> + </div> </div> </template> diff --git a/app/assets/javascripts/vue_shared/components/registry/list_item.vue b/app/assets/javascripts/vue_shared/components/registry/list_item.vue index 9db5d6953d7..4ade75e705e 100644 --- a/app/assets/javascripts/vue_shared/components/registry/list_item.vue +++ b/app/assets/javascripts/vue_shared/components/registry/list_item.vue @@ -54,7 +54,7 @@ export default { class="gl-display-flex gl-flex-direction-column gl-border-b-solid gl-border-t-solid gl-border-t-1 gl-border-b-1" :class="optionalClasses" > - <div class="gl-display-flex gl-align-items-center gl-py-3"> + <div class="gl-display-flex gl-align-items-center gl-py-3 gl-px-5"> <div v-if="$slots['left-action']" class="gl-w-7 gl-display-none gl-sm-display-flex gl-justify-content-start gl-pl-2" diff --git a/app/assets/javascripts/vue_shared/components/registry/persisted_dropdown_selection.vue b/app/assets/javascripts/vue_shared/components/registry/persisted_dropdown_selection.vue new file mode 100644 index 00000000000..36b1a9c49f4 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/registry/persisted_dropdown_selection.vue @@ -0,0 +1,59 @@ +<script> +import { GlDropdown, GlDropdownItem } from '@gitlab/ui'; +import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue'; + +export default { + name: 'PersistedDropdownSelection', + components: { + GlDropdown, + GlDropdownItem, + LocalStorageSync, + }, + props: { + options: { + type: Array, + required: true, + }, + storageKey: { + type: String, + required: true, + }, + }, + data() { + return { + selected: null, + }; + }, + computed: { + dropdownText() { + const selected = this.parsedOptions.find((o) => o.selected); + return selected?.label || this.options[0].label; + }, + parsedOptions() { + return this.options.map((o) => ({ ...o, selected: o.value === this.selected })); + }, + }, + methods: { + setSelected(value) { + this.selected = value; + this.$emit('change', value); + }, + }, +}; +</script> + +<template> + <local-storage-sync :storage-key="storageKey" :value="selected" @input="setSelected"> + <gl-dropdown :text="dropdownText" lazy> + <gl-dropdown-item + v-for="option in parsedOptions" + :key="option.value" + :is-checked="option.selected" + :is-check-item="true" + @click="setSelected(option.value)" + > + {{ option.label }} + </gl-dropdown-item> + </gl-dropdown> + </local-storage-sync> +</template> diff --git a/app/assets/javascripts/vue_shared/components/select2_select.vue b/app/assets/javascripts/vue_shared/components/select2_select.vue index 6574a5ddfde..bb1a8fae7b0 100644 --- a/app/assets/javascripts/vue_shared/components/select2_select.vue +++ b/app/assets/javascripts/vue_shared/components/select2_select.vue @@ -20,6 +20,12 @@ export default { }, }, + watch: { + value() { + $(this.$refs.dropdownInput).val(this.value).trigger('change'); + }, + }, + mounted() { loadCSSFile(gon.select2_css_path) .then(() => { diff --git a/app/assets/javascripts/vue_shared/components/settings/settings_block.vue b/app/assets/javascripts/vue_shared/components/settings/settings_block.vue index 31094b985a2..92ae4575c52 100644 --- a/app/assets/javascripts/vue_shared/components/settings/settings_block.vue +++ b/app/assets/javascripts/vue_shared/components/settings/settings_block.vue @@ -5,6 +5,11 @@ import { __ } from '~/locale'; export default { components: { GlButton }, props: { + slideAnimated: { + type: Boolean, + default: true, + required: false, + }, defaultExpanded: { type: Boolean, default: false, @@ -28,7 +33,7 @@ export default { </script> <template> - <section class="settings no-animate" :class="{ expanded }"> + <section class="settings" :class="{ 'no-animate': !slideAnimated, expanded }"> <div class="settings-header"> <h4><slot name="title"></slot></h4> <gl-button @click="sectionExpanded = !sectionExpanded"> diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_value.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_value.vue index f173c8db540..46ccb9470e5 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_value.vue +++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_value.vue @@ -21,11 +21,14 @@ export default { 'allowLabelRemove', 'allowScopedLabels', 'labelsFilterBasePath', + 'labelsFilterParam', ]), }, methods: { labelFilterUrl(label) { - return `${this.labelsFilterBasePath}?label_name[]=${encodeURIComponent(label.title)}`; + return `${this.labelsFilterBasePath}?${this.labelsFilterParam}[]=${encodeURIComponent( + label.title, + )}`; }, scopedLabel(label) { return this.allowScopedLabels && isScopedLabel(label); diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/labels_select_root.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/labels_select_root.vue index 93fdae19a8d..426ae430ce7 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/labels_select_root.vue +++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/labels_select_root.vue @@ -81,6 +81,11 @@ export default { required: false, default: '', }, + labelsFilterParam: { + type: String, + required: false, + default: 'label_name', + }, dropdownButtonText: { type: String, required: false, @@ -156,6 +161,7 @@ export default { labelsFetchPath: this.labelsFetchPath, labelsManagePath: this.labelsManagePath, labelsFilterBasePath: this.labelsFilterBasePath, + labelsFilterParam: this.labelsFilterParam, labelsListTitle: this.labelsListTitle, labelsCreateTitle: this.labelsCreateTitle, footerCreateLabelTitle: this.footerCreateLabelTitle, diff --git a/app/assets/javascripts/vue_shared/components/sidebar/multiselect_dropdown.vue b/app/assets/javascripts/vue_shared/components/sidebar/multiselect_dropdown.vue index 132abcab82b..ef5f052527b 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/multiselect_dropdown.vue +++ b/app/assets/javascripts/vue_shared/components/sidebar/multiselect_dropdown.vue @@ -1,10 +1,11 @@ <script> -import { GlDropdown, GlDropdownForm } from '@gitlab/ui'; +import { GlDropdown, GlDropdownForm, GlDropdownDivider } from '@gitlab/ui'; export default { components: { GlDropdownForm, GlDropdown, + GlDropdownDivider, }, props: { headerText: { @@ -20,8 +21,12 @@ export default { </script> <template> - <gl-dropdown class="show" :text="text" :header-text="headerText" @toggle="$emit('toggle')"> - <slot name="search"></slot> + <gl-dropdown class="show" :text="text" @toggle="$emit('toggle')"> + <template #header> + <p class="gl-font-weight-bold gl-text-center gl-mt-2 gl-mb-4">{{ headerText }}</p> + <gl-dropdown-divider /> + <slot name="search"></slot> + </template> <gl-dropdown-form> <slot name="items"></slot> </gl-dropdown-form> diff --git a/app/assets/javascripts/vue_shared/components/sidebar/queries/get_issue_participants.query.graphql b/app/assets/javascripts/vue_shared/components/sidebar/queries/get_issue_participants.query.graphql index 62c0b05426b..459ea27e9cd 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/queries/get_issue_participants.query.graphql +++ b/app/assets/javascripts/vue_shared/components/sidebar/queries/get_issue_participants.query.graphql @@ -1,8 +1,10 @@ #import "~/graphql_shared/fragments/user.fragment.graphql" query issueParticipants($fullPath: ID!, $iid: String!) { - project(fullPath: $fullPath) { + workspace: project(fullPath: $fullPath) { + __typename issuable: issue(iid: $iid) { + __typename id participants { nodes { diff --git a/app/assets/javascripts/vue_shared/components/sidebar/queries/get_mr_participants.query.graphql b/app/assets/javascripts/vue_shared/components/sidebar/queries/get_mr_participants.query.graphql index a75ce85a1dc..43bd9f17e9a 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/queries/get_mr_participants.query.graphql +++ b/app/assets/javascripts/vue_shared/components/sidebar/queries/get_mr_participants.query.graphql @@ -1,7 +1,7 @@ #import "~/graphql_shared/fragments/user.fragment.graphql" query getMrParticipants($fullPath: ID!, $iid: String!) { - project(fullPath: $fullPath) { + workspace: project(fullPath: $fullPath) { issuable: mergeRequest(iid: $iid) { id participants { diff --git a/app/assets/javascripts/vue_shared/components/sidebar/queries/update_issue_assignees.mutation.graphql b/app/assets/javascripts/vue_shared/components/sidebar/queries/update_issue_assignees.mutation.graphql index 2eb9bb4b07b..8ee8de2cb5c 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/queries/update_issue_assignees.mutation.graphql +++ b/app/assets/javascripts/vue_shared/components/sidebar/queries/update_issue_assignees.mutation.graphql @@ -1,10 +1,10 @@ #import "~/graphql_shared/fragments/user.fragment.graphql" mutation issueSetAssignees($iid: String!, $assigneeUsernames: [String!]!, $fullPath: ID!) { - issueSetAssignees( + issuableSetAssignees: issueSetAssignees( input: { iid: $iid, assigneeUsernames: $assigneeUsernames, projectPath: $fullPath } ) { - issue { + issuable: issue { id assignees { nodes { diff --git a/app/assets/javascripts/vue_shared/components/tabs/tab.vue b/app/assets/javascripts/vue_shared/components/tabs/tab.vue deleted file mode 100644 index d24c27cfcc3..00000000000 --- a/app/assets/javascripts/vue_shared/components/tabs/tab.vue +++ /dev/null @@ -1,47 +0,0 @@ -<script> -export default { - props: { - title: { - type: String, - required: false, - default: '', - }, - active: { - type: Boolean, - required: false, - default: false, - }, - }, - data() { - return { - // props can't be updated, so we map it to data where we can - localActive: this.active, - }; - }, - watch: { - active() { - this.localActive = this.active; - }, - }, - created() { - this.isTab = true; - }, - updated() { - if (this.$parent) { - this.$parent.$forceUpdate(); - } - }, -}; -</script> - -<template> - <div - :class="{ - active: localActive, - }" - class="tab-pane" - role="tabpanel" - > - <slot></slot> - </div> -</template> diff --git a/app/assets/javascripts/vue_shared/components/tabs/tabs.js b/app/assets/javascripts/vue_shared/components/tabs/tabs.js deleted file mode 100644 index 233df96a520..00000000000 --- a/app/assets/javascripts/vue_shared/components/tabs/tabs.js +++ /dev/null @@ -1,76 +0,0 @@ -export default { - props: { - stopPropagation: { - type: Boolean, - required: false, - default: false, - }, - }, - data() { - return { - currentIndex: 0, - tabs: [], - }; - }, - mounted() { - this.updateTabs(); - }, - methods: { - updateTabs() { - this.tabs = this.$children.filter((child) => child.isTab); - this.currentIndex = this.tabs.findIndex((tab) => tab.localActive); - }, - setTab(e, index) { - if (this.stopPropagation) { - e.stopPropagation(); - e.preventDefault(); - } - - this.tabs[this.currentIndex].localActive = false; - this.tabs[index].localActive = true; - - this.currentIndex = index; - }, - }, - render(h) { - const navItems = this.tabs.map((tab, i) => - h( - 'li', - { - key: i, - }, - [ - h( - 'a', - { - class: tab.localActive ? 'active' : null, - attrs: { - href: '#', - }, - on: { - click: (e) => this.setTab(e, i), - }, - }, - tab.$slots.title || tab.title, - ), - ], - ), - ); - const nav = h( - 'ul', - { - class: 'nav-links tab-links', - }, - [navItems], - ); - const content = h( - 'div', - { - class: ['tab-content'], - }, - [this.$slots.default], - ); - - return h('div', {}, [[nav], content]); - }, -}; diff --git a/app/assets/javascripts/vue_shared/components/tooltip_on_truncate.vue b/app/assets/javascripts/vue_shared/components/tooltip_on_truncate.vue index 8aa6e29adf1..c5fdb5fc242 100644 --- a/app/assets/javascripts/vue_shared/components/tooltip_on_truncate.vue +++ b/app/assets/javascripts/vue_shared/components/tooltip_on_truncate.vue @@ -1,11 +1,11 @@ <script> +import { GlTooltipDirective as GlTooltip } from '@gitlab/ui'; import { isFunction } from 'lodash'; import { hasHorizontalOverflow } from '~/lib/utils/dom_utils'; -import tooltip from '../directives/tooltip'; export default { directives: { - tooltip, + GlTooltip, }, props: { title: { @@ -59,9 +59,8 @@ export default { <template> <span v-if="showTooltip" - v-tooltip + v-gl-tooltip="{ placement }" :title="title" - :data-placement="placement" class="js-show-tooltip gl-min-w-0" > <slot></slot> diff --git a/app/assets/javascripts/vue_shared/components/upload_dropzone/upload_dropzone.vue b/app/assets/javascripts/vue_shared/components/upload_dropzone/upload_dropzone.vue index 5a08e992084..afb1ea702fa 100644 --- a/app/assets/javascripts/vue_shared/components/upload_dropzone/upload_dropzone.vue +++ b/app/assets/javascripts/vue_shared/components/upload_dropzone/upload_dropzone.vue @@ -36,6 +36,11 @@ export default { required: false, default: () => [VALID_IMAGE_FILE_MIMETYPE.mimetype], }, + singleFileSelection: { + type: Boolean, + required: false, + default: false, + }, }, data() { return { @@ -79,7 +84,7 @@ export default { return; } - this.$emit('change', files); + this.$emit('change', this.singleFileSelection ? files[0] : files); }, ondragenter(e) { this.dragCounter += 1; @@ -92,7 +97,7 @@ export default { this.$refs.fileUpload.click(); }, onFileInputChange(e) { - this.$emit('change', e.target.files); + this.$emit('change', this.singleFileSelection ? e.target.files[0] : e.target.files); }, }, }; @@ -119,9 +124,15 @@ export default { data-testid="dropzone-area" > <gl-icon name="upload" :size="iconStyles.size" :class="iconStyles.class" /> - <p class="gl-mb-0"> + <p class="gl-mb-0" data-testid="upload-text"> <slot name="upload-text" :openFileUpload="openFileUpload"> - <gl-sprintf :message="__('Drop or %{linkStart}upload%{linkEnd} files to attach')"> + <gl-sprintf + :message=" + singleFileSelection + ? __('Drop or %{linkStart}upload%{linkEnd} file to attach') + : __('Drop or %{linkStart}upload%{linkEnd} files to attach') + " + > <template #link="{ content }"> <gl-link @click.stop="openFileUpload"> {{ content }} @@ -139,7 +150,7 @@ export default { name="upload_file" :accept="validFileMimetypes" class="hide" - multiple + :multiple="!singleFileSelection" @change="onFileInputChange" /> </slot> diff --git a/app/assets/javascripts/vue_shared/components/user_access_role_badge.vue b/app/assets/javascripts/vue_shared/components/user_access_role_badge.vue new file mode 100644 index 00000000000..e5558c038b3 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/user_access_role_badge.vue @@ -0,0 +1,22 @@ +<script> +/** + * This component applies particular styling to GlBadge that isn't + * available in the current GlBadge variants. + * Where possible, prefer one of the supported GlBadge variants. + * Discussion issue: https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1247 + */ +import { GlBadge } from '@gitlab/ui'; + +export default { + name: 'UserAccessRoleBadge', + components: { + GlBadge, + }, +}; +</script> + +<template> + <gl-badge class="gl-bg-transparent! gl-inset-border-1-gray-100!"> + <slot></slot> + </gl-badge> +</template> 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 37bde089de8..dbd8efec948 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 @@ -12,11 +12,6 @@ import UserAvatarImage from '../user_avatar/user_avatar_image.vue'; const MAX_SKELETON_LINES = 4; -const SECURITY_BOT_USER_DATA = { - username: 'GitLab-Security-Bot', - name: 'GitLab Security Bot', -}; - export default { name: 'UserPopover', maxSkeletonLines: MAX_SKELETON_LINES, @@ -56,15 +51,6 @@ export default { userIsLoading() { return !this.user?.loaded; }, - isSecurityBot() { - const { username, name, websiteUrl = '' } = this.user; - return ( - gon.features?.securityAutoFix && - username === SECURITY_BOT_USER_DATA.username && - name === SECURITY_BOT_USER_DATA.name && - websiteUrl.length - ); - }, availabilityStatus() { return this.user?.status?.availability || ''; }, @@ -114,7 +100,7 @@ export default { <div v-if="statusHtml" class="js-user-status gl-mt-3"> <span v-html="statusHtml"></span> </div> - <div v-if="isSecurityBot" class="gl-text-blue-500"> + <div v-if="user.bot" class="gl-text-blue-500"> <gl-icon name="question" /> <gl-link data-testid="user-popover-bot-docs-link" :href="user.websiteUrl"> {{ sprintf(__('Learn more about %{username}'), { username: user.name }) }} |