summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-07-08 06:09:13 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-07-08 06:09:13 +0000
commit0a319374e7784aa5c2d1c30dd832d2a0509edbab (patch)
tree123c5bac601b85d60cbaba541b25aed8c981c529
parent5683a027b79d2236bf9b3d1eb5303075584894d7 (diff)
downloadgitlab-ce-0a319374e7784aa5c2d1c30dd832d2a0509edbab.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitlab/ci/rails.gitlab-ci.yml4
-rw-r--r--.gitlab/ci/rules.gitlab-ci.yml5
-rw-r--r--app/assets/javascripts/awards_handler.js3
-rw-r--r--app/assets/javascripts/behaviors/gl_emoji.js92
-rw-r--r--app/assets/javascripts/emoji/index.js88
-rw-r--r--app/assets/javascripts/filtered_search/visual_token_value.js20
-rw-r--r--app/assets/javascripts/gfm_auto_complete.js13
-rw-r--r--app/assets/javascripts/ide/components/ide_status_list.vue17
-rw-r--r--app/assets/javascripts/issuables_list/components/issuable.vue16
-rw-r--r--app/assets/javascripts/pages/profiles/show/index.js5
-rw-r--r--app/assets/javascripts/pipelines/components/test_reports/test_reports.vue17
-rw-r--r--app/assets/javascripts/pipelines/components/test_reports/test_summary_table.vue6
-rw-r--r--app/assets/javascripts/pipelines/stores/test_reports/actions.js6
-rw-r--r--app/assets/javascripts/pipelines/stores/test_reports/getters.js12
-rw-r--r--app/assets/javascripts/pipelines/stores/test_reports/mutation_types.js2
-rw-r--r--app/assets/javascripts/pipelines/stores/test_reports/mutations.js4
-rw-r--r--app/assets/javascripts/pipelines/stores/test_reports/state.js2
-rw-r--r--app/assets/javascripts/repository/components/tree_content.vue6
-rw-r--r--app/assets/javascripts/repository/index.js1
-rw-r--r--app/assets/javascripts/repository/queries/files.query.graphql3
-rw-r--r--app/assets/javascripts/repository/queries/vue_file_list_lfs_badge.query.graphql3
-rw-r--r--app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue5
-rw-r--r--app/assets/stylesheets/page_bundles/ide.scss4
-rw-r--r--app/controllers/projects/refs_controller.rb4
-rw-r--r--app/controllers/projects/tree_controller.rb4
-rw-r--r--app/helpers/search_helper.rb2
-rw-r--r--app/models/concerns/has_repository.rb2
-rw-r--r--app/presenters/clusterable_presenter.rb2
-rw-r--r--app/services/users/block_service.rb2
-rw-r--r--app/views/shared/_issuable_meta_data.html.haml4
-rw-r--r--changelogs/unreleased/222534-replace-fa-thumbs-up-and-fa-thumbs-down-with-gitlab-svg-thumbs-ico.yml5
-rw-r--r--changelogs/unreleased/225640-move-link-to-file-view-to-bottom-bar-in-web-ide.yml5
-rw-r--r--config/application.rb1
-rw-r--r--config/environments/development.rb2
-rw-r--r--config/environments/production.rb2
-rw-r--r--config/environments/test.rb4
-rw-r--r--config/gitlab.yml.example5
-rw-r--r--config/initializers/1_settings.rb6
-rw-r--r--config/initializers/action_cable.rb8
-rw-r--r--doc/api/epic_issues.md8
-rw-r--r--doc/api/epic_links.md3
-rw-r--r--doc/api/issues.md10
-rw-r--r--lib/gitlab/action_cable/config.rb17
-rw-r--r--lib/gitlab/ci/config.rb2
-rw-r--r--lib/gitlab/file_finder.rb2
-rw-r--r--lib/gitlab/runtime.rb26
-rw-r--r--locale/gitlab.pot6
-rw-r--r--spec/features/admin/admin_users_spec.rb2
-rw-r--r--spec/features/discussion_comments/commit_spec.rb2
-rw-r--r--spec/features/issuables/issuable_list_spec.rb4
-rw-r--r--spec/features/issues/filtered_search/search_bar_spec.rb2
-rw-r--r--spec/features/issues/issue_detail_spec.rb2
-rw-r--r--spec/features/issues/issue_sidebar_spec.rb2
-rw-r--r--spec/features/issues/user_creates_branch_and_merge_request_spec.rb4
-rw-r--r--spec/features/issues/user_interacts_with_awards_spec.rb4
-rw-r--r--spec/features/labels_hierarchy_spec.rb2
-rw-r--r--spec/features/merge_request/user_creates_image_diff_notes_spec.rb2
-rw-r--r--spec/features/merge_request/user_posts_diff_notes_spec.rb4
-rw-r--r--spec/features/merge_request/user_sees_diff_spec.rb2
-rw-r--r--spec/features/merge_request/user_suggests_changes_on_diff_spec.rb3
-rw-r--r--spec/features/profiles/user_visits_profile_preferences_page_spec.rb2
-rw-r--r--spec/features/projects/members/member_leaves_project_spec.rb2
-rw-r--r--spec/features/users/signup_spec.rb2
-rw-r--r--spec/frontend/__mocks__/document-register-element/index.js1
-rw-r--r--spec/frontend/awards_handler_spec.js11
-rw-r--r--spec/frontend/behaviors/gl_emoji_spec.js110
-rw-r--r--spec/frontend/emoji/emoji_spec.js (renamed from spec/frontend/emoji_spec.js)145
-rw-r--r--spec/frontend/emoji/support/unicode_support_map_spec.js (renamed from spec/frontend/behaviors/gl_emoji/unicode_support_map_spec.js)0
-rw-r--r--spec/frontend/fixtures/emojis.rb17
-rw-r--r--spec/frontend/ide/components/ide_status_list_spec.js8
-rw-r--r--spec/frontend/monitoring/components/dashboard_panel_spec.js2
-rw-r--r--spec/frontend/pipelines/test_reports/stores/actions_spec.js22
-rw-r--r--spec/frontend/pipelines/test_reports/stores/getters_spec.js15
-rw-r--r--spec/frontend/pipelines/test_reports/stores/mutations_spec.js12
-rw-r--r--spec/frontend/pipelines/test_reports/test_reports_spec.js2
-rw-r--r--spec/frontend/pipelines/test_reports/test_suite_table_spec.js5
-rw-r--r--spec/frontend/vue_shared/components/__snapshots__/awards_list_spec.js.snap63
-rw-r--r--spec/lib/gitlab/background_migration/migrate_build_stage_spec.rb2
-rw-r--r--spec/lib/gitlab/lograge/custom_options_spec.rb4
-rw-r--r--spec/lib/gitlab/runtime_spec.rb42
-rw-r--r--spec/models/concerns/reactive_caching_spec.rb2
-rw-r--r--spec/models/personal_access_token_spec.rb2
-rw-r--r--spec/services/quick_actions/interpret_service_spec.rb2
-rw-r--r--spec/support/shared_examples/features/discussion_comments_shared_example.rb2
84 files changed, 528 insertions, 448 deletions
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;
-
- 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;
-
- 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;
+ this.initialize();
+ }
+ initialize() {
+ let emojiUnicode = this.textContent.trim();
+ const { fallbackSpriteClass, fallbackSrc } = this.dataset;
+ let { name, unicodeVersion } = this.dataset;
+
+ return initEmojiMap().then(() => {
+ if (!unicodeVersion) {
+ const emojiInfo = getEmojiInfo(name);
+
+ 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;
+ }
+ }
+
+ 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);
}
- // 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
- });
}
- }
+ });
}
}
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 `
<gl-emoji
- ${classAttribute}
- data-name="${name}"
- data-fallback-src="${fallbackImageSrc}"
${fallbackSpriteAttribute}
- data-unicode-version="${emojiInfo.unicodeVersion}"
- title="${emojiInfo.description}"
- >
- ${contents}
- </gl-emoji>
+ data-name="${name}"></gl-emoji>
`;
}
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 @@
<script>
import { mapGetters } from 'vuex';
+import { GlLink, GlTooltipDirective } from '@gitlab/ui';
import TerminalSyncStatusSafe from './terminal_sync/terminal_sync_status_safe.vue';
import { getFileEOL } from '../utils';
export default {
components: {
+ GlLink,
TerminalSyncStatusSafe,
},
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
computed: {
...mapGetters(['activeFile']),
activeFileEOL() {
@@ -19,12 +24,14 @@ export default {
<template>
<div class="ide-status-list d-flex">
<template v-if="activeFile">
- <div class="ide-status-file">{{ activeFile.name }}</div>
- <div class="ide-status-file">{{ activeFileEOL }}</div>
- <div v-if="!activeFile.binary" class="ide-status-file">
- {{ activeFile.editorRow }}:{{ activeFile.editorColumn }}
+ <div>
+ <gl-link v-gl-tooltip.hover :href="activeFile.permalink" :title="__('Open in file view')">
+ {{ activeFile.name }}
+ </gl-link>
</div>
- <div class="ide-status-file">{{ activeFile.fileLanguage }}</div>
+ <div>{{ activeFileEOL }}</div>
+ <div v-if="!activeFile.binary">{{ activeFile.editorRow }}:{{ activeFile.editorColumn }}</div>
+ <div>{{ activeFile.fileLanguage }}</div>
</template>
<terminal-sync-status-safe />
</div>
diff --git a/app/assets/javascripts/issuables_list/components/issuable.vue b/app/assets/javascripts/issuables_list/components/issuable.vue
index 2ee735fd123..b36a83c4974 100644
--- a/app/assets/javascripts/issuables_list/components/issuable.vue
+++ b/app/assets/javascripts/issuables_list/components/issuable.vue
@@ -6,7 +6,7 @@
// TODO: need to move this component to graphql - https://gitlab.com/gitlab-org/gitlab/-/issues/221246
import { escape, isNumber } from 'lodash';
-import { GlLink, GlTooltipDirective as GlTooltip, GlSprintf, GlLabel } from '@gitlab/ui';
+import { GlLink, GlTooltipDirective as GlTooltip, GlSprintf, GlLabel, GlIcon } from '@gitlab/ui';
import {
dateInWords,
formatDate,
@@ -18,7 +18,6 @@ import {
import { sprintf, __ } from '~/locale';
import initUserPopovers from '~/user_popovers';
import { mergeUrlParams } from '~/lib/utils/url_utility';
-import Icon from '~/vue_shared/components/icon.vue';
import IssueAssignees from '~/vue_shared/components/issue/issue_assignees.vue';
import { isScopedLabel } from '~/lib/utils/common_utils';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
@@ -28,10 +27,10 @@ export default {
openedAgo: __('opened %{timeAgoString} by %{user}'),
},
components: {
- Icon,
IssueAssignees,
GlLink,
GlLabel,
+ GlIcon,
GlSprintf,
},
directives: {
@@ -153,14 +152,14 @@ export default {
value: this.issuable.upvotes,
title: __('Upvotes'),
class: 'js-upvotes',
- faicon: 'fa-thumbs-up',
+ icon: 'thumb-up',
},
{
key: 'downvotes',
value: this.issuable.downvotes,
title: __('Downvotes'),
class: 'js-downvotes',
- faicon: 'fa-thumbs-down',
+ icon: 'thumb-down',
},
];
},
@@ -294,7 +293,7 @@ export default {
:title="__('Weight')"
class="d-none d-sm-inline-block js-weight"
>
- <icon name="weight" class="align-text-bottom" />
+ <gl-icon name="weight" class="align-text-bottom" />
{{ issuable.weight }}
</span>
</div>
@@ -318,11 +317,10 @@ export default {
v-if="meta.value"
:key="meta.key"
v-gl-tooltip
- :class="['d-none d-sm-inline-block ml-2', meta.class]"
+ :class="['d-none d-sm-inline-block ml-2 vertical-align-middle', meta.class]"
:title="meta.title"
>
- <icon v-if="meta.icon" :name="meta.icon" />
- <i v-else :class="['fa', meta.faicon]"></i>
+ <gl-icon v-if="meta.icon" :name="meta.icon" />
{{ meta.value }}
</span>
</template>
diff --git a/app/assets/javascripts/pages/profiles/show/index.js b/app/assets/javascripts/pages/profiles/show/index.js
index ad003181728..74ab1bc13a9 100644
--- a/app/assets/javascripts/pages/profiles/show/index.js
+++ b/app/assets/javascripts/pages/profiles/show/index.js
@@ -4,6 +4,7 @@ import emojiRegex from 'emoji-regex';
import createFlash from '~/flash';
import EmojiMenu from './emoji_menu';
import { __ } from '~/locale';
+import * as Emoji from '~/emoji';
const defaultStatusEmoji = 'speech_balloon';
@@ -55,8 +56,8 @@ document.addEventListener('DOMContentLoaded', () => {
}
});
- import(/* webpackChunkName: 'emoji' */ '~/emoji')
- .then(Emoji => {
+ Emoji.initEmojiMap()
+ .then(() => {
const emojiMenu = new EmojiMenu(
Emoji,
toggleEmojiMenuButtonSelector,
diff --git a/app/assets/javascripts/pipelines/components/test_reports/test_reports.vue b/app/assets/javascripts/pipelines/components/test_reports/test_reports.vue
index 6f2d3ad42ea..a73b7ccbc12 100644
--- a/app/assets/javascripts/pipelines/components/test_reports/test_reports.vue
+++ b/app/assets/javascripts/pipelines/components/test_reports/test_reports.vue
@@ -1,5 +1,5 @@
<script>
-import { mapActions, mapState } from 'vuex';
+import { mapActions, mapGetters, mapState } from 'vuex';
import { GlLoadingIcon } from '@gitlab/ui';
import TestSuiteTable from './test_suite_table.vue';
import TestSummary from './test_summary.vue';
@@ -14,9 +14,10 @@ export default {
TestSummaryTable,
},
computed: {
- ...mapState(['isLoading', 'selectedSuite', 'testReports']),
+ ...mapState(['isLoading', 'selectedSuiteIndex', 'testReports']),
+ ...mapGetters(['getSelectedSuite']),
showSuite() {
- return this.selectedSuite.total_count > 0;
+ return this.selectedSuiteIndex !== null;
},
showTests() {
const { test_suites: testSuites = [] } = this.testReports;
@@ -27,12 +28,12 @@ export default {
this.fetchSummary();
},
methods: {
- ...mapActions(['fetchSummary', 'setSelectedSuite', 'removeSelectedSuite']),
+ ...mapActions(['fetchSummary', 'setSelectedSuiteIndex', 'removeSelectedSuiteIndex']),
summaryBackClick() {
- this.removeSelectedSuite();
+ this.removeSelectedSuiteIndex();
},
- summaryTableRowClick(suite) {
- this.setSelectedSuite(suite);
+ summaryTableRowClick(index) {
+ this.setSelectedSuiteIndex(index);
},
beforeEnterTransition() {
document.documentElement.style.overflowX = 'hidden';
@@ -60,7 +61,7 @@ export default {
@after-leave="afterLeaveTransition"
>
<div v-if="showSuite" key="detail" class="w-100 position-absolute slide-enter-to-element">
- <test-summary :report="selectedSuite" show-back @on-back-click="summaryBackClick" />
+ <test-summary :report="getSelectedSuite" show-back @on-back-click="summaryBackClick" />
<test-suite-table />
</div>
diff --git a/app/assets/javascripts/pipelines/components/test_reports/test_summary_table.vue b/app/assets/javascripts/pipelines/components/test_reports/test_summary_table.vue
index aa53bbb0e97..e6a5fa4fa3e 100644
--- a/app/assets/javascripts/pipelines/components/test_reports/test_summary_table.vue
+++ b/app/assets/javascripts/pipelines/components/test_reports/test_summary_table.vue
@@ -27,8 +27,8 @@ export default {
},
},
methods: {
- tableRowClick(suite) {
- this.$emit('row-click', suite);
+ tableRowClick(index) {
+ this.$emit('row-click', index);
},
},
maxShownRows: 20,
@@ -82,7 +82,7 @@ export default {
:class="{
'gl-responsive-table-row-clickable cursor-pointer': !testSuite.suite_error,
}"
- @click="tableRowClick(testSuite)"
+ @click="tableRowClick(index)"
>
<div class="table-section section-25">
<div role="rowheader" class="table-mobile-header font-weight-bold">
diff --git a/app/assets/javascripts/pipelines/stores/test_reports/actions.js b/app/assets/javascripts/pipelines/stores/test_reports/actions.js
index e7f7995ef96..f31c315db79 100644
--- a/app/assets/javascripts/pipelines/stores/test_reports/actions.js
+++ b/app/assets/javascripts/pipelines/stores/test_reports/actions.js
@@ -35,8 +35,10 @@ export const fetchFullReport = ({ state, commit, dispatch }) => {
});
};
-export const setSelectedSuite = ({ commit }, data) => commit(types.SET_SELECTED_SUITE, data);
-export const removeSelectedSuite = ({ commit }) => commit(types.SET_SELECTED_SUITE, {});
+export const setSelectedSuiteIndex = ({ commit }, data) =>
+ commit(types.SET_SELECTED_SUITE_INDEX, data);
+export const removeSelectedSuiteIndex = ({ commit }) =>
+ commit(types.SET_SELECTED_SUITE_INDEX, null);
export const toggleLoading = ({ commit }) => commit(types.TOGGLE_LOADING);
// prevent babel-plugin-rewire from generating an invalid default during karma tests
diff --git a/app/assets/javascripts/pipelines/stores/test_reports/getters.js b/app/assets/javascripts/pipelines/stores/test_reports/getters.js
index 788c1d32987..877762b77c9 100644
--- a/app/assets/javascripts/pipelines/stores/test_reports/getters.js
+++ b/app/assets/javascripts/pipelines/stores/test_reports/getters.js
@@ -9,14 +9,12 @@ export const getTestSuites = state => {
}));
};
-export const getSuiteTests = state => {
- const { selectedSuite } = state;
-
- if (selectedSuite.test_cases) {
- return selectedSuite.test_cases.sort(sortTestCases).map(addIconStatus);
- }
+export const getSelectedSuite = state =>
+ state.testReports?.test_suites?.[state.selectedSuiteIndex] || {};
- return [];
+export const getSuiteTests = state => {
+ const { test_cases: testCases = [] } = getSelectedSuite(state);
+ return testCases.sort(sortTestCases).map(addIconStatus);
};
// prevent babel-plugin-rewire from generating an invalid default during karma tests
diff --git a/app/assets/javascripts/pipelines/stores/test_reports/mutation_types.js b/app/assets/javascripts/pipelines/stores/test_reports/mutation_types.js
index b9c23bf6059..76405557b51 100644
--- a/app/assets/javascripts/pipelines/stores/test_reports/mutation_types.js
+++ b/app/assets/javascripts/pipelines/stores/test_reports/mutation_types.js
@@ -1,4 +1,4 @@
export const SET_REPORTS = 'SET_REPORTS';
-export const SET_SELECTED_SUITE = 'SET_SELECTED_SUITE';
+export const SET_SELECTED_SUITE_INDEX = 'SET_SELECTED_SUITE_INDEX';
export const SET_SUMMARY = 'SET_SUMMARY';
export const TOGGLE_LOADING = 'TOGGLE_LOADING';
diff --git a/app/assets/javascripts/pipelines/stores/test_reports/mutations.js b/app/assets/javascripts/pipelines/stores/test_reports/mutations.js
index 62770246c12..9d820e571af 100644
--- a/app/assets/javascripts/pipelines/stores/test_reports/mutations.js
+++ b/app/assets/javascripts/pipelines/stores/test_reports/mutations.js
@@ -5,8 +5,8 @@ export default {
Object.assign(state, { testReports });
},
- [types.SET_SELECTED_SUITE](state, selectedSuite) {
- Object.assign(state, { selectedSuite });
+ [types.SET_SELECTED_SUITE_INDEX](state, selectedSuiteIndex) {
+ Object.assign(state, { selectedSuiteIndex });
},
[types.SET_SUMMARY](state, summary) {
diff --git a/app/assets/javascripts/pipelines/stores/test_reports/state.js b/app/assets/javascripts/pipelines/stores/test_reports/state.js
index 0fc49c63ab1..18aefab04f1 100644
--- a/app/assets/javascripts/pipelines/stores/test_reports/state.js
+++ b/app/assets/javascripts/pipelines/stores/test_reports/state.js
@@ -2,7 +2,7 @@ export default ({ fullReportEndpoint = '', summaryEndpoint = '' }) => ({
summaryEndpoint,
fullReportEndpoint,
testReports: {},
- selectedSuite: {},
+ selectedSuiteIndex: null,
summary: {},
isLoading: false,
});
diff --git a/app/assets/javascripts/repository/components/tree_content.vue b/app/assets/javascripts/repository/components/tree_content.vue
index 858b776ce2f..721cc6787dc 100644
--- a/app/assets/javascripts/repository/components/tree_content.vue
+++ b/app/assets/javascripts/repository/components/tree_content.vue
@@ -5,7 +5,6 @@ import FileTable from './table/index.vue';
import getRefMixin from '../mixins/get_ref';
import filesQuery from '../queries/files.query.graphql';
import projectPathQuery from '../queries/project_path.query.graphql';
-import vueFileListLfsBadgeQuery from '../queries/vue_file_list_lfs_badge.query.graphql';
import FilePreview from './preview/index.vue';
import { readmeFile } from '../utils/readme';
@@ -21,9 +20,6 @@ export default {
projectPath: {
query: projectPathQuery,
},
- vueFileListLfsBadge: {
- query: vueFileListLfsBadgeQuery,
- },
},
props: {
path: {
@@ -47,7 +43,6 @@ export default {
blobs: [],
},
isLoadingFiles: false,
- vueFileListLfsBadge: false,
};
},
computed: {
@@ -82,7 +77,6 @@ export default {
path: this.path || '/',
nextPageCursor: this.nextPageCursor,
pageSize: PAGE_SIZE,
- vueLfsEnabled: this.vueFileListLfsBadge,
},
})
.then(({ data }) => {
diff --git a/app/assets/javascripts/repository/index.js b/app/assets/javascripts/repository/index.js
index 6528e283372..01db4e363ba 100644
--- a/app/assets/javascripts/repository/index.js
+++ b/app/assets/javascripts/repository/index.js
@@ -24,7 +24,6 @@ export default function setupVueRepositoryList() {
projectShortPath,
ref,
escapedRef,
- vueFileListLfsBadge: gon.features?.vueFileListLfsBadge || false,
commits: [],
},
});
diff --git a/app/assets/javascripts/repository/queries/files.query.graphql b/app/assets/javascripts/repository/queries/files.query.graphql
index 2815bce9239..10843b0450f 100644
--- a/app/assets/javascripts/repository/queries/files.query.graphql
+++ b/app/assets/javascripts/repository/queries/files.query.graphql
@@ -14,7 +14,6 @@ query Files(
$ref: String!
$pageSize: Int!
$nextPageCursor: String
- $vueLfsEnabled: Boolean = false
) {
project(fullPath: $projectPath) {
repository {
@@ -47,7 +46,7 @@ query Files(
node {
...TreeEntry
webPath
- lfsOid @include(if: $vueLfsEnabled)
+ lfsOid
}
}
pageInfo {
diff --git a/app/assets/javascripts/repository/queries/vue_file_list_lfs_badge.query.graphql b/app/assets/javascripts/repository/queries/vue_file_list_lfs_badge.query.graphql
deleted file mode 100644
index 603e3d3bd81..00000000000
--- a/app/assets/javascripts/repository/queries/vue_file_list_lfs_badge.query.graphql
+++ /dev/null
@@ -1,3 +0,0 @@
-query VueFileListLfsBadge {
- vueFileListLfsBadge @client
-}
diff --git a/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue b/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue
index fd1f9eae152..d5ae9b04090 100644
--- a/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue
+++ b/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue
@@ -8,6 +8,7 @@ import { __, s__ } from '~/locale';
import Api from '~/api';
import eventHub from './event_hub';
import EmojiMenuInModal from './emoji_menu_in_modal';
+import * as Emoji from '~/emoji';
const emojiMenuClass = 'js-modal-status-emoji-menu';
@@ -64,8 +65,8 @@ export default {
const emojiAutocomplete = new GfmAutoComplete();
emojiAutocomplete.setup($(this.$refs.statusMessageField), { emojis: true });
- import(/* webpackChunkName: 'emoji' */ '~/emoji')
- .then(Emoji => {
+ Emoji.initEmojiMap()
+ .then(() => {
if (this.emoji) {
this.emojiTag = Emoji.glEmojiTag(this.emoji);
}
diff --git a/app/assets/stylesheets/page_bundles/ide.scss b/app/assets/stylesheets/page_bundles/ide.scss
index 9c92f891834..83623cbbc65 100644
--- a/app/assets/stylesheets/page_bundles/ide.scss
+++ b/app/assets/stylesheets/page_bundles/ide.scss
@@ -251,10 +251,6 @@ $ide-commit-header-height: 48px;
padding-left: $gl-padding;
}
}
-
-.ide-status-file {
- text-align: right;
-}
// Not great, but this is to deal with our current output
.multi-file-preview-holder {
height: 100%;
diff --git a/app/controllers/projects/refs_controller.rb b/app/controllers/projects/refs_controller.rb
index 0d1583e05e5..db770d3e438 100644
--- a/app/controllers/projects/refs_controller.rb
+++ b/app/controllers/projects/refs_controller.rb
@@ -11,10 +11,6 @@ class Projects::RefsController < Projects::ApplicationController
before_action :assign_ref_vars
before_action :authorize_download_code!
- before_action only: [:logs_tree] do
- push_frontend_feature_flag(:vue_file_list_lfs_badge, default_enabled: true)
- end
-
def switch
respond_to do |format|
format.html do
diff --git a/app/controllers/projects/tree_controller.rb b/app/controllers/projects/tree_controller.rb
index 18e08db2268..aadc766313d 100644
--- a/app/controllers/projects/tree_controller.rb
+++ b/app/controllers/projects/tree_controller.rb
@@ -15,10 +15,6 @@ class Projects::TreeController < Projects::ApplicationController
before_action :authorize_download_code!
before_action :authorize_edit_tree!, only: [:create_dir]
- before_action only: [:show] do
- push_frontend_feature_flag(:vue_file_list_lfs_badge, default_enabled: true)
- end
-
def show
return render_404 unless @commit
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index 4e3b6aad8cc..58ce063dbd4 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -62,7 +62,7 @@ module SearchHelper
}).html_safe
end
- # Overriden in EE
+ # Overridden in EE
def search_blob_title(project, path)
path
end
diff --git a/app/models/concerns/has_repository.rb b/app/models/concerns/has_repository.rb
index 29d31b8bb4f..f7f8aac861e 100644
--- a/app/models/concerns/has_repository.rb
+++ b/app/models/concerns/has_repository.rb
@@ -5,7 +5,7 @@
# of directly having a repository, like project or snippet.
#
# It also includes `Referable`, therefore the method
-# `to_reference` should be overriden in case the object
+# `to_reference` should be overridden in case the object
# needs any special behavior.
module HasRepository
extend ActiveSupport::Concern
diff --git a/app/presenters/clusterable_presenter.rb b/app/presenters/clusterable_presenter.rb
index 5e669ff2e50..4eb0e244e54 100644
--- a/app/presenters/clusterable_presenter.rb
+++ b/app/presenters/clusterable_presenter.rb
@@ -65,7 +65,7 @@ class ClusterablePresenter < Gitlab::View::Presenter::Delegated
raise NotImplementedError
end
- # Will be overidden in EE
+ # Will be overridden in EE
def environments_cluster_path(cluster)
nil
end
diff --git a/app/services/users/block_service.rb b/app/services/users/block_service.rb
index 9c393832d8f..041db731875 100644
--- a/app/services/users/block_service.rb
+++ b/app/services/users/block_service.rb
@@ -19,7 +19,7 @@ module Users
private
def after_block_hook(user)
- # overriden by EE module
+ # overridden by EE module
end
end
end
diff --git a/app/views/shared/_issuable_meta_data.html.haml b/app/views/shared/_issuable_meta_data.html.haml
index 191e6c132f8..dee6dc1e078 100644
--- a/app/views/shared/_issuable_meta_data.html.haml
+++ b/app/views/shared/_issuable_meta_data.html.haml
@@ -11,12 +11,12 @@
- if upvotes > 0
%li.issuable-upvotes.d-none.d-sm-block.has-tooltip{ title: _('Upvotes') }
- = icon('thumbs-up')
+ = sprite_icon('thumb-up', size: 16, css_class: "vertical-align-middle")
= upvotes
- if downvotes > 0
%li.issuable-downvotes.d-none.d-sm-block.has-tooltip{ title: _('Downvotes') }
- = icon('thumbs-down')
+ = sprite_icon('thumb-down', size: 16, css_class: "vertical-align-middle")
= downvotes
%li.issuable-comments.d-none.d-sm-block
diff --git a/changelogs/unreleased/222534-replace-fa-thumbs-up-and-fa-thumbs-down-with-gitlab-svg-thumbs-ico.yml b/changelogs/unreleased/222534-replace-fa-thumbs-up-and-fa-thumbs-down-with-gitlab-svg-thumbs-ico.yml
new file mode 100644
index 00000000000..c484417b12a
--- /dev/null
+++ b/changelogs/unreleased/222534-replace-fa-thumbs-up-and-fa-thumbs-down-with-gitlab-svg-thumbs-ico.yml
@@ -0,0 +1,5 @@
+---
+title: Normalize the 'thumb-up', 'thumb-down' icon.
+merge_request: 35988
+author:
+type: other
diff --git a/changelogs/unreleased/225640-move-link-to-file-view-to-bottom-bar-in-web-ide.yml b/changelogs/unreleased/225640-move-link-to-file-view-to-bottom-bar-in-web-ide.yml
new file mode 100644
index 00000000000..e45513ca16f
--- /dev/null
+++ b/changelogs/unreleased/225640-move-link-to-file-view-to-bottom-bar-in-web-ide.yml
@@ -0,0 +1,5 @@
+---
+title: Move file link to bottom in Web IDE
+merge_request: 35847
+author:
+type: changed
diff --git a/config/application.rb b/config/application.rb
index 524827226e7..47f8ca48d91 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -17,6 +17,7 @@ module Gitlab
class Application < Rails::Application
require_dependency Rails.root.join('lib/gitlab')
require_dependency Rails.root.join('lib/gitlab/utils')
+ require_dependency Rails.root.join('lib/gitlab/action_cable/config')
require_dependency Rails.root.join('lib/gitlab/redis/wrapper')
require_dependency Rails.root.join('lib/gitlab/redis/cache')
require_dependency Rails.root.join('lib/gitlab/redis/queues')
diff --git a/config/environments/development.rb b/config/environments/development.rb
index 25d57467060..9d4fc6ba5e9 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -49,8 +49,6 @@ Rails.application.configure do
# Do not log asset requests
config.assets.quiet = true
- config.allow_concurrency = Gitlab::Runtime.multi_threaded?
-
# BetterErrors live shell (REPL) on every stack frame
BetterErrors::Middleware.allow_ip!("127.0.0.1/0")
diff --git a/config/environments/production.rb b/config/environments/production.rb
index c03421040a3..393a274606e 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -77,6 +77,4 @@ Rails.application.configure do
config.action_mailer.raise_delivery_errors = true
config.eager_load = true
-
- config.allow_concurrency = Gitlab::Runtime.multi_threaded?
end
diff --git a/config/environments/test.rb b/config/environments/test.rb
index c130eb84baa..e08e2a34ff4 100644
--- a/config/environments/test.rb
+++ b/config/environments/test.rb
@@ -54,4 +54,8 @@ Rails.application.configure do
config.logger = ActiveSupport::TaggedLogging.new(Logger.new(nil))
config.log_level = :fatal
end
+
+ # Mount the ActionCable Engine in-app so that we don't have to spawn another Puma
+ # process for feature specs
+ ENV['ACTION_CABLE_IN_APP'] = 'true'
end
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index 57296e3ceae..ce22f636184 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -1105,11 +1105,6 @@ production: &base
# host: localhost
# port: 3808
- ## ActionCable settings
- action_cable:
- # Number of threads used to process ActionCable connection callbacks and channel actions
- # worker_pool_size: 4
-
## Monitoring
# Built in monitoring settings
monitoring:
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index 8d7d51f1e32..ff7090c3fa3 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -738,12 +738,6 @@ Settings.webpack.dev_server['host'] ||= 'localhost'
Settings.webpack.dev_server['port'] ||= 3808
#
-# ActionCable settings
-#
-Settings['action_cable'] ||= Settingslogic.new({})
-Settings.action_cable['worker_pool_size'] ||= 4
-
-#
# Monitoring settings
#
Settings['monitoring'] ||= Settingslogic.new({})
diff --git a/config/initializers/action_cable.rb b/config/initializers/action_cable.rb
index c549dd45ad9..5530e7d64a2 100644
--- a/config/initializers/action_cable.rb
+++ b/config/initializers/action_cable.rb
@@ -3,11 +3,11 @@
require 'action_cable/subscription_adapter/redis'
Rails.application.configure do
- # We only mount the ActionCable engine in tests where we run it in-app
- # For other environments, we run it on a standalone Puma server
- config.action_cable.mount_path = Rails.env.test? ? '/-/cable' : nil
+ # Mount the ActionCable engine when in-app mode is enabled
+ config.action_cable.mount_path = Gitlab::ActionCable::Config.in_app? ? '/-/cable' : nil
+
config.action_cable.url = Gitlab::Utils.append_path(Gitlab.config.gitlab.relative_url_root, '/-/cable')
- config.action_cable.worker_pool_size = Gitlab.config.action_cable.worker_pool_size
+ config.action_cable.worker_pool_size = Gitlab::ActionCable::Config.worker_pool_size
end
# https://github.com/rails/rails/blob/bb5ac1623e8de08c1b7b62b1368758f0d3bb6379/actioncable/lib/action_cable/subscription_adapter/redis.rb#L18
diff --git a/doc/api/epic_issues.md b/doc/api/epic_issues.md
index 86f88b0322f..4ab505f3627 100644
--- a/doc/api/epic_issues.md
+++ b/doc/api/epic_issues.md
@@ -4,13 +4,15 @@ group: Portfolio Management
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
-# Epic Issues API **(ULTIMATE)**
+# Epic Issues API **(PREMIUM)**
Every API call to epic_issues must be authenticated.
-If a user is not a member of a group and the group is private, a `GET` request on that group will result to a `404` status code.
+If a user is not a member of a group and the group is private, a `GET` request on that group will
+result in a `404` status code.
-Epics are available only in Ultimate. If epics feature is not available a `403` status code will be returned.
+Epics are available only in GitLab [Premium and higher](https://about.gitlab.com/pricing/).
+If the Epics feature is not available, a `403` status code will be returned.
## List issues for an epic
diff --git a/doc/api/epic_links.md b/doc/api/epic_links.md
index 756a41a0680..1d54bfe01e3 100644
--- a/doc/api/epic_links.md
+++ b/doc/api/epic_links.md
@@ -9,7 +9,8 @@ Every API call to `epic_links` must be authenticated.
If a user is not a member of a group and the group is private, a `GET` request on that group will result to a `404` status code.
-Epics are available only in the [Ultimate/Gold tier](https://about.gitlab.com/pricing/). If the epics feature is not available, a `403` status code will be returned.
+Multi-level Epics are available only in GitLab [Ultimate/Gold](https://about.gitlab.com/pricing/).
+If the Multi-level Epics feature is not available, a `403` status code will be returned.
## List epics related to a given epic
diff --git a/doc/api/issues.md b/doc/api/issues.md
index 6078c77e45a..8bf78facfc9 100644
--- a/doc/api/issues.md
+++ b/doc/api/issues.md
@@ -620,7 +620,7 @@ the `weight` parameter:
}
```
-Users on GitLab [Ultimate](https://about.gitlab.com/pricing/) will additionally see
+Users on GitLab [Premium](https://about.gitlab.com/pricing/) will additionally see
the `epic` property:
```javascript
@@ -669,8 +669,8 @@ POST /projects/:id/issues
| `merge_request_to_resolve_discussions_of` | integer | no | The IID of a merge request in which to resolve all issues. This will fill the issue with a default description and mark all discussions as resolved. When passing a description or title, these values will take precedence over the default values.|
| `discussion_to_resolve` | string | no | The ID of a discussion to resolve. This will fill in the issue with a default description and mark the discussion as resolved. Use in combination with `merge_request_to_resolve_discussions_of`. |
| `weight` **(STARTER)** | integer | no | The weight of the issue. Valid values are greater than or equal to 0. |
-| `epic_id` **(ULTIMATE)** | integer | no | ID of the epic to add the issue to. Valid values are greater than or equal to 0. |
-| `epic_iid` **(ULTIMATE)** | integer | no | IID of the epic to add the issue to. Valid values are greater than or equal to 0. (deprecated, [will be removed in version 5](https://gitlab.com/gitlab-org/gitlab/-/issues/35157)) |
+| `epic_id` **(PREMIUM)** | integer | no | ID of the epic to add the issue to. Valid values are greater than or equal to 0. |
+| `epic_iid` **(PREMIUM)** | integer | no | IID of the epic to add the issue to. Valid values are greater than or equal to 0. (deprecated, [will be removed in version 5](https://gitlab.com/gitlab-org/gitlab/-/issues/35157)) |
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/4/issues?title=Issues%20with%20auth&labels=bug"
@@ -787,8 +787,8 @@ PUT /projects/:id/issues/:issue_iid
| `due_date` | string | no | Date time string in the format YEAR-MONTH-DAY, for example `2016-03-11` |
| `weight` **(STARTER)** | integer | no | The weight of the issue. Valid values are greater than or equal to 0. 0 |
| `discussion_locked` | boolean | no | Flag indicating if the issue's discussion is locked. If the discussion is locked only project members can add or edit comments. |
-| `epic_id` **(ULTIMATE)** | integer | no | ID of the epic to add the issue to. Valid values are greater than or equal to 0. |
-| `epic_iid` **(ULTIMATE)** | integer | no | IID of the epic to add the issue to. Valid values are greater than or equal to 0. (deprecated, [will be removed in version 5](https://gitlab.com/gitlab-org/gitlab/-/issues/35157)) |
+| `epic_id` **(PREMIUM)** | integer | no | ID of the epic to add the issue to. Valid values are greater than or equal to 0. |
+| `epic_iid` **(PREMIUM)** | integer | no | IID of the epic to add the issue to. Valid values are greater than or equal to 0. (deprecated, [will be removed in version 5](https://gitlab.com/gitlab-org/gitlab/-/issues/35157)) |
```shell
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/4/issues/85?state_event=close"
diff --git a/lib/gitlab/action_cable/config.rb b/lib/gitlab/action_cable/config.rb
new file mode 100644
index 00000000000..38e870353eb
--- /dev/null
+++ b/lib/gitlab/action_cable/config.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module ActionCable
+ class Config
+ class << self
+ def in_app?
+ Gitlab::Utils.to_boolean(ENV.fetch('ACTION_CABLE_IN_APP', false))
+ end
+
+ def worker_pool_size
+ ENV.fetch('ACTION_CABLE_WORKER_POOL_SIZE', 4).to_i
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/config.rb b/lib/gitlab/ci/config.rb
index 10e0f4b8e4d..c01b08d703d 100644
--- a/lib/gitlab/ci/config.rb
+++ b/lib/gitlab/ci/config.rb
@@ -93,7 +93,7 @@ module Gitlab
Gitlab::ErrorTracking.track_and_raise_for_dev_exception(error, @context.sentry_payload)
end
- # Overriden in EE
+ # Overridden in EE
def rescue_errors
RESCUE_ERRORS
end
diff --git a/lib/gitlab/file_finder.rb b/lib/gitlab/file_finder.rb
index d438b0415fa..6225955a930 100644
--- a/lib/gitlab/file_finder.rb
+++ b/lib/gitlab/file_finder.rb
@@ -42,7 +42,7 @@ module Gitlab
end
end
- # Overriden in Gitlab::WikiFileFinder
+ # Overridden in Gitlab::WikiFileFinder
def search_paths(query)
repository.search_files_by_name(query, ref)
end
diff --git a/lib/gitlab/runtime.rb b/lib/gitlab/runtime.rb
index abf6ee07d53..8b40aaa101a 100644
--- a/lib/gitlab/runtime.rb
+++ b/lib/gitlab/runtime.rb
@@ -37,7 +37,7 @@ module Gitlab
end
def puma?
- !!defined?(::Puma) && !defined?(ACTION_CABLE_SERVER)
+ !!defined?(::Puma)
end
# For unicorn, we need to check for actual server instances to avoid false positives.
@@ -70,11 +70,11 @@ module Gitlab
end
def web_server?
- puma? || unicorn? || action_cable?
+ puma? || unicorn?
end
def action_cable?
- !!defined?(ACTION_CABLE_SERVER)
+ web_server? && (!!defined?(ACTION_CABLE_SERVER) || Gitlab::ActionCable::Config.in_app?)
end
def multi_threaded?
@@ -82,19 +82,21 @@ module Gitlab
end
def max_threads
- main_thread = 1
+ threads = 1 # main thread
- if action_cable?
- Gitlab::Application.config.action_cable.worker_pool_size
- elsif puma?
- Puma.cli_config.options[:max_threads]
+ if puma?
+ threads += Puma.cli_config.options[:max_threads]
elsif sidekiq?
# An extra thread for the poller in Sidekiq Cron:
# https://github.com/ondrejbartas/sidekiq-cron#under-the-hood
- Sidekiq.options[:concurrency] + 1
- else
- 0
- end + main_thread
+ threads += Sidekiq.options[:concurrency] + 1
+ end
+
+ if action_cable?
+ threads += Gitlab::ActionCable::Config.worker_pool_size
+ end
+
+ threads
end
end
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index bf3b5b9d3d3..cbf29779c11 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -2862,6 +2862,9 @@ msgstr ""
msgid "ApprovalRule|e.g. QA, Security, etc."
msgstr ""
+msgid "Approvals|Section: %section"
+msgstr ""
+
msgid "Approve"
msgstr ""
@@ -15931,6 +15934,9 @@ msgstr ""
msgid "Open in Xcode"
msgstr ""
+msgid "Open in file view"
+msgstr ""
+
msgid "Open issues"
msgstr ""
diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb
index 21dfca134e3..6cd18f2755c 100644
--- a/spec/features/admin/admin_users_spec.rb
+++ b/spec/features/admin/admin_users_spec.rb
@@ -38,7 +38,7 @@ RSpec.describe "Admin::Users" do
end
describe "view extra user information" do
- it 'shows the user popover on hover', :js, :quarantine do
+ it 'shows the user popover on hover', :js, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/11290' do
expect(page).not_to have_selector('#__BV_popover_1__')
first_user_link = page.first('.js-user-link')
diff --git a/spec/features/discussion_comments/commit_spec.rb b/spec/features/discussion_comments/commit_spec.rb
index 5a744e43bb6..32c0ba2a9a7 100644
--- a/spec/features/discussion_comments/commit_spec.rb
+++ b/spec/features/discussion_comments/commit_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe 'Thread Comments Commit', :js do
expect(page).to have_css('.js-note-emoji')
end
- it 'adds award to the correct note', quarantine: 'https://gitlab.com/gitlab-org/gitlab/issues/207973' do
+ it 'adds award to the correct note', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/207973' do
find("#note_#{commit_discussion_note2.id} .js-note-emoji").click
first('.emoji-menu .js-emoji-btn').click
diff --git a/spec/features/issuables/issuable_list_spec.rb b/spec/features/issuables/issuable_list_spec.rb
index 1481c4d07a2..8cf4dac9afe 100644
--- a/spec/features/issuables/issuable_list_spec.rb
+++ b/spec/features/issuables/issuable_list_spec.rb
@@ -28,8 +28,8 @@ RSpec.describe 'issuable list', :js do
it "counts upvotes, downvotes and notes count for each #{issuable_type.to_s.humanize}" do
visit_issuable_list(issuable_type)
- expect(first('.fa-thumbs-up').find(:xpath, '..')).to have_content(1)
- expect(first('.fa-thumbs-down').find(:xpath, '..')).to have_content(1)
+ expect(first('.issuable-upvotes')).to have_content(1)
+ expect(first('.issuable-downvotes')).to have_content(1)
expect(first('.fa-comments').find(:xpath, '..')).to have_content(2)
end
diff --git a/spec/features/issues/filtered_search/search_bar_spec.rb b/spec/features/issues/filtered_search/search_bar_spec.rb
index 167fecc5ab1..2a094281133 100644
--- a/spec/features/issues/filtered_search/search_bar_spec.rb
+++ b/spec/features/issues/filtered_search/search_bar_spec.rb
@@ -88,7 +88,7 @@ RSpec.describe 'Search bar', :js do
expect(find('#js-dropdown-hint')).to have_selector('.filter-dropdown .filter-dropdown-item', count: original_size)
end
- it 'resets the dropdown filters', :quarantine do
+ it 'resets the dropdown filters', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/9985' do
filtered_search.click
hint_offset = get_left_style(find('#js-dropdown-hint')['style'])
diff --git a/spec/features/issues/issue_detail_spec.rb b/spec/features/issues/issue_detail_spec.rb
index ab319daec71..9879703c8bf 100644
--- a/spec/features/issues/issue_detail_spec.rb
+++ b/spec/features/issues/issue_detail_spec.rb
@@ -28,7 +28,7 @@ RSpec.describe 'Issue Detail', :js do
visit project_issue_path(project, issue)
end
- it 'encodes the description to prevent xss issues', quarantine: 'https://gitlab.com/gitlab-org/gitlab/issues/207951' do
+ it 'encodes the description to prevent xss issues', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/207951' do
page.within('.issuable-details .detail-page-description') do
image = find('img.js-lazy-loaded')
diff --git a/spec/features/issues/issue_sidebar_spec.rb b/spec/features/issues/issue_sidebar_spec.rb
index 9e4362bf0e5..ecda80f2483 100644
--- a/spec/features/issues/issue_sidebar_spec.rb
+++ b/spec/features/issues/issue_sidebar_spec.rb
@@ -195,7 +195,7 @@ RSpec.describe 'Issue Sidebar' do
end
end
- context 'creating a project label', :js, :quarantine do
+ context 'creating a project label', :js, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/27992' do
before do
page.within('.block.labels') do
click_link 'Create project'
diff --git a/spec/features/issues/user_creates_branch_and_merge_request_spec.rb b/spec/features/issues/user_creates_branch_and_merge_request_spec.rb
index a546fb3e85b..900ef435d1d 100644
--- a/spec/features/issues/user_creates_branch_and_merge_request_spec.rb
+++ b/spec/features/issues/user_creates_branch_and_merge_request_spec.rb
@@ -31,7 +31,7 @@ RSpec.describe 'User creates branch and merge request on issue page', :js do
end
# In order to improve tests performance, all UI checks are placed in this test.
- it 'shows elements', :quarantine do
+ it 'shows elements', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/27993' do
button_create_merge_request = find('.js-create-merge-request')
button_toggle_dropdown = find('.create-mr-dropdown-wrap .dropdown-toggle')
@@ -141,7 +141,7 @@ RSpec.describe 'User creates branch and merge request on issue page', :js do
visit project_issue_path(project, issue)
end
- it 'disables the create branch button', :quarantine do
+ it 'disables the create branch button', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/27985' do
expect(page).to have_css('.create-mr-dropdown-wrap .unavailable:not(.hidden)')
expect(page).to have_css('.create-mr-dropdown-wrap .available.hidden', visible: false)
expect(page).to have_content /Related merge requests/
diff --git a/spec/features/issues/user_interacts_with_awards_spec.rb b/spec/features/issues/user_interacts_with_awards_spec.rb
index 7b7e087a6d6..35d9db68d32 100644
--- a/spec/features/issues/user_interacts_with_awards_spec.rb
+++ b/spec/features/issues/user_interacts_with_awards_spec.rb
@@ -16,7 +16,7 @@ RSpec.describe 'User interacts with awards' do
visit(project_issue_path(project, issue))
end
- it 'toggles the thumbsup award emoji', :quarantine do
+ it 'toggles the thumbsup award emoji', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/27959' do
page.within('.awards') do
thumbsup = page.first('.award-control')
thumbsup.click
@@ -77,7 +77,7 @@ RSpec.describe 'User interacts with awards' do
end
end
- it 'shows the list of award emoji categories', :quarantine do
+ it 'shows the list of award emoji categories', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/27991' do
page.within('.awards') do
page.find('.js-add-award').click
end
diff --git a/spec/features/labels_hierarchy_spec.rb b/spec/features/labels_hierarchy_spec.rb
index 3ab7fbea198..1545cb36e9b 100644
--- a/spec/features/labels_hierarchy_spec.rb
+++ b/spec/features/labels_hierarchy_spec.rb
@@ -23,7 +23,7 @@ RSpec.describe 'Labels Hierarchy', :js do
end
shared_examples 'assigning labels from sidebar' do
- it 'can assign all ancestors labels', :quarantine do
+ it 'can assign all ancestors labels', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/27952' do
[grandparent_group_label, parent_group_label, project_label_1].each do |label|
page.within('.block.labels') do
find('.edit-link').click
diff --git a/spec/features/merge_request/user_creates_image_diff_notes_spec.rb b/spec/features/merge_request/user_creates_image_diff_notes_spec.rb
index 34eaca24a01..3cd23764382 100644
--- a/spec/features/merge_request/user_creates_image_diff_notes_spec.rb
+++ b/spec/features/merge_request/user_creates_image_diff_notes_spec.rb
@@ -88,7 +88,7 @@ RSpec.describe 'Merge request > User creates image diff notes', :js do
create_image_diff_note
end
- it 'shows indicator and avatar badges, and allows collapsing/expanding the discussion notes', :quarantine do
+ it 'shows indicator and avatar badges, and allows collapsing/expanding the discussion notes', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/27950' do
indicator = find('.js-image-badge', match: :first)
badge = find('.user-avatar-link .badge', match: :first)
diff --git a/spec/features/merge_request/user_posts_diff_notes_spec.rb b/spec/features/merge_request/user_posts_diff_notes_spec.rb
index dbad2f191a1..6ecffb05009 100644
--- a/spec/features/merge_request/user_posts_diff_notes_spec.rb
+++ b/spec/features/merge_request/user_posts_diff_notes_spec.rb
@@ -46,7 +46,7 @@ RSpec.describe 'Merge request > User posts diff notes', :js do
end
context 'with an old line on the left and a new line on the right' do
- it 'allows commenting on the left side', quarantine: 'https://gitlab.com/gitlab-org/gitlab/issues/199050' do
+ it 'allows commenting on the left side', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/199050' do
should_allow_commenting(find('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_9_9"]').find(:xpath, '..'), 'left')
end
@@ -56,7 +56,7 @@ RSpec.describe 'Merge request > User posts diff notes', :js do
end
context 'with an unchanged line on the left and an unchanged line on the right' do
- it 'allows commenting on the left side', quarantine: 'https://gitlab.com/gitlab-org/gitlab/issues/196826' do
+ it 'allows commenting on the left side', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/196826' do
should_allow_commenting(find('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_7_7"]', match: :first).find(:xpath, '..'), 'left')
end
diff --git a/spec/features/merge_request/user_sees_diff_spec.rb b/spec/features/merge_request/user_sees_diff_spec.rb
index 2229b242d5b..d067fc0ada4 100644
--- a/spec/features/merge_request/user_sees_diff_spec.rb
+++ b/spec/features/merge_request/user_sees_diff_spec.rb
@@ -72,7 +72,7 @@ RSpec.describe 'Merge request > User sees diff', :js do
end
context 'as user who needs to fork' do
- it 'shows fork/cancel confirmation', :sidekiq_might_not_need_inline, quarantine: 'https://gitlab.com/gitlab-org/gitlab/issues/196749' do
+ it 'shows fork/cancel confirmation', :sidekiq_might_not_need_inline, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/196749' do
sign_in(user)
visit diffs_project_merge_request_path(project, merge_request)
diff --git a/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb b/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb
index e7eb4bb41cc..0506d190487 100644
--- a/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb
+++ b/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb
@@ -188,8 +188,7 @@ RSpec.describe 'User comments on a diff', :js do
end
context 'multiple suggestions in expanded lines' do
- # https://gitlab.com/gitlab-org/gitlab/issues/38277
- it 'suggestions are appliable', :quarantine do
+ it 'suggestions are appliable', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/38277' do
diff_file = merge_request.diffs(paths: ['files/ruby/popen.rb']).diff_files.first
hash = Digest::SHA1.hexdigest(diff_file.file_path)
diff --git a/spec/features/profiles/user_visits_profile_preferences_page_spec.rb b/spec/features/profiles/user_visits_profile_preferences_page_spec.rb
index d9421631b32..2747b5894dc 100644
--- a/spec/features/profiles/user_visits_profile_preferences_page_spec.rb
+++ b/spec/features/profiles/user_visits_profile_preferences_page_spec.rb
@@ -65,7 +65,7 @@ RSpec.describe 'User visits the profile preferences page' do
end
describe 'User changes their language', :js do
- it 'creates a flash message', :quarantine do
+ it 'creates a flash message', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/31404' do
select2('en', from: '#user_preferred_language')
click_button 'Save'
diff --git a/spec/features/projects/members/member_leaves_project_spec.rb b/spec/features/projects/members/member_leaves_project_spec.rb
index aa7633c3b28..c4bd0b81dc0 100644
--- a/spec/features/projects/members/member_leaves_project_spec.rb
+++ b/spec/features/projects/members/member_leaves_project_spec.rb
@@ -20,7 +20,7 @@ RSpec.describe 'Projects > Members > Member leaves project' do
expect(project.users.exists?(user.id)).to be_falsey
end
- it 'user leaves project by url param', :js, :quarantine do
+ it 'user leaves project by url param', :js, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/35925' do
visit project_path(project, leave: 1)
page.accept_confirm
diff --git a/spec/features/users/signup_spec.rb b/spec/features/users/signup_spec.rb
index ef65b3a2cc6..af2ecfec498 100644
--- a/spec/features/users/signup_spec.rb
+++ b/spec/features/users/signup_spec.rb
@@ -98,7 +98,7 @@ RSpec.shared_examples 'Signup' do
expect(page).to have_content("Invalid input, please avoid emojis")
end
- it 'shows a pending message if the username availability is being fetched', :quarantine do
+ it 'shows a pending message if the username availability is being fetched', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/31484' do
fill_in 'new_user_username', with: 'new-user'
expect(find('.username > .validation-pending')).not_to have_css '.hide'
diff --git a/spec/frontend/__mocks__/document-register-element/index.js b/spec/frontend/__mocks__/document-register-element/index.js
new file mode 100644
index 00000000000..2d1ec238274
--- /dev/null
+++ b/spec/frontend/__mocks__/document-register-element/index.js
@@ -0,0 +1 @@
+export default () => {};
diff --git a/spec/frontend/awards_handler_spec.js b/spec/frontend/awards_handler_spec.js
index 754f0702b84..ef09c59b5f6 100644
--- a/spec/frontend/awards_handler_spec.js
+++ b/spec/frontend/awards_handler_spec.js
@@ -1,13 +1,17 @@
import $ from 'jquery';
import Cookies from 'js-cookie';
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
import loadAwardsHandler from '~/awards_handler';
import '~/lib/utils/common_utils';
import waitForPromises from './helpers/wait_for_promises';
+import { EMOJI_VERSION } from '~/emoji';
window.gl = window.gl || {};
window.gon = window.gon || {};
let openAndWaitForEmojiMenu;
+let mock;
let awardsHandler = null;
const urlRoot = gon.relative_url_root;
@@ -24,8 +28,13 @@ const lazyAssert = (done, assertFn) => {
};
describe('AwardsHandler', () => {
+ const emojiData = getJSONFixture('emojis/emojis.json');
preloadFixtures('snippets/show.html');
+
beforeEach(done => {
+ mock = new MockAdapter(axios);
+ mock.onGet(`/-/emojis/${EMOJI_VERSION}/emojis.json`).reply(200, emojiData);
+
loadFixtures('snippets/show.html');
loadAwardsHandler(true)
.then(obj => {
@@ -58,6 +67,8 @@ describe('AwardsHandler', () => {
// restore original url root value
gon.relative_url_root = urlRoot;
+ mock.restore();
+
// Undo what we did to the shared <body>
$('body').removeAttr('data-page');
diff --git a/spec/frontend/behaviors/gl_emoji_spec.js b/spec/frontend/behaviors/gl_emoji_spec.js
new file mode 100644
index 00000000000..7ea0bafc328
--- /dev/null
+++ b/spec/frontend/behaviors/gl_emoji_spec.js
@@ -0,0 +1,110 @@
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
+import { initEmojiMap, EMOJI_VERSION } from '~/emoji';
+import installGlEmojiElement from '~/behaviors/gl_emoji';
+
+import * as EmojiUnicodeSupport from '~/emoji/support';
+import waitForPromises from 'jest/helpers/wait_for_promises';
+
+jest.mock('~/emoji/support');
+
+describe('gl_emoji', () => {
+ let mock;
+ const emojiData = getJSONFixture('emojis/emojis.json');
+
+ beforeAll(() => {
+ jest.spyOn(EmojiUnicodeSupport, 'default').mockReturnValue(true);
+ installGlEmojiElement();
+ });
+
+ function markupToDomElement(markup) {
+ const div = document.createElement('div');
+ div.innerHTML = markup;
+ document.body.appendChild(div);
+
+ return div.firstElementChild;
+ }
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ mock.onGet(`/-/emojis/${EMOJI_VERSION}/emojis.json`).reply(200, emojiData);
+
+ return initEmojiMap().catch(() => {});
+ });
+
+ afterEach(() => {
+ mock.restore();
+
+ document.body.innerHTML = '';
+ });
+
+ describe.each([
+ [
+ 'bomb emoji just with name attribute',
+ '<gl-emoji data-name="bomb"></gl-emoji>',
+ '<gl-emoji data-name="bomb" data-unicode-version="6.0" title="bomb">💣</gl-emoji>',
+ '<gl-emoji data-name="bomb" data-unicode-version="6.0" title="bomb"><img class="emoji" title=":bomb:" alt=":bomb:" src="/-/emojis/1/bomb.png" width="20" height="20" align="absmiddle"></gl-emoji>',
+ ],
+ [
+ 'bomb emoji with name attribute and unicode version',
+ '<gl-emoji data-name="bomb" data-unicode-version="6.0">💣</gl-emoji>',
+ '<gl-emoji data-name="bomb" data-unicode-version="6.0">💣</gl-emoji>',
+ '<gl-emoji data-name="bomb" data-unicode-version="6.0"><img class="emoji" title=":bomb:" alt=":bomb:" src="/-/emojis/1/bomb.png" width="20" height="20" align="absmiddle"></gl-emoji>',
+ ],
+ [
+ 'bomb emoji with sprite fallback',
+ '<gl-emoji data-fallback-sprite-class="emoji-bomb" data-name="bomb"></gl-emoji>',
+ '<gl-emoji data-fallback-sprite-class="emoji-bomb" data-name="bomb" data-unicode-version="6.0" title="bomb">💣</gl-emoji>',
+ '<gl-emoji data-fallback-sprite-class="emoji-bomb" data-name="bomb" data-unicode-version="6.0" title="bomb" class="emoji-icon emoji-bomb">💣</gl-emoji>',
+ ],
+ [
+ 'bomb emoji with image fallback',
+ '<gl-emoji data-fallback-src="/bomb.png" data-name="bomb"></gl-emoji>',
+ '<gl-emoji data-fallback-src="/bomb.png" data-name="bomb" data-unicode-version="6.0" title="bomb">💣</gl-emoji>',
+ '<gl-emoji data-fallback-src="/bomb.png" data-name="bomb" data-unicode-version="6.0" title="bomb"><img class="emoji" title=":bomb:" alt=":bomb:" src="/bomb.png" width="20" height="20" align="absmiddle"></gl-emoji>',
+ ],
+ [
+ 'invalid emoji',
+ '<gl-emoji data-name="invalid_emoji"></gl-emoji>',
+ '<gl-emoji data-name="grey_question" data-unicode-version="6.0" title="white question mark ornament">❔</gl-emoji>',
+ '<gl-emoji data-name="grey_question" data-unicode-version="6.0" title="white question mark ornament"><img class="emoji" title=":grey_question:" alt=":grey_question:" src="/-/emojis/1/grey_question.png" width="20" height="20" align="absmiddle"></gl-emoji>',
+ ],
+ ])('%s', (name, markup, withEmojiSupport, withoutEmojiSupport) => {
+ it(`renders correctly with emoji support`, async () => {
+ jest.spyOn(EmojiUnicodeSupport, 'default').mockReturnValue(true);
+ const glEmojiElement = markupToDomElement(markup);
+
+ await waitForPromises();
+
+ expect(glEmojiElement.outerHTML).toBe(withEmojiSupport);
+ });
+
+ it(`renders correctly without emoji support`, async () => {
+ jest.spyOn(EmojiUnicodeSupport, 'default').mockReturnValue(false);
+ const glEmojiElement = markupToDomElement(markup);
+
+ await waitForPromises();
+
+ expect(glEmojiElement.outerHTML).toBe(withoutEmojiSupport);
+ });
+ });
+
+ it('Adds sprite CSS if emojis are not supported', async () => {
+ const testPath = '/test-path.css';
+ jest.spyOn(EmojiUnicodeSupport, 'default').mockReturnValue(false);
+ window.gon.emoji_sprites_css_path = testPath;
+
+ expect(document.head.querySelector(`link[href="${testPath}"]`)).toBe(null);
+ expect(window.gon.emoji_sprites_css_added).toBeFalsy();
+
+ markupToDomElement(
+ '<gl-emoji data-fallback-sprite-class="emoji-bomb" data-name="bomb"></gl-emoji>',
+ );
+ await waitForPromises();
+
+ expect(document.head.querySelector(`link[href="${testPath}"]`).outerHTML).toBe(
+ '<link rel="stylesheet" href="/test-path.css">',
+ );
+ expect(window.gon.emoji_sprites_css_added).toBe(true);
+ });
+});
diff --git a/spec/frontend/emoji_spec.js b/spec/frontend/emoji/emoji_spec.js
index 25bc95e0dd6..c6a15d5976a 100644
--- a/spec/frontend/emoji_spec.js
+++ b/spec/frontend/emoji/emoji_spec.js
@@ -1,4 +1,6 @@
-import { glEmojiTag } from '~/emoji';
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
+import { initEmojiMap, glEmojiTag, EMOJI_VERSION } from '~/emoji';
import isEmojiUnicodeSupported, {
isFlagEmoji,
isRainbowFlagEmoji,
@@ -7,6 +9,7 @@ import isEmojiUnicodeSupported, {
isHorceRacingSkinToneComboEmoji,
isPersonZwjEmoji,
} from '~/emoji/support/is_emoji_unicode_supported';
+import { trimText } from 'helpers/text_helper';
const emptySupportMap = {
personZwj: false,
@@ -50,77 +53,28 @@ const emojiFixtureMap = {
},
};
-function markupToDomElement(markup) {
- const div = document.createElement('div');
- div.innerHTML = markup;
- return div.firstElementChild;
-}
-
-function testGlEmojiImageFallback(element, name, src) {
- expect(element.tagName.toLowerCase()).toBe('img');
- expect(element.getAttribute('src')).toBe(src);
- expect(element.getAttribute('title')).toBe(`:${name}:`);
- expect(element.getAttribute('alt')).toBe(`:${name}:`);
-}
-
-const defaults = {
- forceFallback: false,
- sprite: false,
-};
+describe('gl_emoji', () => {
+ let mock;
+ const emojiData = getJSONFixture('emojis/emojis.json');
-function testGlEmojiElement(element, name, unicodeVersion, unicodeMoji, options = {}) {
- const opts = { ...defaults, ...options };
- expect(element.tagName.toLowerCase()).toBe('gl-emoji');
- expect(element.dataset.name).toBe(name);
- expect(element.dataset.fallbackSrc.length).toBeGreaterThan(0);
- expect(element.dataset.unicodeVersion).toBe(unicodeVersion);
-
- const fallbackSpriteClass = `emoji-${name}`;
- if (opts.sprite) {
- expect(element.dataset.fallbackSpriteClass).toBe(fallbackSpriteClass);
- }
-
- if (opts.forceFallback && opts.sprite) {
- expect(element.getAttribute('class')).toBe(`emoji-icon ${fallbackSpriteClass}`);
- }
-
- if (opts.forceFallback && !opts.sprite) {
- // Check for image fallback
- testGlEmojiImageFallback(element.firstElementChild, name, element.dataset.fallbackSrc);
- } else {
- // Otherwise make sure things are still unicode text
- expect(element.textContent.trim()).toBe(unicodeMoji);
- }
-}
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ mock.onGet(`/-/emojis/${EMOJI_VERSION}/emojis.json`).reply(200, emojiData);
+
+ return initEmojiMap().catch(() => {});
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
-describe('gl_emoji', () => {
describe('glEmojiTag', () => {
it('bomb emoji', () => {
const emojiKey = 'bomb';
const markup = glEmojiTag(emojiFixtureMap[emojiKey].name);
- const glEmojiElement = markupToDomElement(markup);
- testGlEmojiElement(
- glEmojiElement,
- emojiFixtureMap[emojiKey].name,
- emojiFixtureMap[emojiKey].unicodeVersion,
- emojiFixtureMap[emojiKey].moji,
- );
- });
- it('bomb emoji with image fallback', () => {
- const emojiKey = 'bomb';
- const markup = glEmojiTag(emojiFixtureMap[emojiKey].name, {
- forceFallback: true,
- });
- const glEmojiElement = markupToDomElement(markup);
- testGlEmojiElement(
- glEmojiElement,
- emojiFixtureMap[emojiKey].name,
- emojiFixtureMap[emojiKey].unicodeVersion,
- emojiFixtureMap[emojiKey].moji,
- {
- forceFallback: true,
- },
+ expect(trimText(markup)).toMatchInlineSnapshot(
+ `"<gl-emoji data-name=\\"bomb\\"></gl-emoji>"`,
);
});
@@ -129,65 +83,8 @@ describe('gl_emoji', () => {
const markup = glEmojiTag(emojiFixtureMap[emojiKey].name, {
sprite: true,
});
- const glEmojiElement = markupToDomElement(markup);
- testGlEmojiElement(
- glEmojiElement,
- emojiFixtureMap[emojiKey].name,
- emojiFixtureMap[emojiKey].unicodeVersion,
- emojiFixtureMap[emojiKey].moji,
- {
- sprite: true,
- },
- );
- });
-
- it('bomb emoji with sprite fallback', () => {
- const emojiKey = 'bomb';
- const markup = glEmojiTag(emojiFixtureMap[emojiKey].name, {
- forceFallback: true,
- sprite: true,
- });
- const glEmojiElement = markupToDomElement(markup);
- testGlEmojiElement(
- glEmojiElement,
- emojiFixtureMap[emojiKey].name,
- emojiFixtureMap[emojiKey].unicodeVersion,
- emojiFixtureMap[emojiKey].moji,
- {
- forceFallback: true,
- sprite: true,
- },
- );
- });
-
- it('question mark when invalid emoji name given', () => {
- const name = 'invalid_emoji';
- const emojiKey = 'grey_question';
- const markup = glEmojiTag(name);
- const glEmojiElement = markupToDomElement(markup);
- testGlEmojiElement(
- glEmojiElement,
- emojiFixtureMap[emojiKey].name,
- emojiFixtureMap[emojiKey].unicodeVersion,
- emojiFixtureMap[emojiKey].moji,
- );
- });
-
- it('question mark with image fallback when invalid emoji name given', () => {
- const name = 'invalid_emoji';
- const emojiKey = 'grey_question';
- const markup = glEmojiTag(name, {
- forceFallback: true,
- });
- const glEmojiElement = markupToDomElement(markup);
- testGlEmojiElement(
- glEmojiElement,
- emojiFixtureMap[emojiKey].name,
- emojiFixtureMap[emojiKey].unicodeVersion,
- emojiFixtureMap[emojiKey].moji,
- {
- forceFallback: true,
- },
+ expect(trimText(markup)).toMatchInlineSnapshot(
+ `"<gl-emoji data-fallback-sprite-class=\\"emoji-bomb\\" data-name=\\"bomb\\"></gl-emoji>"`,
);
});
});
diff --git a/spec/frontend/behaviors/gl_emoji/unicode_support_map_spec.js b/spec/frontend/emoji/support/unicode_support_map_spec.js
index aaee9c30cac..aaee9c30cac 100644
--- a/spec/frontend/behaviors/gl_emoji/unicode_support_map_spec.js
+++ b/spec/frontend/emoji/support/unicode_support_map_spec.js
diff --git a/spec/frontend/fixtures/emojis.rb b/spec/frontend/fixtures/emojis.rb
new file mode 100644
index 00000000000..b95c7632917
--- /dev/null
+++ b/spec/frontend/fixtures/emojis.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Emojis (JavaScript fixtures)', type: :request do
+ include JavaScriptFixturesHelpers
+
+ before(:all) do
+ clean_frontend_fixtures('emojis/')
+ end
+
+ it 'emojis/emojis.json' do |example|
+ get '/-/emojis/1/emojis.json'
+
+ expect(response).to be_successful
+ end
+end
diff --git a/spec/frontend/ide/components/ide_status_list_spec.js b/spec/frontend/ide/components/ide_status_list_spec.js
index 847464ed806..fed61233e55 100644
--- a/spec/frontend/ide/components/ide_status_list_spec.js
+++ b/spec/frontend/ide/components/ide_status_list_spec.js
@@ -1,5 +1,6 @@
import Vuex from 'vuex';
import { createLocalVue, shallowMount } from '@vue/test-utils';
+import { GlLink } from '@gitlab/ui';
import IdeStatusList from '~/ide/components/ide_status_list.vue';
import TerminalSyncStatusSafe from '~/ide/components/terminal_sync/terminal_sync_status_safe.vue';
@@ -9,6 +10,7 @@ const TEST_FILE = {
editorColumn: 23,
fileLanguage: 'markdown',
content: 'abc\nndef',
+ permalink: '/lorem.md',
};
const localVue = createLocalVue();
@@ -19,6 +21,7 @@ describe('ide/components/ide_status_list', () => {
let store;
let wrapper;
+ const findLink = () => wrapper.find(GlLink);
const createComponent = (options = {}) => {
store = new Vuex.Store({
getters: {
@@ -51,8 +54,9 @@ describe('ide/components/ide_status_list', () => {
createComponent();
});
- it('shows file name', () => {
- expect(wrapper.text()).toContain(TEST_FILE.name);
+ it('shows a link to the file that contains the file name', () => {
+ expect(findLink().attributes('href')).toBe(TEST_FILE.permalink);
+ expect(findLink().text()).toBe(TEST_FILE.name);
});
it('shows file eol', () => {
diff --git a/spec/frontend/monitoring/components/dashboard_panel_spec.js b/spec/frontend/monitoring/components/dashboard_panel_spec.js
index 96e0c39cb27..a2499c84ff7 100644
--- a/spec/frontend/monitoring/components/dashboard_panel_spec.js
+++ b/spec/frontend/monitoring/components/dashboard_panel_spec.js
@@ -369,7 +369,7 @@ describe('Dashboard Panel', () => {
});
});
- it('it is overriden when a datazoom event is received', () => {
+ it('it is overridden when a datazoom event is received', () => {
state.logsPath = mockLogsPath;
state.timeRange = mockTimeRange;
diff --git a/spec/frontend/pipelines/test_reports/stores/actions_spec.js b/spec/frontend/pipelines/test_reports/stores/actions_spec.js
index bd42db36645..c47c6e99103 100644
--- a/spec/frontend/pipelines/test_reports/stores/actions_spec.js
+++ b/spec/frontend/pipelines/test_reports/stores/actions_spec.js
@@ -22,7 +22,7 @@ describe('Actions TestReports Store', () => {
fullReportEndpoint,
summaryEndpoint,
testReports: {},
- selectedSuite: {},
+ selectedSuite: null,
summary: {},
};
@@ -101,28 +101,28 @@ describe('Actions TestReports Store', () => {
});
});
- describe('set selected suite', () => {
- const selectedSuite = testReports.test_suites[0];
+ describe('set selected suite index', () => {
+ const selectedSuiteIndex = 0;
- it('sets selectedSuite', done => {
+ it('sets selectedSuiteIndex', done => {
testAction(
- actions.setSelectedSuite,
- selectedSuite,
+ actions.setSelectedSuiteIndex,
+ selectedSuiteIndex,
state,
- [{ type: types.SET_SELECTED_SUITE, payload: selectedSuite }],
+ [{ type: types.SET_SELECTED_SUITE_INDEX, payload: selectedSuiteIndex }],
[],
done,
);
});
});
- describe('remove selected suite', () => {
- it('sets selectedSuite to {}', done => {
+ describe('remove selected suite index', () => {
+ it('sets selectedSuiteIndex to null', done => {
testAction(
- actions.removeSelectedSuite,
+ actions.removeSelectedSuiteIndex,
{},
state,
- [{ type: types.SET_SELECTED_SUITE, payload: {} }],
+ [{ type: types.SET_SELECTED_SUITE_INDEX, payload: null }],
[],
done,
);
diff --git a/spec/frontend/pipelines/test_reports/stores/getters_spec.js b/spec/frontend/pipelines/test_reports/stores/getters_spec.js
index 011a7e68908..ca9ebb54138 100644
--- a/spec/frontend/pipelines/test_reports/stores/getters_spec.js
+++ b/spec/frontend/pipelines/test_reports/stores/getters_spec.js
@@ -9,12 +9,12 @@ describe('Getters TestReports Store', () => {
const defaultState = {
testReports,
- selectedSuite: testReports.test_suites[0],
+ selectedSuiteIndex: 0,
};
const emptyState = {
testReports: {},
- selectedSuite: {},
+ selectedSuite: null,
};
beforeEach(() => {
@@ -47,6 +47,17 @@ describe('Getters TestReports Store', () => {
});
});
+ describe('getSelectedSuite', () => {
+ it('should return the selected suite', () => {
+ setupState();
+
+ const selectedSuite = getters.getSelectedSuite(state);
+ const expected = testReports.test_suites[state.selectedSuiteIndex];
+
+ expect(selectedSuite).toEqual(expected);
+ });
+ });
+
describe('getSuiteTests', () => {
it('should return the test cases inside the suite', () => {
setupState();
diff --git a/spec/frontend/pipelines/test_reports/stores/mutations_spec.js b/spec/frontend/pipelines/test_reports/stores/mutations_spec.js
index cf54cacab60..2320f84b3bb 100644
--- a/spec/frontend/pipelines/test_reports/stores/mutations_spec.js
+++ b/spec/frontend/pipelines/test_reports/stores/mutations_spec.js
@@ -10,7 +10,7 @@ describe('Mutations TestReports Store', () => {
const defaultState = {
endpoint: '',
testReports: {},
- selectedSuite: {},
+ selectedSuite: null,
isLoading: false,
};
@@ -27,12 +27,12 @@ describe('Mutations TestReports Store', () => {
});
});
- describe('set selected suite', () => {
- it('should set selectedSuite', () => {
- const selectedSuite = testReports.test_suites[0];
- mutations[types.SET_SELECTED_SUITE](mockState, selectedSuite);
+ describe('set selected suite index', () => {
+ it('should set selectedSuiteIndex', () => {
+ const selectedSuiteIndex = 0;
+ mutations[types.SET_SELECTED_SUITE_INDEX](mockState, selectedSuiteIndex);
- expect(mockState.selectedSuite).toEqual(selectedSuite);
+ expect(mockState.selectedSuiteIndex).toEqual(selectedSuiteIndex);
});
});
diff --git a/spec/frontend/pipelines/test_reports/test_reports_spec.js b/spec/frontend/pipelines/test_reports/test_reports_spec.js
index dd2b7220d7c..7bd71716cb0 100644
--- a/spec/frontend/pipelines/test_reports/test_reports_spec.js
+++ b/spec/frontend/pipelines/test_reports/test_reports_spec.js
@@ -3,6 +3,7 @@ import { shallowMount, createLocalVue } from '@vue/test-utils';
import { getJSONFixture } from 'helpers/fixtures';
import TestReports from '~/pipelines/components/test_reports/test_reports.vue';
import * as actions from '~/pipelines/stores/test_reports/actions';
+import * as getters from '~/pipelines/stores/test_reports/getters';
const localVue = createLocalVue();
localVue.use(Vuex);
@@ -29,6 +30,7 @@ describe('Test reports app', () => {
...actions,
fetchSummary: () => {},
},
+ getters,
});
wrapper = shallowMount(TestReports, {
diff --git a/spec/frontend/pipelines/test_reports/test_suite_table_spec.js b/spec/frontend/pipelines/test_reports/test_suite_table_spec.js
index 5d448bcb439..65bffe7039a 100644
--- a/spec/frontend/pipelines/test_reports/test_suite_table_spec.js
+++ b/spec/frontend/pipelines/test_reports/test_suite_table_spec.js
@@ -28,7 +28,10 @@ describe('Test reports suite table', () => {
const createComponent = (suite = testSuite) => {
store = new Vuex.Store({
state: {
- selectedSuite: suite,
+ testReports: {
+ test_suites: [suite],
+ },
+ selectedSuiteIndex: 0,
},
getters,
});
diff --git a/spec/frontend/vue_shared/components/__snapshots__/awards_list_spec.js.snap b/spec/frontend/vue_shared/components/__snapshots__/awards_list_spec.js.snap
index df4b30f1cb8..19671d425a9 100644
--- a/spec/frontend/vue_shared/components/__snapshots__/awards_list_spec.js.snap
+++ b/spec/frontend/vue_shared/components/__snapshots__/awards_list_spec.js.snap
@@ -18,15 +18,8 @@ exports[`vue_shared/components/awards_list default matches snapshot 1`] = `
<gl-emoji
- data-fallback-src="/assets/emoji/thumbsup-59ec2457ab33e8897261d01a495f6cf5c668d0004807dc541c3b1be5294b1e61.png"
data-name="thumbsup"
- data-unicode-version="6.0"
- title="thumbs up sign"
- >
-
- 👍
-
- </gl-emoji>
+ />
</span>
@@ -51,15 +44,8 @@ exports[`vue_shared/components/awards_list default matches snapshot 1`] = `
<gl-emoji
- data-fallback-src="/assets/emoji/thumbsdown-5954334e2dae5357312b3d629f10a496c728029e02216f8c8b887f9b51561c61.png"
data-name="thumbsdown"
- data-unicode-version="6.0"
- title="thumbs down sign"
- >
-
- 👎
-
- </gl-emoji>
+ />
</span>
@@ -84,15 +70,8 @@ exports[`vue_shared/components/awards_list default matches snapshot 1`] = `
<gl-emoji
- data-fallback-src="/assets/emoji/smile-14905c372d5bf7719bd727c9efae31a03291acec79801652a23710c6848c5d14.png"
data-name="smile"
- data-unicode-version="6.0"
- title="smiling face with open mouth and smiling eyes"
- >
-
- 😄
-
- </gl-emoji>
+ />
</span>
@@ -117,15 +96,8 @@ exports[`vue_shared/components/awards_list default matches snapshot 1`] = `
<gl-emoji
- data-fallback-src="/assets/emoji/ok_hand-d63002dce3cc3655b67b8765b7c28d370edba0e3758b2329b60e0e61c4d8e78d.png"
data-name="ok_hand"
- data-unicode-version="6.0"
- title="ok hand sign"
- >
-
- 👌
-
- </gl-emoji>
+ />
</span>
@@ -150,15 +122,8 @@ exports[`vue_shared/components/awards_list default matches snapshot 1`] = `
<gl-emoji
- data-fallback-src="/assets/emoji/cactus-2c5c4c35f26c7046fdc002b337e0d939729b33a26980e675950f9934c91e40fd.png"
data-name="cactus"
- data-unicode-version="6.0"
- title="cactus"
- >
-
- 🌵
-
- </gl-emoji>
+ />
</span>
@@ -183,15 +148,8 @@ exports[`vue_shared/components/awards_list default matches snapshot 1`] = `
<gl-emoji
- data-fallback-src="/assets/emoji/a-bddbb39e8a1d35d42b7c08e7d47f63988cb4d8614b79f74e70b9c67c221896cc.png"
data-name="a"
- data-unicode-version="6.0"
- title="negative squared latin capital letter a"
- >
-
- 🅰
-
- </gl-emoji>
+ />
</span>
@@ -216,15 +174,8 @@ exports[`vue_shared/components/awards_list default matches snapshot 1`] = `
<gl-emoji
- data-fallback-src="/assets/emoji/b-722f9db9442e7c0fc0d0ac0f5291fbf47c6a0ac4d8abd42e97957da705fb82bf.png"
data-name="b"
- data-unicode-version="6.0"
- title="negative squared latin capital letter b"
- >
-
- 🅱
-
- </gl-emoji>
+ />
</span>
diff --git a/spec/lib/gitlab/background_migration/migrate_build_stage_spec.rb b/spec/lib/gitlab/background_migration/migrate_build_stage_spec.rb
index 78a4ec34cf2..65d45ec694f 100644
--- a/spec/lib/gitlab/background_migration/migrate_build_stage_spec.rb
+++ b/spec/lib/gitlab/background_migration/migrate_build_stage_spec.rb
@@ -55,7 +55,7 @@ RSpec.describe Gitlab::BackgroundMigration::MigrateBuildStage do
statuses[:pending]]
end
- it 'recovers from unique constraint violation only twice', :quarantine do
+ it 'recovers from unique constraint violation only twice', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/28128' do
allow(described_class::Migratable::Stage)
.to receive(:find_by).and_return(nil)
diff --git a/spec/lib/gitlab/lograge/custom_options_spec.rb b/spec/lib/gitlab/lograge/custom_options_spec.rb
index 550f8c17f04..218007c6e2a 100644
--- a/spec/lib/gitlab/lograge/custom_options_spec.rb
+++ b/spec/lib/gitlab/lograge/custom_options_spec.rb
@@ -65,14 +65,14 @@ RSpec.describe Gitlab::Lograge::CustomOptions do
end
end
- context 'when correlation_id is overriden' do
+ context 'when correlation_id is overridden' do
let(:correlation_id_key) { Labkit::Correlation::CorrelationId::LOG_KEY }
before do
event_payload[correlation_id_key] = '123456'
end
- it 'sets the overriden value' do
+ it 'sets the overridden value' do
expect(subject[correlation_id_key]).to eq('123456')
end
end
diff --git a/spec/lib/gitlab/runtime_spec.rb b/spec/lib/gitlab/runtime_spec.rb
index 8c1f17d070e..8ed7cc141cd 100644
--- a/spec/lib/gitlab/runtime_spec.rb
+++ b/spec/lib/gitlab/runtime_spec.rb
@@ -48,18 +48,47 @@ RSpec.describe Gitlab::Runtime do
before do
stub_const('::Puma', puma_type)
allow(puma_type).to receive_message_chain(:cli_config, :options).and_return(max_threads: 2)
+ stub_env('ACTION_CABLE_IN_APP', 'false')
end
it_behaves_like "valid runtime", :puma, 3
+
+ context "when ActionCable in-app mode is enabled" do
+ before do
+ stub_env('ACTION_CABLE_IN_APP', 'true')
+ stub_env('ACTION_CABLE_WORKER_POOL_SIZE', '3')
+ end
+
+ it_behaves_like "valid runtime", :puma, 6
+ end
+
+ context "when ActionCable standalone is run" do
+ before do
+ stub_const('ACTION_CABLE_SERVER', true)
+ stub_env('ACTION_CABLE_WORKER_POOL_SIZE', '8')
+ end
+
+ it_behaves_like "valid runtime", :puma, 11
+ end
end
context "unicorn" do
before do
stub_const('::Unicorn', Module.new)
stub_const('::Unicorn::HttpServer', Class.new)
+ stub_env('ACTION_CABLE_IN_APP', 'false')
end
it_behaves_like "valid runtime", :unicorn, 1
+
+ context "when ActionCable in-app mode is enabled" do
+ before do
+ stub_env('ACTION_CABLE_IN_APP', 'true')
+ stub_env('ACTION_CABLE_WORKER_POOL_SIZE', '3')
+ end
+
+ it_behaves_like "valid runtime", :unicorn, 4
+ end
end
context "sidekiq" do
@@ -105,17 +134,4 @@ RSpec.describe Gitlab::Runtime do
it_behaves_like "valid runtime", :rails_runner, 1
end
-
- context "action_cable" do
- before do
- stub_const('ACTION_CABLE_SERVER', true)
- stub_const('::Puma', Module.new)
-
- allow(Gitlab::Application).to receive_message_chain(:config, :action_cable, :worker_pool_size).and_return(8)
- end
-
- it "reports its maximum concurrency based on ActionCable's worker pool size" do
- expect(subject.max_threads).to eq(9)
- end
- end
end
diff --git a/spec/models/concerns/reactive_caching_spec.rb b/spec/models/concerns/reactive_caching_spec.rb
index 425dc70e7a1..b12ad82920f 100644
--- a/spec/models/concerns/reactive_caching_spec.rb
+++ b/spec/models/concerns/reactive_caching_spec.rb
@@ -298,7 +298,7 @@ RSpec.describe ReactiveCaching, :use_clean_rails_memory_store_caching do
expect(read_reactive_cache(instance)).not_to eq(calculation.call)
end
- context 'when reactive_cache_limit_enabled? is overriden to return false' do
+ context 'when reactive_cache_limit_enabled? is overridden to return false' do
before do
allow(instance).to receive(:reactive_cache_limit_enabled?).and_return(false)
end
diff --git a/spec/models/personal_access_token_spec.rb b/spec/models/personal_access_token_spec.rb
index b9cb5477c54..7fae9cc60fc 100644
--- a/spec/models/personal_access_token_spec.rb
+++ b/spec/models/personal_access_token_spec.rb
@@ -204,7 +204,7 @@ RSpec.describe PersonalAccessToken do
end
describe '.simple_sorts' do
- it 'includes overriden keys' do
+ it 'includes overridden keys' do
expect(described_class.simple_sorts.keys).to include(*%w(expires_at_asc expires_at_desc))
end
end
diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb
index 66601d26bd2..57e32b1aea9 100644
--- a/spec/services/quick_actions/interpret_service_spec.rb
+++ b/spec/services/quick_actions/interpret_service_spec.rb
@@ -792,7 +792,7 @@ RSpec.describe QuickActions::InterpretService do
let(:issuable) { issue }
end
- it_behaves_like 'assign command', :quarantine do
+ it_behaves_like 'assign command', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/27989' do
let(:content) { "/assign @#{developer.username} @#{developer2.username}" }
let(:issuable) { merge_request }
end
diff --git a/spec/support/shared_examples/features/discussion_comments_shared_example.rb b/spec/support/shared_examples/features/discussion_comments_shared_example.rb
index 6007798c290..9fc5d8933e5 100644
--- a/spec/support/shared_examples/features/discussion_comments_shared_example.rb
+++ b/spec/support/shared_examples/features/discussion_comments_shared_example.rb
@@ -266,7 +266,7 @@ RSpec.shared_examples 'thread comments' do |resource_name|
end
end
- it 'has "Comment" selected when opening the menu', quarantine: 'https://gitlab.com/gitlab-org/gitlab/issues/196825' do
+ it 'has "Comment" selected when opening the menu', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/196825' do
find(toggle_selector).click
find("#{menu_selector} li", match: :first)