diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-11-17 18:15:43 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-11-17 18:15:43 +0300 |
commit | 843b1e9386fbda332839d23246d0ee2382fb7f4c (patch) | |
tree | 7663f7e38aa4e018c7210a9abdfddcd83a8bcbce /app/assets/javascripts | |
parent | 2724004cd7b8fa9d179c926c62f2fd7be63c2d81 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts')
8 files changed, 49 insertions, 154 deletions
diff --git a/app/assets/javascripts/header.js b/app/assets/javascripts/header.js index 095a2dc1324..7a729cc58c3 100644 --- a/app/assets/javascripts/header.js +++ b/app/assets/javascripts/header.js @@ -2,11 +2,9 @@ // See https://gitlab.com/groups/gitlab-org/-/epics/11875. import Vue from 'vue'; -import NewNavToggle from '~/nav/components/new_nav_toggle.vue'; import { highCountTrim } from '~/lib/utils/text_utility'; import Tracking from '~/tracking'; import Translate from '~/vue_shared/translate'; -import { parseBoolean } from '~/lib/utils/common_utils'; /** * Updates todo counter when todos are toggled. @@ -121,25 +119,7 @@ export function initNavUserDropdownTracking() { } } -function initNewNavToggle() { - const el = document.querySelector('.js-new-nav-toggle'); - if (!el) return false; - - return new Vue({ - el, - render(h) { - return h(NewNavToggle, { - props: { - enabled: parseBoolean(el.dataset.enabled), - endpoint: el.dataset.endpoint, - }, - }); - }, - }); -} - if (!gon?.use_new_navigation) { requestIdleCallback(initStatusTriggers); } requestIdleCallback(initNavUserDropdownTracking); -requestIdleCallback(initNewNavToggle); diff --git a/app/assets/javascripts/nav/components/new_nav_toggle.vue b/app/assets/javascripts/nav/components/new_nav_toggle.vue deleted file mode 100644 index 4e5d6b0ce6c..00000000000 --- a/app/assets/javascripts/nav/components/new_nav_toggle.vue +++ /dev/null @@ -1,105 +0,0 @@ -<script> -import { GlToggle, GlDisclosureDropdownItem } from '@gitlab/ui'; -import axios from '~/lib/utils/axios_utils'; -import { createAlert } from '~/alert'; -import { s__ } from '~/locale'; -import Tracking from '~/tracking'; - -export default { - i18n: { - sectionTitle: s__('NorthstarNavigation|Navigation redesign'), - toggleMenuItemLabel: s__('NorthstarNavigation|New navigation'), - toggleLabel: s__('NorthstarNavigation|Toggle new navigation'), - updateError: s__( - 'NorthstarNavigation|Could not update the new navigation preference. Please try again later.', - ), - }, - components: { - GlToggle, - GlDisclosureDropdownItem, - }, - props: { - enabled: { - type: Boolean, - required: true, - }, - endpoint: { - type: String, - required: true, - }, - newNavigation: { - type: Boolean, - required: false, - default: false, - }, - }, - data() { - return { - isEnabled: this.enabled, - }; - }, - methods: { - toggleNav() { - this.isEnabled = !this.isEnabled; - this.updateAndReload(); - }, - async updateAndReload() { - try { - await axios.put(this.endpoint, { user: { use_new_navigation: this.isEnabled } }); - - Tracking.event(undefined, 'click_toggle', { - label: this.enabled ? 'disable_new_nav_beta' : 'enable_new_nav_beta', - property: this.enabled ? 'nav_user_menu' : 'navigation_top', - }); - - window.location.reload(); - } catch (error) { - createAlert({ - message: this.$options.i18n.updateError, - error, - }); - } - }, - }, -}; -</script> - -<template> - <gl-disclosure-dropdown-item v-if="newNavigation" @action="toggleNav"> - <div class="gl-new-dropdown-item-content"> - <div - class="gl-new-dropdown-item-text-wrapper gl-display-flex! gl-justify-content-space-between gl-align-items-center gl-py-2! gl-gap-3" - > - {{ $options.i18n.toggleMenuItemLabel }} - <gl-toggle - class="gl-flex-grow-0!" - :value="isEnabled" - :label="$options.i18n.toggleLabel" - label-position="hidden" - /> - </div> - </div> - </gl-disclosure-dropdown-item> - - <li v-else> - <div - class="gl-px-4 gl-py-2 gl-display-flex gl-justify-content-space-between gl-align-items-center" - > - <b>{{ $options.i18n.sectionTitle }}</b> - </div> - - <div - class="menu-item gl-cursor-pointer gl-display-flex! gl-justify-content-space-between gl-align-items-center gl-gap-3" - @click.prevent.stop="toggleNav" - > - {{ $options.i18n.toggleMenuItemLabel }} - <gl-toggle - class="gl-flex-grow-0!" - :value="isEnabled" - :label="$options.i18n.toggleLabel" - label-position="hidden" - data-testid="new_navigation_toggle" - /> - </div> - </li> -</template> diff --git a/app/assets/javascripts/profile/edit/components/user_avatar.vue b/app/assets/javascripts/profile/edit/components/user_avatar.vue index f0ff972336b..d69db9f3d6c 100644 --- a/app/assets/javascripts/profile/edit/components/user_avatar.vue +++ b/app/assets/javascripts/profile/edit/components/user_avatar.vue @@ -50,7 +50,7 @@ export default { modalCrop: '.modal-profile-crop', pickImageEl: '.js-choose-user-avatar-button', uploadImageBtn: '.js-upload-user-avatar', - modalCropImg: '.modal-profile-crop-image', + modalCropImg: document.querySelector('.modal-profile-crop-image'), onBlobChange: this.onBlobChange, }; // This has to be used with jQuery, considering migrate that from jQuery to Vue in the future. diff --git a/app/assets/javascripts/profile/gl_crop.js b/app/assets/javascripts/profile/gl_crop.js index ea1a5199ece..0c57dc3cbbe 100644 --- a/app/assets/javascripts/profile/gl_crop.js +++ b/app/assets/javascripts/profile/gl_crop.js @@ -1,7 +1,7 @@ -/* eslint-disable no-useless-escape, no-underscore-dangle, func-names, no-return-assign, consistent-return, class-methods-use-this */ +/* eslint-disable no-underscore-dangle, func-names */ import $ from 'jquery'; -import 'cropper'; +import Cropper from 'cropperjs'; import { isString } from 'lodash'; import { s__ } from '~/locale'; import { createAlert } from '~/alert'; @@ -9,7 +9,7 @@ import { loadCSSFile } from '../lib/utils/css_utils'; (() => { // Matches everything but the file name - const FILENAMEREGEX = /^.*[\\\/]/; + const FILENAMEREGEX = /^.*[\\/]/; class GitLabCrop { constructor( @@ -33,7 +33,6 @@ import { loadCSSFile } from '../lib/utils/css_utils'; this.onModalShow = this.onModalShow.bind(this); this.onPickImageClick = this.onPickImageClick.bind(this); this.fileInput = $(input); - this.modalCropImg = isString(this.modalCropImg) ? $(this.modalCropImg) : this.modalCropImg; this.fileInput .attr('name', `${this.fileInput.attr('name')}-trigger`) .attr('id', `${this.fileInput.attr('id')}-trigger`); @@ -53,9 +52,9 @@ import { loadCSSFile } from '../lib/utils/css_utils'; this.pickImageEl = this.getElement(pickImageEl); this.modalCrop = isString(modalCrop) ? $(modalCrop) : modalCrop; this.uploadImageBtn = isString(uploadImageBtn) ? $(uploadImageBtn) : uploadImageBtn; - this.modalCropImg = isString(modalCropImg) ? $(modalCropImg) : modalCropImg; this.cropActionsBtn = this.modalCrop.find('[data-method]'); this.onBlobChange = onBlobChange; + this.cropperInstance = null; this.bindEvents(); } @@ -78,7 +77,8 @@ import { loadCSSFile } from '../lib/utils/css_utils'; return _this.onActionBtnClick(btn); }); this.onBlobChange(null); - return (this.croppedImageBlob = null); + this.croppedImageBlob = null; + return null; } onPickImageClick() { @@ -87,7 +87,7 @@ import { loadCSSFile } from '../lib/utils/css_utils'; onModalShow() { const _this = this; - return this.modalCropImg.cropper({ + this.cropperInstance = new Cropper(this.modalCropImg, { viewMode: 1, center: false, aspectRatio: 1, @@ -104,11 +104,10 @@ import { loadCSSFile } from '../lib/utils/css_utils'; cropBoxResizable: false, toggleDragModeOnDblclick: false, built() { - const $image = $(this); - const container = $image.cropper('getContainerData'); + const container = this.cropperInstance.getContainerData(); const { cropBoxWidth, cropBoxHeight } = _this; - return $image.cropper('setCropBoxData', { + return this.cropperInstance.setCropBoxData({ width: cropBoxWidth, height: cropBoxHeight, left: (container.width - cropBoxWidth) / 2, @@ -119,7 +118,7 @@ import { loadCSSFile } from '../lib/utils/css_utils'; } onModalHide() { - this.modalCropImg.attr('src', '').cropper('destroy'); + this.cropperInstance.destroy(); const modalElement = document.querySelector('.modal-profile-crop'); if (modalElement) modalElement.remove(); } @@ -134,9 +133,10 @@ import { loadCSSFile } from '../lib/utils/css_utils'; onActionBtnClick(btn) { const data = $(btn).data(); - if (this.modalCropImg.data('cropper') && data.method) { - return this.modalCropImg.cropper(data.method, data.option); + if (data.method) { + return this.cropperInstance[data.method](data.option); } + return null; } onFileInputChange(e, input) { @@ -146,7 +146,7 @@ import { loadCSSFile } from '../lib/utils/css_utils'; readFile(input) { const reader = new FileReader(); reader.onload = () => { - this.modalCropImg.attr('src', reader.result); + this.modalCropImg.setAttribute('src', reader.result); import(/* webpackChunkName: 'bootstrapModal' */ 'bootstrap/js/dist/modal') .then(() => { this.modalCrop.modal('show'); @@ -162,7 +162,7 @@ import { loadCSSFile } from '../lib/utils/css_utils'; return reader.readAsDataURL(input.files[0]); } - dataURLtoBlob(dataURL) { + static dataURLtoBlob(dataURL) { let i = 0; let len = 0; const binary = atob(dataURL.split(',')[1]); @@ -184,14 +184,14 @@ import { loadCSSFile } from '../lib/utils/css_utils'; } setBlob() { - this.dataURL = this.modalCropImg - .cropper('getCroppedCanvas', { + this.dataURL = this.cropperInstance + .getCroppedCanvas({ width: 200, height: 200, }) .toDataURL('image/png'); - this.croppedImageBlob = this.dataURLtoBlob(this.dataURL); + this.croppedImageBlob = GitLabCrop.dataURLtoBlob(this.dataURL); this.onBlobChange(this.croppedImageBlob); return this.croppedImageBlob; } diff --git a/app/assets/javascripts/profile/profile.js b/app/assets/javascripts/profile/profile.js index 2ccb360c7c1..4d3824f910c 100644 --- a/app/assets/javascripts/profile/profile.js +++ b/app/assets/javascripts/profile/profile.js @@ -23,7 +23,7 @@ export default class Profile { modalCrop: '.modal-profile-crop', pickImageEl: '.js-choose-user-avatar-button', uploadImageBtn: '.js-upload-user-avatar', - modalCropImg: '.modal-profile-crop-image', + modalCropImg: document.querySelector('.modal-profile-crop-image'), }; this.avatarGlCrop = $('.js-user-avatar-input').glCrop(cropOpts).data('glcrop'); } diff --git a/app/assets/javascripts/snippets/components/snippet_title.vue b/app/assets/javascripts/snippets/components/snippet_title.vue index 0e4dbf55963..f345fcf291f 100644 --- a/app/assets/javascripts/snippets/components/snippet_title.vue +++ b/app/assets/javascripts/snippets/components/snippet_title.vue @@ -1,15 +1,24 @@ <script> -import { GlSprintf } from '@gitlab/ui'; - +import { GlIcon, GlTooltipDirective, GlSprintf } from '@gitlab/ui'; +import { __, s__ } from '~/locale'; import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; import SnippetDescription from './snippet_description_view.vue'; export default { + name: 'SnippetTitle', + i18n: { + hiddenTooltip: s__('Snippets|This snippet is hidden because its author has been banned'), + hiddenAriaLabel: __('Hidden'), + }, components: { + GlIcon, TimeAgoTooltip, GlSprintf, SnippetDescription, }, + directives: { + GlTooltip: GlTooltipDirective, + }, props: { snippet: { type: Object, @@ -20,9 +29,23 @@ export default { </script> <template> <div class="snippet-header limited-header-width"> - <h2 class="snippet-title gl-mt-0 mb-3" data-testid="snippet-title-content"> - {{ snippet.title }} - </h2> + <div class="gl-display-flex"> + <span + v-if="snippet.hidden" + class="gl-bg-orange-50 gl-text-orange-600 gl-h-6 gl-w-6 border-radius-default gl-line-height-24 gl-text-center gl-mr-3 gl-mt-2" + > + <gl-icon + v-gl-tooltip.bottom + name="spam" + :title="$options.i18n.hiddenTooltip" + :aria-label="$options.i18n.hiddenAriaLabel" + /> + </span> + + <h2 class="snippet-title gl-mt-0 mb-3" data-testid="snippet-title-content"> + {{ snippet.title }} + </h2> + </div> <snippet-description v-if="snippet.description" :description="snippet.descriptionHtml" /> diff --git a/app/assets/javascripts/super_sidebar/components/user_menu.vue b/app/assets/javascripts/super_sidebar/components/user_menu.vue index 5712b716f48..ef4ba8d9056 100644 --- a/app/assets/javascripts/super_sidebar/components/user_menu.vue +++ b/app/assets/javascripts/super_sidebar/components/user_menu.vue @@ -19,9 +19,6 @@ const DROPDOWN_X_OFFSET_IMPERSONATING = DROPDOWN_X_OFFSET_BASE + IMPERSONATING_O export default { i18n: { - newNavigation: { - sectionTitle: s__('NorthstarNavigation|Navigation redesign'), - }, setStatus: s__('SetStatusModal|Set status'), editStatus: s__('SetStatusModal|Edit status'), editProfile: s__('CurrentUser|Edit profile'), diff --git a/app/assets/javascripts/vue_merge_request_widget/components/widget/widget.vue b/app/assets/javascripts/vue_merge_request_widget/components/widget/widget.vue index 0eb50b9ff4f..3be09eef5ad 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/widget/widget.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/widget/widget.vue @@ -19,7 +19,7 @@ import ActionButtons from './action_buttons.vue'; const WIDGET_PREFIX = 'Widget'; const MISSING_RESPONSE_HEADERS = - 'MR Widget: raesponse object should contain status and headers object. Make sure to include that in your `fetchCollapsedData` and `fetchExpandedData` functions.'; + 'MR Widget: response object should contain status and headers object. Make sure to include that in your `fetchCollapsedData` and `fetchExpandedData` functions.'; const LOADING_STATE_COLLAPSED = 'collapsed'; const LOADING_STATE_EXPANDED = 'expanded'; |