From 0a319374e7784aa5c2d1c30dd832d2a0509edbab Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Wed, 8 Jul 2020 06:09:13 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .gitlab/ci/rails.gitlab-ci.yml | 4 +- .gitlab/ci/rules.gitlab-ci.yml | 5 +- app/assets/javascripts/awards_handler.js | 3 +- app/assets/javascripts/behaviors/gl_emoji.js | 88 +++++++---- app/assets/javascripts/emoji/index.js | 88 +++++++---- .../filtered_search/visual_token_value.js | 20 +-- app/assets/javascripts/gfm_auto_complete.js | 13 +- .../ide/components/ide_status_list.vue | 17 +- .../issuables_list/components/issuable.vue | 16 +- .../javascripts/pages/profiles/show/index.js | 5 +- .../components/test_reports/test_reports.vue | 17 +- .../test_reports/test_summary_table.vue | 6 +- .../pipelines/stores/test_reports/actions.js | 6 +- .../pipelines/stores/test_reports/getters.js | 12 +- .../stores/test_reports/mutation_types.js | 2 +- .../stores/test_reports/mutations.js | 4 +- .../pipelines/stores/test_reports/state.js | 2 +- .../repository/components/tree_content.vue | 6 - app/assets/javascripts/repository/index.js | 1 - .../repository/queries/files.query.graphql | 3 +- .../vue_file_list_lfs_badge.query.graphql | 3 - .../set_status_modal_wrapper.vue | 5 +- app/assets/stylesheets/page_bundles/ide.scss | 4 - app/controllers/projects/refs_controller.rb | 4 - app/controllers/projects/tree_controller.rb | 4 - app/helpers/search_helper.rb | 2 +- app/models/concerns/has_repository.rb | 2 +- app/presenters/clusterable_presenter.rb | 2 +- app/services/users/block_service.rb | 2 +- .../shared/_issuable_meta_data.html.haml | 4 +- ...thumbs-down-with-gitlab-svg-thumbs-ico.yml | 5 + ...-to-file-view-to-bottom-bar-in-web-ide.yml | 5 + config/application.rb | 1 + config/environments/development.rb | 2 - config/environments/production.rb | 2 - config/environments/test.rb | 4 + config/gitlab.yml.example | 5 - config/initializers/1_settings.rb | 6 - config/initializers/action_cable.rb | 8 +- doc/api/epic_issues.md | 8 +- doc/api/epic_links.md | 3 +- doc/api/issues.md | 10 +- lib/gitlab/action_cable/config.rb | 17 ++ lib/gitlab/ci/config.rb | 2 +- lib/gitlab/file_finder.rb | 2 +- lib/gitlab/runtime.rb | 26 ++-- locale/gitlab.pot | 6 + spec/features/admin/admin_users_spec.rb | 2 +- .../discussion_comments/commit_spec.rb | 2 +- spec/features/issuables/issuable_list_spec.rb | 4 +- .../issues/filtered_search/search_bar_spec.rb | 2 +- spec/features/issues/issue_detail_spec.rb | 2 +- spec/features/issues/issue_sidebar_spec.rb | 2 +- ...r_creates_branch_and_merge_request_spec.rb | 4 +- .../issues/user_interacts_with_awards_spec.rb | 4 +- spec/features/labels_hierarchy_spec.rb | 2 +- .../user_creates_image_diff_notes_spec.rb | 2 +- .../user_posts_diff_notes_spec.rb | 4 +- .../merge_request/user_sees_diff_spec.rb | 2 +- .../user_suggests_changes_on_diff_spec.rb | 3 +- ...er_visits_profile_preferences_page_spec.rb | 2 +- .../members/member_leaves_project_spec.rb | 2 +- spec/features/users/signup_spec.rb | 2 +- .../document-register-element/index.js | 1 + spec/frontend/awards_handler_spec.js | 11 ++ spec/frontend/behaviors/gl_emoji_spec.js | 110 +++++++++++++ spec/frontend/{ => emoji}/emoji_spec.js | 147 +++--------------- .../support}/unicode_support_map_spec.js | 0 spec/frontend/fixtures/emojis.rb | 17 ++ .../ide/components/ide_status_list_spec.js | 8 +- .../components/dashboard_panel_spec.js | 2 +- .../test_reports/stores/actions_spec.js | 22 +-- .../test_reports/stores/getters_spec.js | 15 +- .../test_reports/stores/mutations_spec.js | 12 +- .../test_reports/test_reports_spec.js | 2 + .../test_reports/test_suite_table_spec.js | 5 +- .../__snapshots__/awards_list_spec.js.snap | 63 +------- .../migrate_build_stage_spec.rb | 2 +- .../lib/gitlab/lograge/custom_options_spec.rb | 4 +- spec/lib/gitlab/runtime_spec.rb | 42 +++-- spec/models/concerns/reactive_caching_spec.rb | 2 +- spec/models/personal_access_token_spec.rb | 2 +- .../quick_actions/interpret_service_spec.rb | 2 +- .../discussion_comments_shared_example.rb | 2 +- 84 files changed, 527 insertions(+), 447 deletions(-) delete mode 100644 app/assets/javascripts/repository/queries/vue_file_list_lfs_badge.query.graphql create mode 100644 changelogs/unreleased/222534-replace-fa-thumbs-up-and-fa-thumbs-down-with-gitlab-svg-thumbs-ico.yml create mode 100644 changelogs/unreleased/225640-move-link-to-file-view-to-bottom-bar-in-web-ide.yml create mode 100644 lib/gitlab/action_cable/config.rb create mode 100644 spec/frontend/__mocks__/document-register-element/index.js create mode 100644 spec/frontend/behaviors/gl_emoji_spec.js rename spec/frontend/{ => emoji}/emoji_spec.js (70%) rename spec/frontend/{behaviors/gl_emoji => emoji/support}/unicode_support_map_spec.js (100%) create mode 100644 spec/frontend/fixtures/emojis.rb diff --git a/.gitlab/ci/rails.gitlab-ci.yml b/.gitlab/ci/rails.gitlab-ci.yml index 084143f1695..e424c4c9f6d 100644 --- a/.gitlab/ci/rails.gitlab-ci.yml +++ b/.gitlab/ci/rails.gitlab-ci.yml @@ -369,10 +369,8 @@ db:rollback geo: # EE: Canonical MR pipelines rspec foss-impact: extends: - - .rspec-base - - .as-if-foss + - .rspec-base-pg11-as-if-foss - .rails:rules:ee-mr-only - - .use-pg11 script: - install_gitlab_gem - run_timed_command "scripts/gitaly-test-build" diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml index 4a65e9950cd..dc38dba8e94 100644 --- a/.gitlab/ci/rules.gitlab-ci.yml +++ b/.gitlab/ci/rules.gitlab-ci.yml @@ -322,11 +322,8 @@ rules: - <<: *if-not-ee when: never - - <<: *if-security-merge-request + - <<: *if-merge-request # Always run for MRs since `compile-test-assets as-if-foss` is either needed by `rspec foss-impact` or the `rspec * as-if-foss` jobs. changes: *code-backstage-qa-patterns - - <<: *if-merge-request-title-as-if-foss - - <<: *if-merge-request - changes: *ci-patterns .frontend:rules:default-frontend-jobs: rules: diff --git a/app/assets/javascripts/awards_handler.js b/app/assets/javascripts/awards_handler.js index 8381b050900..217577de7cb 100644 --- a/app/assets/javascripts/awards_handler.js +++ b/app/assets/javascripts/awards_handler.js @@ -9,6 +9,7 @@ import { updateTooltipTitle } from './lib/utils/common_utils'; import { isInVueNoteablePage } from './lib/utils/dom_utils'; import flash from './flash'; import axios from './lib/utils/axios_utils'; +import * as Emoji from '~/emoji'; const animationEndEventString = 'animationend webkitAnimationEnd MSAnimationEnd oAnimationEnd'; const transitionEndEventString = 'transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd'; @@ -619,7 +620,7 @@ export class AwardsHandler { let awardsHandlerPromise = null; export default function loadAwardsHandler(reload = false) { if (!awardsHandlerPromise || reload) { - awardsHandlerPromise = import(/* webpackChunkName: 'emoji' */ './emoji').then(Emoji => { + awardsHandlerPromise = Emoji.initEmojiMap().then(() => { const awardsHandler = new AwardsHandler(Emoji); awardsHandler.bindEvents(); return awardsHandler; diff --git a/app/assets/javascripts/behaviors/gl_emoji.js b/app/assets/javascripts/behaviors/gl_emoji.js index d1d75658181..bcf732e9522 100644 --- a/app/assets/javascripts/behaviors/gl_emoji.js +++ b/app/assets/javascripts/behaviors/gl_emoji.js @@ -1,47 +1,69 @@ import 'document-register-element'; import isEmojiUnicodeSupported from '../emoji/support'; +import { initEmojiMap, getEmojiInfo, emojiFallbackImageSrc, emojiImageTag } from '../emoji'; class GlEmoji extends HTMLElement { constructor() { super(); - const emojiUnicode = this.textContent.trim(); - const { name, unicodeVersion, fallbackSrc, fallbackSpriteClass } = this.dataset; + this.initialize(); + } + initialize() { + let emojiUnicode = this.textContent.trim(); + const { fallbackSpriteClass, fallbackSrc } = this.dataset; + let { name, unicodeVersion } = this.dataset; - const isEmojiUnicode = - this.childNodes && - Array.prototype.every.call(this.childNodes, childNode => childNode.nodeType === 3); - const hasImageFallback = fallbackSrc && fallbackSrc.length > 0; - const hasCssSpriteFalback = fallbackSpriteClass && fallbackSpriteClass.length > 0; + return initEmojiMap().then(() => { + if (!unicodeVersion) { + const emojiInfo = getEmojiInfo(name); - if (emojiUnicode && isEmojiUnicode && !isEmojiUnicodeSupported(emojiUnicode, unicodeVersion)) { - // CSS sprite fallback takes precedence over image fallback - if (hasCssSpriteFalback) { - if (!gon.emoji_sprites_css_added && gon.emoji_sprites_css_path) { - const emojiSpriteLinkTag = document.createElement('link'); - emojiSpriteLinkTag.setAttribute('rel', 'stylesheet'); - emojiSpriteLinkTag.setAttribute('href', gon.emoji_sprites_css_path); - document.head.appendChild(emojiSpriteLinkTag); - gon.emoji_sprites_css_added = true; + if (emojiInfo) { + if (name !== emojiInfo.name) { + ({ name } = emojiInfo); + this.dataset.name = emojiInfo.name; + } + unicodeVersion = emojiInfo.u; + this.dataset.unicodeVersion = unicodeVersion; + + emojiUnicode = emojiInfo.e; + this.innerHTML = emojiInfo.e; + + this.title = emojiInfo.d; } - // IE 11 doesn't like adding multiple at once :( - this.classList.add('emoji-icon'); - this.classList.add(fallbackSpriteClass); - } else { - import(/* webpackChunkName: 'emoji' */ '../emoji') - .then(({ emojiImageTag, emojiFallbackImageSrc }) => { - if (hasImageFallback) { - this.innerHTML = emojiImageTag(name, fallbackSrc); - } else { - const src = emojiFallbackImageSrc(name); - this.innerHTML = emojiImageTag(name, src); - } - }) - .catch(() => { - // do nothing - }); } - } + + const isEmojiUnicode = + this.childNodes && + Array.prototype.every.call(this.childNodes, childNode => childNode.nodeType === 3); + + if ( + emojiUnicode && + isEmojiUnicode && + !isEmojiUnicodeSupported(emojiUnicode, unicodeVersion) + ) { + const hasImageFallback = fallbackSrc && fallbackSrc.length > 0; + const hasCssSpriteFallback = fallbackSpriteClass && fallbackSpriteClass.length > 0; + + // CSS sprite fallback takes precedence over image fallback + if (hasCssSpriteFallback) { + if (!gon.emoji_sprites_css_added && gon.emoji_sprites_css_path) { + const emojiSpriteLinkTag = document.createElement('link'); + emojiSpriteLinkTag.setAttribute('rel', 'stylesheet'); + emojiSpriteLinkTag.setAttribute('href', gon.emoji_sprites_css_path); + document.head.appendChild(emojiSpriteLinkTag); + gon.emoji_sprites_css_added = true; + } + // IE 11 doesn't like adding multiple at once :( + this.classList.add('emoji-icon'); + this.classList.add(fallbackSpriteClass); + } else if (hasImageFallback) { + this.innerHTML = emojiImageTag(name, fallbackSrc); + } else { + const src = emojiFallbackImageSrc(name); + this.innerHTML = emojiImageTag(name, src); + } + } + }); } } diff --git a/app/assets/javascripts/emoji/index.js b/app/assets/javascripts/emoji/index.js index 27dff8cf9aa..4567c807c40 100644 --- a/app/assets/javascripts/emoji/index.js +++ b/app/assets/javascripts/emoji/index.js @@ -1,13 +1,63 @@ import { uniq } from 'lodash'; -import emojiMap from 'emojis/digests.json'; import emojiAliases from 'emojis/aliases.json'; +import axios from '../lib/utils/axios_utils'; -export const validEmojiNames = [...Object.keys(emojiMap), ...Object.keys(emojiAliases)]; +import AccessorUtilities from '../lib/utils/accessor'; + +let emojiMap = null; +let emojiPromise = null; +let validEmojiNames = null; + +export const EMOJI_VERSION = '1'; + +const isLocalStorageAvailable = AccessorUtilities.isLocalStorageAccessSafe(); + +export function initEmojiMap() { + emojiPromise = + emojiPromise || + new Promise((resolve, reject) => { + if (emojiMap) { + resolve(emojiMap); + } else if ( + isLocalStorageAvailable && + window.localStorage.getItem('gl-emoji-map-version') === EMOJI_VERSION && + window.localStorage.getItem('gl-emoji-map') + ) { + emojiMap = JSON.parse(window.localStorage.getItem('gl-emoji-map')); + validEmojiNames = [...Object.keys(emojiMap), ...Object.keys(emojiAliases)]; + resolve(emojiMap); + } else { + // We load the JSON file direct from the server + // because it can't be loaded from a CDN due to + // cross domain problems with JSON + axios + .get(`${gon.relative_url_root || ''}/-/emojis/${EMOJI_VERSION}/emojis.json`) + .then(({ data }) => { + emojiMap = data; + validEmojiNames = [...Object.keys(emojiMap), ...Object.keys(emojiAliases)]; + resolve(emojiMap); + if (isLocalStorageAvailable) { + window.localStorage.setItem('gl-emoji-map-version', EMOJI_VERSION); + window.localStorage.setItem('gl-emoji-map', JSON.stringify(emojiMap)); + } + }) + .catch(err => { + reject(err); + }); + } + }); + + return emojiPromise; +} export function normalizeEmojiName(name) { return Object.prototype.hasOwnProperty.call(emojiAliases, name) ? emojiAliases[name] : name; } +export function getValidEmojiNames() { + return validEmojiNames; +} + export function isEmojiNameValid(name) { return validEmojiNames.indexOf(name) >= 0; } @@ -36,8 +86,8 @@ export function getEmojiCategoryMap() { }; Object.keys(emojiMap).forEach(name => { const emoji = emojiMap[name]; - if (emojiCategoryMap[emoji.category]) { - emojiCategoryMap[emoji.category].push(name); + if (emojiCategoryMap[emoji.c]) { + emojiCategoryMap[emoji.c].push(name); } }); } @@ -58,8 +108,9 @@ export function getEmojiInfo(query) { } export function emojiFallbackImageSrc(inputName) { - const { name, digest } = getEmojiInfo(inputName); - return `${gon.asset_host || ''}${gon.relative_url_root || ''}/assets/emoji/${name}-${digest}.png`; + const { name } = getEmojiInfo(inputName); + return `${gon.asset_host || ''}${gon.relative_url_root || + ''}/-/emojis/${EMOJI_VERSION}/${name}.png`; } export function emojiImageTag(name, src) { @@ -67,36 +118,17 @@ export function emojiImageTag(name, src) { } export function glEmojiTag(inputName, options) { - const opts = { sprite: false, forceFallback: false, ...options }; - const { name, ...emojiInfo } = getEmojiInfo(inputName); - - const fallbackImageSrc = emojiFallbackImageSrc(name); + const opts = { sprite: false, ...options }; + const name = normalizeEmojiName(inputName); const fallbackSpriteClass = `emoji-${name}`; - const classList = []; - if (opts.forceFallback && opts.sprite) { - classList.push('emoji-icon'); - classList.push(fallbackSpriteClass); - } - const classAttribute = classList.length > 0 ? `class="${classList.join(' ')}"` : ''; const fallbackSpriteAttribute = opts.sprite ? `data-fallback-sprite-class="${fallbackSpriteClass}"` : ''; - let contents = emojiInfo.moji; - if (opts.forceFallback && !opts.sprite) { - contents = emojiImageTag(name, fallbackImageSrc); - } return ` - ${contents} - + data-name="${name}"> `; } diff --git a/app/assets/javascripts/filtered_search/visual_token_value.js b/app/assets/javascripts/filtered_search/visual_token_value.js index 02caf0851af..b1e6c4142e9 100644 --- a/app/assets/javascripts/filtered_search/visual_token_value.js +++ b/app/assets/javascripts/filtered_search/visual_token_value.js @@ -7,6 +7,7 @@ import DropdownUtils from '~/filtered_search/dropdown_utils'; import Flash from '~/flash'; import UsersCache from '~/lib/utils/users_cache'; import { __ } from '~/locale'; +import * as Emoji from '~/emoji'; export default class VisualTokenValue { constructor(tokenValue, tokenType, tokenOperator) { @@ -137,18 +138,13 @@ export default class VisualTokenValue { const element = tokenValueElement; const value = this.tokenValue; - return ( - import(/* webpackChunkName: 'emoji' */ '../emoji') - .then(Emoji => { - if (!Emoji.isEmojiNameValid(value)) { - return; - } + return Emoji.initEmojiMap().then(() => { + if (!Emoji.isEmojiNameValid(value)) { + return; + } - container.dataset.originalValue = value; - element.innerHTML = Emoji.glEmojiTag(value); - }) - // ignore error and leave emoji name in the search bar - .catch(() => {}) - ); + container.dataset.originalValue = value; + element.innerHTML = Emoji.glEmojiTag(value); + }); } } diff --git a/app/assets/javascripts/gfm_auto_complete.js b/app/assets/javascripts/gfm_auto_complete.js index fcd535cad73..0121fcf2859 100644 --- a/app/assets/javascripts/gfm_auto_complete.js +++ b/app/assets/javascripts/gfm_auto_complete.js @@ -5,6 +5,7 @@ import SidebarMediator from '~/sidebar/sidebar_mediator'; import glRegexp from './lib/utils/regexp'; import AjaxCache from './lib/utils/ajax_cache'; import { spriteIcon } from './lib/utils/common_utils'; +import * as Emoji from '~/emoji'; function sanitize(str) { return str.replace(/<(?:.|\n)*?>/gm, ''); @@ -586,14 +587,12 @@ class GfmAutoComplete { if (this.cachedData[at]) { this.loadData($input, at, this.cachedData[at]); } else if (GfmAutoComplete.atTypeMap[at] === 'emojis') { - import(/* webpackChunkName: 'emoji' */ './emoji') - .then(({ validEmojiNames, glEmojiTag }) => { - this.loadData($input, at, validEmojiNames); - GfmAutoComplete.glEmojiTag = glEmojiTag; + Emoji.initEmojiMap() + .then(() => { + this.loadData($input, at, Emoji.getValidEmojiNames()); + GfmAutoComplete.glEmojiTag = Emoji.glEmojiTag; }) - .catch(() => { - this.isLoadingData[at] = false; - }); + .catch(() => {}); } else if (dataSource) { AjaxCache.retrieve(dataSource, true) .then(data => { diff --git a/app/assets/javascripts/ide/components/ide_status_list.vue b/app/assets/javascripts/ide/components/ide_status_list.vue index 92d25709bd5..1354fdc3d98 100644 --- a/app/assets/javascripts/ide/components/ide_status_list.vue +++ b/app/assets/javascripts/ide/components/ide_status_list.vue @@ -1,12 +1,17 @@