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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/diffs/components/app.vue51
-rw-r--r--app/assets/javascripts/diffs/store/actions.js17
-rw-r--r--app/assets/javascripts/diffs/store/getters.js3
-rw-r--r--app/assets/javascripts/diffs/store/modules/diff_state.js2
-rw-r--r--app/assets/javascripts/diffs/store/mutation_types.js2
-rw-r--r--app/assets/javascripts/diffs/store/mutations.js4
-rw-r--r--app/assets/javascripts/init_changes_dropdown.js12
-rw-r--r--app/assets/javascripts/init_diff_stats_dropdown.js30
-rw-r--r--app/assets/javascripts/merge_request_tabs.js5
-rw-r--r--app/assets/javascripts/milestones/stores/mutations.js4
-rw-r--r--app/assets/javascripts/packages_and_registries/package_registry/components/details/additional_metadata.vue46
-rw-r--r--app/assets/javascripts/pages/projects/commit/show/index.js4
-rw-r--r--app/assets/javascripts/pages/projects/compare/show/index.js4
-rw-r--r--app/assets/javascripts/pages/projects/wikis/index.js2
-rw-r--r--app/assets/javascripts/vue_shared/components/diff_stats_dropdown.vue159
-rw-r--r--app/assets/stylesheets/framework/diffs.scss41
-rw-r--r--app/assets/stylesheets/page_bundles/signup.scss30
-rw-r--r--app/controllers/registrations/experience_levels_controller.rb44
-rw-r--r--app/helpers/diff_helper.rb21
-rw-r--r--app/models/user.rb1
-rw-r--r--app/models/user_preference.rb2
-rw-r--r--app/views/projects/diffs/_stats.html.haml42
-rw-r--r--app/views/registrations/experience_levels/show.html.haml29
-rw-r--r--config/feature_flags/ops/lower_relation_max_count_limit.yml8
-rw-r--r--config/initializers/kaminari_active_record_relation_methods_with_limit.rb4
-rw-r--r--config/routes.rb2
-rw-r--r--doc/administration/auth/atlassian.md2
-rw-r--r--doc/administration/clusters/kas.md22
-rw-r--r--doc/administration/integration/mailgun.md2
-rw-r--r--doc/administration/integration/plantuml.md2
-rw-r--r--doc/administration/operations/puma.md50
-rw-r--r--doc/administration/static_objects_external_storage.md2
-rw-r--r--doc/development/documentation/styleguide/word_list.md17
-rw-r--r--doc/development/integrations/jenkins.md2
-rw-r--r--doc/development/issue_types.md5
-rw-r--r--doc/development/work_items.md196
-rw-r--r--doc/integration/akismet.md2
-rw-r--r--doc/integration/datadog.md2
-rw-r--r--doc/integration/github.md2
-rw-r--r--doc/integration/gitlab.md2
-rw-r--r--doc/integration/gitpod.md2
-rw-r--r--doc/integration/jenkins.md2
-rw-r--r--doc/integration/jira/dvcs.md4
-rw-r--r--doc/integration/kerberos.md2
-rw-r--r--doc/integration/oauth_provider.md2
-rw-r--r--doc/integration/omniauth.md4
-rw-r--r--doc/integration/sourcegraph.md2
-rw-r--r--doc/integration/trello_power_up.md2
-rw-r--r--doc/integration/vault.md2
-rw-r--r--doc/raketasks/features.md2
-rw-r--r--doc/security/webhooks.md4
-rw-r--r--doc/subscriptions/gitlab_com/index.md4
-rw-r--r--doc/system_hooks/system_hooks.md2
-rw-r--r--doc/tools/email.md2
-rw-r--r--doc/topics/autodevops/quick_start_guide.md1
-rw-r--r--doc/user/admin_area/appearance.md2
-rw-r--r--doc/user/admin_area/diff_limits.md2
-rw-r--r--doc/user/admin_area/index.md14
-rw-r--r--doc/user/admin_area/merge_requests_approvals.md2
-rw-r--r--doc/user/admin_area/monitoring/health_check.md2
-rw-r--r--doc/user/admin_area/settings/account_and_limit_settings.md22
-rw-r--r--doc/user/admin_area/settings/external_authorization.md2
-rw-r--r--doc/user/admin_area/settings/floc.md2
-rw-r--r--doc/user/admin_area/settings/help_page.md2
-rw-r--r--doc/user/admin_area/settings/index.md4
-rw-r--r--doc/user/admin_area/settings/instance_template_repository.md2
-rw-r--r--doc/user/admin_area/settings/project_integration_management.md6
-rw-r--r--doc/user/admin_area/settings/push_event_activities_limit.md2
-rw-r--r--doc/user/admin_area/settings/rate_limits_on_raw_endpoints.md2
-rw-r--r--doc/user/admin_area/settings/sign_in_restrictions.md4
-rw-r--r--doc/user/admin_area/settings/sign_up_restrictions.md12
-rw-r--r--doc/user/admin_area/settings/terms.md2
-rw-r--r--doc/user/admin_area/settings/user_and_ip_rate_limits.md2
-rw-r--r--doc/user/admin_area/settings/visibility_and_access_controls.md24
-rw-r--r--doc/user/admin_area/user_cohorts.md2
-rw-r--r--doc/user/discussions/index.md8
-rw-r--r--doc/user/group/index.md2
-rw-r--r--doc/user/group/saml_sso/index.md2
-rw-r--r--doc/user/group/settings/import_export.md2
-rw-r--r--doc/user/instance/clusters/index.md2
-rw-r--r--doc/user/packages/terraform_module_registry/index.md4
-rw-r--r--doc/user/profile/account/delete_account.md2
-rw-r--r--doc/user/profile/active_sessions.md4
-rw-r--r--doc/user/profile/index.md4
-rw-r--r--doc/user/profile/notifications.md8
-rw-r--r--doc/user/profile/personal_access_tokens.md6
-rw-r--r--doc/user/project/issues/managing_issues.md2
-rw-r--r--doc/user/project/members/share_project_with_groups.md2
-rw-r--r--doc/user/project/pages/pages_access_control.md2
-rw-r--r--doc/user/project/repository/branches/default.md2
-rw-r--r--doc/user/project/repository/gpg_signed_commits/index.md6
-rw-r--r--doc/user/project/repository/repository_mirroring.md2
-rw-r--r--doc/user/project/web_ide/index.md2
-rw-r--r--lib/gitlab/pagination/offset_pagination.rb10
-rw-r--r--locale/gitlab.pot63
-rw-r--r--package.json4
-rw-r--r--spec/controllers/registrations/experience_levels_controller_spec.rb159
-rw-r--r--spec/features/commit_spec.rb2
-rw-r--r--spec/features/projects/commits/user_browses_commits_spec.rb8
-rw-r--r--spec/features/registrations/experience_level_spec.rb44
-rw-r--r--spec/frontend/diffs/components/app_spec.js2
-rw-r--r--spec/frontend/diffs/store/actions_spec.js7
-rw-r--r--spec/frontend/diffs/store/mutations_spec.js6
-rw-r--r--spec/frontend/milestones/stores/mutations_spec.js58
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/details/additional_metadata_spec.js43
-rw-r--r--spec/frontend/vue_shared/components/diff_stats_dropdown_spec.js176
-rw-r--r--spec/lib/gitlab/pagination/offset_pagination_spec.rb37
-rw-r--r--spec/models/user_spec.rb3
-rw-r--r--spec/requests/api/users_spec.rb91
-rw-r--r--spec/support/shared_examples/features/wiki/user_views_wiki_page_shared_examples.rb6
-rw-r--r--spec/views/projects/diffs/_stats.html.haml_spec.rb58
-rw-r--r--yarn.lock36
112 files changed, 1179 insertions, 722 deletions
diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue
index 9ef10c5435e..57162c46002 100644
--- a/app/assets/javascripts/diffs/components/app.vue
+++ b/app/assets/javascripts/diffs/components/app.vue
@@ -1,5 +1,5 @@
<script>
-import { GlLoadingIcon, GlPagination, GlSprintf } from '@gitlab/ui';
+import { GlLoadingIcon, GlPagination, GlSprintf, GlAlert } from '@gitlab/ui';
import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
import Mousetrap from 'mousetrap';
import { mapState, mapGetters, mapActions } from 'vuex';
@@ -77,6 +77,7 @@ export default {
GlPagination,
GlSprintf,
MrWidgetHowToMergeModal,
+ GlAlert,
},
alerts: {
ALERT_OVERFLOW_HIDDEN,
@@ -199,7 +200,6 @@ export default {
...mapState('diffs', [
'showTreeList',
'isLoading',
- 'isBatchLoading',
'diffFiles',
'diffViewType',
'commit',
@@ -226,6 +226,8 @@ export default {
'isParallelView',
'currentDiffIndex',
'isVirtualScrollingEnabled',
+ 'isBatchLoading',
+ 'isBatchLoadingError',
]),
...mapGetters('batchComments', ['draftsCount']),
...mapGetters(['isNotesFetched', 'getNoteableData']),
@@ -620,6 +622,9 @@ export default {
this.subscribedToVirtualScrollingEvents = true;
}
},
+ reloadPage() {
+ window.location.reload();
+ },
},
minTreeWidth: MIN_TREE_WIDTH,
maxTreeWidth: MAX_TREE_WIDTH,
@@ -638,17 +643,19 @@ export default {
:diff-files-count-text="numTotalFiles"
/>
- <hidden-files-warning
- v-if="visibleWarning == $options.alerts.ALERT_OVERFLOW_HIDDEN"
- :visible="numVisibleFiles"
- :total="numTotalFiles"
- :plain-diff-path="plainDiffPath"
- :email-patch-path="emailPatchPath"
- />
- <collapsed-files-warning
- v-if="visibleWarning == $options.alerts.ALERT_COLLAPSED_FILES"
- :limited="isLimitedContainer"
- />
+ <template v-if="!isBatchLoadingError">
+ <hidden-files-warning
+ v-if="visibleWarning == $options.alerts.ALERT_OVERFLOW_HIDDEN"
+ :visible="numVisibleFiles"
+ :total="numTotalFiles"
+ :plain-diff-path="plainDiffPath"
+ :email-patch-path="emailPatchPath"
+ />
+ <collapsed-files-warning
+ v-if="visibleWarning == $options.alerts.ALERT_COLLAPSED_FILES"
+ :limited="isLimitedContainer"
+ />
+ </template>
<div
:data-can-create-note="getNoteableData.current_user.can_create_note"
@@ -677,7 +684,18 @@ export default {
}"
>
<commit-widget v-if="commit" :commit="commit" :collapsible="false" />
- <div v-if="isBatchLoading" class="loading"><gl-loading-icon size="lg" /></div>
+ <gl-alert
+ v-if="isBatchLoadingError"
+ variant="danger"
+ :dismissible="false"
+ :primary-button-text="__('Reload page')"
+ @primaryAction="reloadPage"
+ >
+ {{ __("Error: Couldn't load some or all of the changes.") }}
+ </gl-alert>
+ <div v-if="isBatchLoading && !isBatchLoadingError" class="loading">
+ <gl-loading-icon size="lg" />
+ </div>
<template v-else-if="renderDiffFiles">
<dynamic-scroller
v-if="isVirtualScrollingEnabled"
@@ -753,7 +771,10 @@ export default {
</div>
<gl-loading-icon v-else-if="retrievingBatches" size="lg" />
</template>
- <no-changes v-else :changes-empty-state-illustration="changesEmptyStateIllustration" />
+ <no-changes
+ v-else-if="!isBatchLoadingError"
+ :changes-empty-state-illustration="changesEmptyStateIllustration"
+ />
</div>
</div>
<mr-widget-how-to-merge-modal
diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js
index 97126421764..5c94c6b803b 100644
--- a/app/assets/javascripts/diffs/store/actions.js
+++ b/app/assets/javascripts/diffs/store/actions.js
@@ -101,7 +101,7 @@ export const fetchDiffFilesBatch = ({ commit, state, dispatch }) => {
let totalLoaded = 0;
let scrolledVirtualScroller = false;
- commit(types.SET_BATCH_LOADING, true);
+ commit(types.SET_BATCH_LOADING_STATE, 'loading');
commit(types.SET_RETRIEVING_BATCHES, true);
eventHub.$emit(EVT_PERF_MARK_DIFF_FILES_START);
@@ -112,7 +112,7 @@ export const fetchDiffFilesBatch = ({ commit, state, dispatch }) => {
totalLoaded += diff_files.length;
commit(types.SET_DIFF_DATA_BATCH, { diff_files });
- commit(types.SET_BATCH_LOADING, false);
+ commit(types.SET_BATCH_LOADING_STATE, 'loaded');
if (window.gon?.features?.diffsVirtualScrolling && !scrolledVirtualScroller) {
const index = state.diffFiles.findIndex(
@@ -127,7 +127,7 @@ export const fetchDiffFilesBatch = ({ commit, state, dispatch }) => {
}
if (!isNoteLink && !state.currentDiffFileId) {
- commit(types.VIEW_DIFF_FILE, diff_files[0].file_hash);
+ commit(types.VIEW_DIFF_FILE, diff_files[0]?.file_hash);
}
if (isNoteLink) {
@@ -179,11 +179,14 @@ export const fetchDiffFilesBatch = ({ commit, state, dispatch }) => {
return null;
})
- .catch(() => commit(types.SET_RETRIEVING_BATCHES, false));
+ .catch(() => {
+ commit(types.SET_RETRIEVING_BATCHES, false);
+ commit(types.SET_BATCH_LOADING_STATE, 'error');
+ });
- return getBatch()
- .then(() => !window.gon?.features?.diffsVirtualScrolling && handleLocationHash())
- .catch(() => null);
+ return getBatch().then(
+ () => !window.gon?.features?.diffsVirtualScrolling && handleLocationHash(),
+ );
};
export const fetchDiffFilesMeta = ({ commit, state }) => {
diff --git a/app/assets/javascripts/diffs/store/getters.js b/app/assets/javascripts/diffs/store/getters.js
index 18bd8e5f1d8..ca85be5d829 100644
--- a/app/assets/javascripts/diffs/store/getters.js
+++ b/app/assets/javascripts/diffs/store/getters.js
@@ -191,3 +191,6 @@ export const isVirtualScrollingEnabled = (state) => {
getParameterValues('virtual_scrolling')[0] === 'true')
);
};
+
+export const isBatchLoading = (state) => state.batchLoadingState === 'loading';
+export const isBatchLoadingError = (state) => state.batchLoadingState === 'error';
diff --git a/app/assets/javascripts/diffs/store/modules/diff_state.js b/app/assets/javascripts/diffs/store/modules/diff_state.js
index 6e30956a767..a5b1a577a78 100644
--- a/app/assets/javascripts/diffs/store/modules/diff_state.js
+++ b/app/assets/javascripts/diffs/store/modules/diff_state.js
@@ -10,7 +10,7 @@ const defaultViewType = INLINE_DIFF_VIEW_TYPE;
export default () => ({
isLoading: true,
isTreeLoaded: false,
- isBatchLoading: false,
+ batchLoadingState: null,
retrievingBatches: false,
addedLines: null,
removedLines: null,
diff --git a/app/assets/javascripts/diffs/store/mutation_types.js b/app/assets/javascripts/diffs/store/mutation_types.js
index 2c370221f40..60836f747f5 100644
--- a/app/assets/javascripts/diffs/store/mutation_types.js
+++ b/app/assets/javascripts/diffs/store/mutation_types.js
@@ -1,6 +1,6 @@
export const SET_BASE_CONFIG = 'SET_BASE_CONFIG';
export const SET_LOADING = 'SET_LOADING';
-export const SET_BATCH_LOADING = 'SET_BATCH_LOADING';
+export const SET_BATCH_LOADING_STATE = 'SET_BATCH_LOADING_STATE';
export const SET_RETRIEVING_BATCHES = 'SET_RETRIEVING_BATCHES';
export const SET_DIFF_METADATA = 'SET_DIFF_METADATA';
diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js
index 1aa83453bf7..6bc927b9d1f 100644
--- a/app/assets/javascripts/diffs/store/mutations.js
+++ b/app/assets/javascripts/diffs/store/mutations.js
@@ -60,8 +60,8 @@ export default {
Object.assign(state, { isLoading });
},
- [types.SET_BATCH_LOADING](state, isBatchLoading) {
- Object.assign(state, { isBatchLoading });
+ [types.SET_BATCH_LOADING_STATE](state, batchLoadingState) {
+ Object.assign(state, { batchLoadingState });
},
[types.SET_RETRIEVING_BATCHES](state, retrievingBatches) {
diff --git a/app/assets/javascripts/init_changes_dropdown.js b/app/assets/javascripts/init_changes_dropdown.js
deleted file mode 100644
index b42264c870b..00000000000
--- a/app/assets/javascripts/init_changes_dropdown.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import $ from 'jquery';
-import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
-import { stickyMonitor } from './lib/utils/sticky';
-
-export default (stickyTop) => {
- stickyMonitor(document.querySelector('.js-diff-files-changed'), stickyTop);
-
- initDeprecatedJQueryDropdown($('.js-diff-stats-dropdown'), {
- filterable: true,
- remoteFilter: false,
- });
-};
diff --git a/app/assets/javascripts/init_diff_stats_dropdown.js b/app/assets/javascripts/init_diff_stats_dropdown.js
new file mode 100644
index 00000000000..27df761a103
--- /dev/null
+++ b/app/assets/javascripts/init_diff_stats_dropdown.js
@@ -0,0 +1,30 @@
+import Vue from 'vue';
+import DiffStatsDropdown from '~/vue_shared/components/diff_stats_dropdown.vue';
+import { stickyMonitor } from './lib/utils/sticky';
+
+export const initDiffStatsDropdown = (stickyTop) => {
+ if (stickyTop) {
+ stickyMonitor(document.querySelector('.js-diff-files-changed'), stickyTop);
+ }
+
+ const el = document.querySelector('.js-diff-stats-dropdown');
+
+ if (!el) {
+ return false;
+ }
+
+ const { changed, added, deleted, files } = el.dataset;
+
+ return new Vue({
+ el,
+ render: (createElement) =>
+ createElement(DiffStatsDropdown, {
+ props: {
+ changed: parseInt(changed, 10),
+ added: parseInt(added, 10),
+ deleted: parseInt(deleted, 10),
+ files: JSON.parse(files),
+ },
+ }),
+ });
+};
diff --git a/app/assets/javascripts/merge_request_tabs.js b/app/assets/javascripts/merge_request_tabs.js
index 540959b3a46..a40caea1223 100644
--- a/app/assets/javascripts/merge_request_tabs.js
+++ b/app/assets/javascripts/merge_request_tabs.js
@@ -7,7 +7,7 @@ import createEventHub from '~/helpers/event_hub_factory';
import BlobForkSuggestion from './blob/blob_fork_suggestion';
import Diff from './diff';
import createFlash from './flash';
-import initChangesDropdown from './init_changes_dropdown';
+import { initDiffStatsDropdown } from './init_diff_stats_dropdown';
import axios from './lib/utils/axios_utils';
import {
parseUrlPathname,
@@ -433,8 +433,7 @@ export default class MergeRequestTabs {
.then(({ data }) => {
const $container = $('#diffs');
$container.html(data.html);
-
- initChangesDropdown(this.stickyTop);
+ initDiffStatsDropdown(this.stickyTop);
localTimeAgo(document.querySelectorAll('#diffs .js-timeago'));
syntaxHighlight($('#diffs .js-syntax-highlight'));
diff --git a/app/assets/javascripts/milestones/stores/mutations.js b/app/assets/javascripts/milestones/stores/mutations.js
index 3a7babf6fa0..1f88c0a1ea6 100644
--- a/app/assets/javascripts/milestones/stores/mutations.js
+++ b/app/assets/javascripts/milestones/stores/mutations.js
@@ -38,7 +38,7 @@ export default {
[types.RECEIVE_PROJECT_MILESTONES_SUCCESS](state, response) {
state.matches.projectMilestones = {
list: response.data.map(({ title }) => ({ title })),
- totalCount: parseInt(response.headers['x-total'], 10),
+ totalCount: parseInt(response.headers['x-total'], 10) || response.data.length,
error: null,
};
},
@@ -52,7 +52,7 @@ export default {
[types.RECEIVE_GROUP_MILESTONES_SUCCESS](state, response) {
state.matches.groupMilestones = {
list: response.data.map(({ title }) => ({ title })),
- totalCount: parseInt(response.headers['x-total'], 10),
+ totalCount: parseInt(response.headers['x-total'], 10) || response.data.length,
error: null,
};
},
diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/additional_metadata.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/additional_metadata.vue
index 4d6a1d5462b..059f038b6e7 100644
--- a/app/assets/javascripts/packages_and_registries/package_registry/components/details/additional_metadata.vue
+++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/additional_metadata.vue
@@ -5,7 +5,9 @@ import {
PACKAGE_TYPE_NUGET,
PACKAGE_TYPE_CONAN,
PACKAGE_TYPE_MAVEN,
+ PACKAGE_TYPE_COMPOSER,
} from '~/packages_and_registries/package_registry/constants';
+import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import DetailsRow from '~/vue_shared/components/registry/details_row.vue';
export default {
@@ -15,11 +17,17 @@ export default {
recipeText: s__('PackageRegistry|Recipe: %{recipe}'),
appGroup: s__('PackageRegistry|App group: %{group}'),
appName: s__('PackageRegistry|App name: %{name}'),
+ targetShaCopyButton: s__('PackageRegistry|Copy target SHA'),
+ targetSha: s__('PackageRegistry|Target SHA: %{sha}'),
+ composerJson: s__(
+ 'PackageRegistry|Composer.json with license: %{license} and version: %{version}',
+ ),
},
components: {
DetailsRow,
GlLink,
GlSprintf,
+ ClipboardButton,
},
props: {
packageEntity: {
@@ -30,9 +38,12 @@ export default {
computed: {
showMetadata() {
return (
- [PACKAGE_TYPE_NUGET, PACKAGE_TYPE_CONAN, PACKAGE_TYPE_MAVEN].includes(
- this.packageEntity.packageType,
- ) && this.packageEntity.metadata
+ [
+ PACKAGE_TYPE_NUGET,
+ PACKAGE_TYPE_CONAN,
+ PACKAGE_TYPE_MAVEN,
+ PACKAGE_TYPE_COMPOSER,
+ ].includes(this.packageEntity.packageType) && this.packageEntity.metadata
);
},
showNugetMetadata() {
@@ -44,6 +55,9 @@ export default {
showMavenMetadata() {
return this.packageEntity.packageType === PACKAGE_TYPE_MAVEN;
},
+ showComposerMetadata() {
+ return this.packageEntity.packageType === PACKAGE_TYPE_COMPOSER;
+ },
},
};
</script>
@@ -101,6 +115,32 @@ export default {
</gl-sprintf>
</details-row>
</template>
+
+ <template v-else-if="showComposerMetadata">
+ <details-row icon="information-o" padding="gl-p-4" dashed data-testid="composer-target-sha">
+ <gl-sprintf :message="$options.i18n.targetSha">
+ <template #sha>
+ <strong>{{ packageEntity.metadata.targetSha }}</strong>
+ <clipboard-button
+ :title="$options.i18n.targetShaCopyButton"
+ :text="packageEntity.metadata.targetSha"
+ category="tertiary"
+ css-class="gl-p-0!"
+ />
+ </template>
+ </gl-sprintf>
+ </details-row>
+ <details-row icon="information-o" padding="gl-p-4" data-testid="composer-json">
+ <gl-sprintf :message="$options.i18n.composerJson">
+ <template #license>
+ <strong>{{ packageEntity.metadata.composerJson.license }}</strong>
+ </template>
+ <template #version>
+ <strong>{{ packageEntity.metadata.composerJson.version }}</strong>
+ </template>
+ </gl-sprintf>
+ </details-row>
+ </template>
</div>
</div>
</template>
diff --git a/app/assets/javascripts/pages/projects/commit/show/index.js b/app/assets/javascripts/pages/projects/commit/show/index.js
index a008e7172aa..c6a76df7bde 100644
--- a/app/assets/javascripts/pages/projects/commit/show/index.js
+++ b/app/assets/javascripts/pages/projects/commit/show/index.js
@@ -4,8 +4,8 @@ import loadAwardsHandler from '~/awards_handler';
import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import Diff from '~/diff';
import createFlash from '~/flash';
-import initChangesDropdown from '~/init_changes_dropdown';
import initDeprecatedNotes from '~/init_deprecated_notes';
+import { initDiffStatsDropdown } from '~/init_diff_stats_dropdown';
import axios from '~/lib/utils/axios_utils';
import { handleLocationHash } from '~/lib/utils/common_utils';
import { __ } from '~/locale';
@@ -17,7 +17,7 @@ import '~/sourcegraph/load';
const hasPerfBar = document.querySelector('.with-performance-bar');
const performanceHeight = hasPerfBar ? 35 : 0;
-initChangesDropdown(document.querySelector('.navbar-gitlab').offsetHeight + performanceHeight);
+initDiffStatsDropdown(document.querySelector('.navbar-gitlab').offsetHeight + performanceHeight);
new ZenMode();
new ShortcutsNavigation();
diff --git a/app/assets/javascripts/pages/projects/compare/show/index.js b/app/assets/javascripts/pages/projects/compare/show/index.js
index 5edaa7f7e51..b74f7d1cf57 100644
--- a/app/assets/javascripts/pages/projects/compare/show/index.js
+++ b/app/assets/javascripts/pages/projects/compare/show/index.js
@@ -1,11 +1,11 @@
import Diff from '~/diff';
import GpgBadges from '~/gpg_badges';
-import initChangesDropdown from '~/init_changes_dropdown';
+import { initDiffStatsDropdown } from '~/init_diff_stats_dropdown';
import initCompareSelector from '~/projects/compare';
initCompareSelector();
new Diff(); // eslint-disable-line no-new
const paddingTop = 16;
-initChangesDropdown(document.querySelector('.navbar-gitlab').offsetHeight - paddingTop);
+initDiffStatsDropdown(document.querySelector('.navbar-gitlab').offsetHeight - paddingTop);
GpgBadges.fetch();
diff --git a/app/assets/javascripts/pages/projects/wikis/index.js b/app/assets/javascripts/pages/projects/wikis/index.js
index dead61cf358..2c1f9e634ab 100644
--- a/app/assets/javascripts/pages/projects/wikis/index.js
+++ b/app/assets/javascripts/pages/projects/wikis/index.js
@@ -1,3 +1,5 @@
+import { initDiffStatsDropdown } from '~/init_diff_stats_dropdown';
import initWikis from '~/pages/shared/wikis';
initWikis();
+initDiffStatsDropdown();
diff --git a/app/assets/javascripts/vue_shared/components/diff_stats_dropdown.vue b/app/assets/javascripts/vue_shared/components/diff_stats_dropdown.vue
new file mode 100644
index 00000000000..56e6399a1b7
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/diff_stats_dropdown.vue
@@ -0,0 +1,159 @@
+<script>
+import {
+ GlDropdown,
+ GlDropdownItem,
+ GlDropdownText,
+ GlSearchBoxByType,
+ GlSprintf,
+} from '@gitlab/ui';
+import fuzzaldrinPlus from 'fuzzaldrin-plus';
+import { __, n__, s__, sprintf } from '~/locale';
+
+export const i18n = {
+ messageAdditionsDeletions: s__('Diffs|with %{additions} and %{deletions}'),
+ noFilesFound: __('No files found.'),
+ noFileNameAvailable: s__('Diffs|No file name available'),
+ searchFiles: __('Search files'),
+};
+
+export default {
+ i18n,
+ components: {
+ GlDropdown,
+ GlDropdownItem,
+ GlDropdownText,
+ GlSearchBoxByType,
+ GlSprintf,
+ },
+ props: {
+ changed: {
+ type: Number,
+ required: true,
+ },
+ added: {
+ type: Number,
+ required: true,
+ },
+ deleted: {
+ type: Number,
+ required: true,
+ },
+ files: {
+ type: Array,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ search: '',
+ };
+ },
+ computed: {
+ filteredFiles() {
+ return this.search.length > 0
+ ? fuzzaldrinPlus.filter(this.files, this.search, { key: 'name' })
+ : this.files;
+ },
+ messageChanged() {
+ return sprintf(
+ n__(
+ 'Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}',
+ 'Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}',
+ this.changed,
+ ),
+ { count: this.changed },
+ );
+ },
+
+ additionsText() {
+ return n__('Diffs|%d addition', 'Diffs|%d additions', this.added);
+ },
+ deletionsText() {
+ return n__('Diffs|%d deletion', 'Diffs|%d deletions', this.deleted);
+ },
+ },
+ methods: {
+ jumpToFile(fileHash) {
+ window.location.hash = fileHash;
+ },
+ focusInput() {
+ this.$refs.search.focusInput();
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <gl-sprintf :message="messageChanged">
+ <template #dropdown="{ content: dropdownText }">
+ <gl-dropdown
+ category="tertiary"
+ variant="confirm"
+ :text="dropdownText"
+ data-testid="diff-stats-dropdown"
+ class="gl-vertical-align-baseline"
+ toggle-class="gl-px-0! gl-font-weight-bold!"
+ menu-class="gl-w-auto!"
+ no-flip
+ @shown="focusInput"
+ >
+ <template #header>
+ <gl-search-box-by-type
+ ref="search"
+ v-model.trim="search"
+ :placeholder="$options.i18n.searchFiles"
+ />
+ </template>
+ <gl-dropdown-item
+ v-for="file in filteredFiles"
+ :key="file.href"
+ :icon-name="file.icon"
+ :icon-color="file.iconColor"
+ @click="jumpToFile(file.href)"
+ >
+ <div class="gl-display-flex">
+ <span v-if="file.name" class="gl-font-weight-bold gl-mr-3 gl-text-truncate">{{
+ file.name
+ }}</span>
+ <span v-else class="gl-mr-3 gl-font-weight-bold gl-font-style-italic gl-gray-400">{{
+ $options.i18n.noFileNameAvailable
+ }}</span>
+ <span class="gl-ml-auto gl-white-space-nowrap">
+ <span class="gl-text-green-600">+{{ file.added }}</span>
+ <span class="gl-text-red-500">-{{ file.removed }}</span>
+ </span>
+ </div>
+ <div class="gl-text-gray-700 gl-overflow-hidden gl-text-overflow-ellipsis">
+ {{ file.path }}
+ </div>
+ </gl-dropdown-item>
+ <gl-dropdown-text v-if="!filteredFiles.length">
+ {{ $options.i18n.noFilesFound }}
+ </gl-dropdown-text>
+ </gl-dropdown>
+ </template>
+ </gl-sprintf>
+ <span
+ class="diff-stats-additions-deletions-expanded"
+ data-testid="diff-stats-additions-deletions-expanded"
+ >
+ <gl-sprintf :message="$options.i18n.messageAdditionsDeletions">
+ <template #additions>
+ <span class="gl-text-green-600 gl-font-weight-bold">{{ additionsText }}</span>
+ </template>
+ <template #deletions>
+ <span class="gl-text-red-500 gl-font-weight-bold">{{ deletionsText }}</span>
+ </template>
+ </gl-sprintf>
+ </span>
+
+ <div
+ class="diff-stats-additions-deletions-collapsed gl-float-right gl-display-none"
+ data-testid="diff-stats-additions-deletions-collapsed"
+ >
+ <span class="gl-text-green-600 gl-font-weight-bold">+{{ added }}</span>
+ <span class="gl-text-red-500 gl-font-weight-bold">-{{ deleted }}</span>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/stylesheets/framework/diffs.scss b/app/assets/stylesheets/framework/diffs.scss
index 9adb8532a93..568182ad796 100644
--- a/app/assets/stylesheets/framework/diffs.scss
+++ b/app/assets/stylesheets/framework/diffs.scss
@@ -682,26 +682,6 @@ table.code {
max-height: 50vh;
}
-.diff-stats-summary-toggler {
- padding: 0;
- background-color: transparent;
- border: 0;
- color: $blue-600;
- font-weight: $gl-font-weight-bold;
-
- &:hover,
- &:focus {
- outline: none;
- color: $blue-800;
- }
-
- .caret-icon {
- position: relative;
- top: 2px;
- left: -1px;
- }
-}
-
// Mobile
@media (max-width: 480px) {
.diff-title {
@@ -853,21 +833,14 @@ table.code {
.diff-files-changed {
.inline-parallel-buttons {
- position: relative;
+ @include gl-relative;
z-index: 1;
}
- .commit-stat-summary {
- @include media-breakpoint-up(sm) {
- background-color: $white;
- }
- }
-
@include media-breakpoint-up(sm) {
- position: -webkit-sticky;
- position: sticky;
+ @include gl-sticky;
top: $header-height + $mr-tabs-height;
- background-color: $white;
+ @include gl-bg-white;
z-index: 200;
.with-performance-bar & {
@@ -875,14 +848,13 @@ table.code {
}
&.is-stuck {
- padding-top: 0;
- padding-bottom: 0;
+ @include gl-py-0;
border-top: 1px solid $white-dark;
border-bottom: 1px solid $white-dark;
.diff-stats-additions-deletions-expanded,
.inline-parallel-buttons {
- display: none !important;
+ @include gl-display-none;
}
}
}
@@ -890,12 +862,13 @@ table.code {
@include media-breakpoint-up(lg) {
&.is-stuck {
.diff-stats-additions-deletions-collapsed {
- display: block !important;
+ @include gl-display-block;
}
}
}
}
+
.diff-file-changes {
max-width: 560px;
width: 100%;
diff --git a/app/assets/stylesheets/page_bundles/signup.scss b/app/assets/stylesheets/page_bundles/signup.scss
index d6c3a3ff5da..57e5d2411d1 100644
--- a/app/assets/stylesheets/page_bundles/signup.scss
+++ b/app/assets/stylesheets/page_bundles/signup.scss
@@ -39,36 +39,6 @@
}
}
-.signup-page[data-page^='registrations:experience_levels'] {
- $card-shadow-color: rgba(var(--black, $black), 0.2);
-
- .page-wrap {
- background-color: var(--white, $white);
- }
-
- .card-deck {
- max-width: 828px;
- }
-
- .card {
- transition: box-shadow 0.3s ease-in-out;
- }
-
- .card:hover {
- box-shadow: 0 $gl-spacing-scale-3 $gl-spacing-scale-5 $card-shadow-color;
- }
-
- @media (min-width: $breakpoint-sm) {
- .card-deck .card {
- margin: 0 $gl-spacing-scale-3;
- }
- }
-
- .stretched-link:hover {
- text-decoration: none;
- }
-}
-
.edit-profile {
max-width: 460px;
}
diff --git a/app/controllers/registrations/experience_levels_controller.rb b/app/controllers/registrations/experience_levels_controller.rb
deleted file mode 100644
index 3c94bce126c..00000000000
--- a/app/controllers/registrations/experience_levels_controller.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-# frozen_string_literal: true
-
-module Registrations
- class ExperienceLevelsController < ApplicationController
- layout 'minimal'
-
- before_action :ensure_namespace_path_param
-
- feature_category :onboarding
-
- def update
- current_user.experience_level = params[:experience_level]
-
- if current_user.save
- hide_advanced_issues
-
- if learn_gitlab.available?
- redirect_to namespace_project_board_path(params[:namespace_path], learn_gitlab.project, learn_gitlab.board)
- else
- redirect_to group_path(params[:namespace_path])
- end
- else
- render :show
- end
- end
-
- private
-
- def ensure_namespace_path_param
- redirect_to root_path unless params[:namespace_path].present?
- end
-
- def hide_advanced_issues
- return unless current_user.user_preference.novice?
- return unless learn_gitlab.available?
-
- Boards::UpdateService.new(learn_gitlab.project, current_user, label_ids: [learn_gitlab.label.id]).execute(learn_gitlab.board)
- end
-
- def learn_gitlab
- @learn_gitlab ||= LearnGitlab::Project.new(current_user)
- end
- end
-end
diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb
index 40d7eab584c..ca5fe38576e 100644
--- a/app/helpers/diff_helper.rb
+++ b/app/helpers/diff_helper.rb
@@ -183,9 +183,9 @@ module DiffHelper
def diff_file_changed_icon_color(diff_file)
if diff_file.deleted_file?
- "cred"
+ "danger"
elsif diff_file.new_file?
- "cgreen"
+ "success"
end
end
@@ -248,6 +248,23 @@ module DiffHelper
toggle_whitespace_link(url, options)
end
+ def diff_files_data(diff_files)
+ diffs_map = diff_files.map do |f|
+ {
+ href: "##{hexdigest(f.file_path)}",
+ title: f.new_path,
+ name: f.file_path,
+ path: diff_file_path_text(f),
+ icon: diff_file_changed_icon(f),
+ iconColor: "#{diff_file_changed_icon_color(f)}",
+ added: f.added_lines,
+ removed: f.removed_lines
+ }
+ end
+
+ diffs_map.to_json
+ end
+
def hide_whitespace?
params[:w] == '1'
end
diff --git a/app/models/user.rb b/app/models/user.rb
index ddaa540a92f..14fe9d452fd 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -307,7 +307,6 @@ class User < ApplicationRecord
:gitpod_enabled, :gitpod_enabled=,
:setup_for_company, :setup_for_company=,
:render_whitespace_in_code, :render_whitespace_in_code=,
- :experience_level, :experience_level=,
:markdown_surround_selection, :markdown_surround_selection=,
to: :user_preference
diff --git a/app/models/user_preference.rb b/app/models/user_preference.rb
index 2735e169b5f..337ae7125f3 100644
--- a/app/models/user_preference.rb
+++ b/app/models/user_preference.rb
@@ -20,7 +20,7 @@ class UserPreference < ApplicationRecord
less_than_or_equal_to: Gitlab::TabWidth::MAX
}
- enum experience_level: { novice: 0, experienced: 1 }
+ ignore_columns :experience_level, remove_with: '14.10', remove_after: '2021-03-22'
default_value_for :tab_width, value: Gitlab::TabWidth::DEFAULT, allows_nil: false
default_value_for :timezone, value: Time.zone.tzinfo.name, allows_nil: false
diff --git a/app/views/projects/diffs/_stats.html.haml b/app/views/projects/diffs/_stats.html.haml
index 8edaacf7552..fe9658a440a 100644
--- a/app/views/projects/diffs/_stats.html.haml
+++ b/app/views/projects/diffs/_stats.html.haml
@@ -1,41 +1 @@
-- sum_added_lines = diff_files.sum(&:added_lines)
-- sum_removed_lines = diff_files.sum(&:removed_lines)
-.commit-stat-summary.dropdown
- Showing
- %button.diff-stats-summary-toggler.js-diff-stats-dropdown{ type: "button", data: { toggle: "dropdown", display: "static" } }<
- = pluralize(diff_files.size, "changed file")
- = sprite_icon("chevron-down", css_class: "gl-ml-2")
- %span.diff-stats-additions-deletions-expanded#diff-stats
- with
- %strong.cgreen= pluralize(sum_added_lines, 'addition')
- and
- %strong.cred= pluralize(sum_removed_lines, 'deletion')
- .diff-stats-additions-deletions-collapsed.float-right.d-none{ "aria-hidden": "true", "aria-describedby": "diff-stats" }
- %strong.cgreen<
- +#{sum_added_lines}
- %strong.cred<
- \-#{sum_removed_lines}
- .dropdown-menu.diff-file-changes
- = dropdown_filter("Search files")
- .dropdown-content
- %ul
- - diff_files.each do |diff_file|
- %li
- %a.diff-changed-file{ href: "##{hexdigest(diff_file.file_path)}", title: diff_file.new_path }
- = sprite_icon(diff_file_changed_icon(diff_file), css_class: "#{diff_file_changed_icon_color(diff_file)} diff-file-changed-icon gl-mr-3")
- %span.diff-changed-file-content.gl-mr-3
- - if diff_file.file_path
- %strong.diff-changed-file-name
- = diff_file.file_path
- - else
- %strong.diff-changed-blank-file-name
- = s_('Diffs|No file name available')
- %span.diff-changed-file-path.gl-mt-2= diff_file_path_text(diff_file)
- %span.diff-changed-stats
- %span.cgreen<
- +#{diff_file.added_lines}
- %span.cred<
- \-#{diff_file.removed_lines}
- %li.dropdown-menu-empty-item.hidden
- %a
- = _("No files found.")
+.js-diff-stats-dropdown{ data: { changed: diff_files.size, added: diff_files.sum(&:added_lines), deleted: diff_files.sum(&:removed_lines), files: diff_files_data(diff_files) } }
diff --git a/app/views/registrations/experience_levels/show.html.haml b/app/views/registrations/experience_levels/show.html.haml
deleted file mode 100644
index 16e59757147..00000000000
--- a/app/views/registrations/experience_levels/show.html.haml
+++ /dev/null
@@ -1,29 +0,0 @@
-- page_title _('What’s your experience level?')
-- @hide_flash = true
-
-.gl-display-flex.gl-flex-direction-column.gl-align-items-center
- = image_tag 'learn-gitlab-avatar.jpg', width: '90'
-
- %h2.gl-text-center.gl-mt-3.gl-mb-3= _('Hello there')
- %p.gl-text-center.gl-font-lg.gl-mb-6= _('Welcome to the guided GitLab tour')
-
- %h3.gl-text-center.gl-font-lg.gl-mt-6.gl-mb-0= _('What describes you best?')
-
- .card-deck.gl-mt-6
- .card
- .card-body.gl-display-flex.gl-py-8.gl-pr-5.gl-pl-7
- .gl-align-self-center.gl-pr-6
- = image_tag 'novice.svg', width: '78', height: '78', alt: ''
- %div
- %p.gl-font-lg.gl-font-weight-bold.gl-mb-2= _('Novice')
- %p= _('I’m not familiar with the basics of DevOps.')
- = link_to _('Show me the basics'), users_sign_up_experience_level_path(experience_level: :novice, namespace_path: params[:namespace_path]), method: :patch, class: 'stretched-link'
-
- .card
- .card-body.gl-display-flex.gl-py-8.gl-pr-5.gl-pl-7
- .gl-align-self-center.gl-pr-6
- = image_tag 'experienced.svg', width: '78', height: '78', alt: ''
- %div
- %p.gl-font-lg.gl-font-weight-bold.gl-mb-2= _('Experienced')
- %p= _('I’m familiar with the basics of DevOps.')
- = link_to _('Show me advanced features'), users_sign_up_experience_level_path(experience_level: :experienced, namespace_path: params[:namespace_path]), method: :patch, class: 'stretched-link'
diff --git a/config/feature_flags/ops/lower_relation_max_count_limit.yml b/config/feature_flags/ops/lower_relation_max_count_limit.yml
new file mode 100644
index 00000000000..7a532c0948a
--- /dev/null
+++ b/config/feature_flags/ops/lower_relation_max_count_limit.yml
@@ -0,0 +1,8 @@
+---
+name: lower_relation_max_count_limit
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/69620
+rollout_issue_url:
+milestone: '14.3'
+type: ops
+group: group::verify
+default_enabled: false
diff --git a/config/initializers/kaminari_active_record_relation_methods_with_limit.rb b/config/initializers/kaminari_active_record_relation_methods_with_limit.rb
index 982cb69e532..9a5a95403ad 100644
--- a/config/initializers/kaminari_active_record_relation_methods_with_limit.rb
+++ b/config/initializers/kaminari_active_record_relation_methods_with_limit.rb
@@ -4,6 +4,7 @@ module Kaminari
# Active Record specific page scope methods implementations
module ActiveRecordRelationMethodsWithLimit
MAX_COUNT_LIMIT = 10_000
+ MAX_COUNT_NEW_LOWER_LIMIT = 1_000
# This is a modified version of
# https://github.com/kaminari/kaminari/blob/c5186f5d9b7f23299d115408e62047447fd3189d/kaminari-activerecord/lib/kaminari/activerecord/active_record_relation_methods.rb#L17-L41
@@ -21,7 +22,8 @@ module Kaminari
return @total_count = (current_page - 1) * limit_value + @records.length if @records.any? && (@records.length < limit_value)
end
- limit = options.fetch(:limit, MAX_COUNT_LIMIT).to_i
+ max_limit = Feature.enabled?(:lower_relation_max_count_limit, type: :ops) ? MAX_COUNT_NEW_LOWER_LIMIT : MAX_COUNT_LIMIT
+ limit = options.fetch(:limit, max_limit).to_i
# #count overrides the #select which could include generated columns referenced in #order, so skip #order here, where it's irrelevant to the result anyway
c = except(:offset, :limit, :order)
# Remove includes only if they are irrelevant
diff --git a/config/routes.rb b/config/routes.rb
index c5f91ee4020..39a5007effa 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -63,8 +63,6 @@ Rails.application.routes.draw do
end
end
- resource :experience_level, only: [:show, :update]
-
Gitlab.ee do
resources :groups, only: [:new, :create]
resources :projects, only: [:new, :create]
diff --git a/doc/administration/auth/atlassian.md b/doc/administration/auth/atlassian.md
index 868482148e5..b58bbfa8eac 100644
--- a/doc/administration/auth/atlassian.md
+++ b/doc/administration/auth/atlassian.md
@@ -16,7 +16,7 @@ To enable the Atlassian OmniAuth provider for passwordless authentication you mu
1. Click **Create a new app**.
1. Choose an App Name, such as 'GitLab', and click **Create**.
1. Note the `Client ID` and `Secret` for the [GitLab configuration](#gitlab-configuration) steps.
-1. In the left sidebar under **APIS AND FEATURES**, click **OAuth 2.0 (3LO)**.
+1. On the left sidebar under **APIS AND FEATURES**, click **OAuth 2.0 (3LO)**.
1. Enter the GitLab callback URL using the format `https://gitlab.example.com/users/auth/atlassian_oauth2/callback` and click **Save changes**.
1. Click **+ Add** in the left sidebar under **APIS AND FEATURES**.
1. Click **Add** for **Jira platform REST API** and then **Configure**.
diff --git a/doc/administration/clusters/kas.md b/doc/administration/clusters/kas.md
index 8e5c162001e..98ee3ae3f98 100644
--- a/doc/administration/clusters/kas.md
+++ b/doc/administration/clusters/kas.md
@@ -129,3 +129,25 @@ or the path to `config.yaml` inside the project is not valid.
To fix this, ensure that the paths to the configuration repository and to the `config.yaml` file
are correct.
+
+### KAS logs - dial tcp <GITLAB_INTERNAL_IP>:443: connect: connection refused
+
+If you are running a self-managed GitLab instance and:
+
+- The instance isn't running behind an SSL-terminating proxy.
+- The instance doesn't have HTTPS configured on the GitLab instance itself.
+- The instance's hostname resolves locally to its internal IP address.
+
+You may see the following error when the KAS tries to connect to the GitLab API:
+
+```json
+{"level":"error","time":"2021-08-16T14:56:47.289Z","msg":"GetAgentInfo()","correlation_id":"01FD7QE35RXXXX8R47WZFBAXTN","grpc_service":"gitlab.agent.reverse_tunnel.rpc.ReverseTunnel","grpc_method":"Connect","error":"Get \"https://gitlab.example.com/api/v4/internal/kubernetes/agent_info\": dial tcp 172.17.0.4:443: connect: connection refused"}
+```
+
+To fix this for [Omnibus](https://docs.gitlab.com/omnibus/) package installations,
+set the following parameter in `/etc/gitlab/gitlab.rb`
+(replacing `gitlab.example.com` with your GitLab instance's hostname):
+
+```ruby
+gitlab_kas['gitlab_address'] = 'http://gitlab.example.com'
+```
diff --git a/doc/administration/integration/mailgun.md b/doc/administration/integration/mailgun.md
index 6486cc9de04..5a56aed4427 100644
--- a/doc/administration/integration/mailgun.md
+++ b/doc/administration/integration/mailgun.md
@@ -33,7 +33,7 @@ you're ready to enable the Mailgun integration:
1. Sign in to GitLab as an [Administrator](../../user/permissions.md) user.
1. On the top bar, select **Menu >** **{admin}** **Admin**.
-1. In the left sidebar, go to **Settings > General** and expand the **Mailgun** section.
+1. On the left sidebar, go to **Settings > General** and expand the **Mailgun** section.
1. Select the **Enable Mailgun** check box.
1. Enter the Mailgun HTTP webhook signing key as described in
[the Mailgun documentation](https://documentation.mailgun.com/en/latest/user_manual.html#webhooks) and
diff --git a/doc/administration/integration/plantuml.md b/doc/administration/integration/plantuml.md
index 0d321ccd35e..94fef89d966 100644
--- a/doc/administration/integration/plantuml.md
+++ b/doc/administration/integration/plantuml.md
@@ -207,7 +207,7 @@ After configuring your local PlantUML server, you're ready to enable the PlantUM
1. Sign in to GitLab as an [Administrator](../../user/permissions.md) user.
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, go to **Settings > General** and expand the **PlantUML** section.
+1. On the left sidebar, go to **Settings > General** and expand the **PlantUML** section.
1. Select the **Enable PlantUML** checkbox.
1. Set the PlantUML instance as `https://gitlab.example.com/-/plantuml/`,
and click **Save changes**.
diff --git a/doc/administration/operations/puma.md b/doc/administration/operations/puma.md
index e8477eaf686..faffb727a34 100644
--- a/doc/administration/operations/puma.md
+++ b/doc/administration/operations/puma.md
@@ -36,6 +36,14 @@ For more details about the Puma configuration, see the
## Puma Worker Killer
+Puma forks worker processes as part of a strategy to reduce memory use.
+
+Each time a worker is created, it shares memory with the primary process and
+only uses additional memory when it makes changes or additions to its memory pages.
+
+Memory use by workers therefore increases over time, and Puma Worker Killer is the
+mechanism that recovers this memory.
+
By default:
- The [Puma Worker Killer](https://github.com/schneems/puma_worker_killer) restarts a worker if it
@@ -56,6 +64,47 @@ To change the memory limit setting:
sudo gitlab-ctl reconfigure
```
+There are costs associated with killing and replacing workers including
+reduced capacity to run GitLab, and CPU that is consumed
+restarting the workers. `per_worker_max_memory_mb` should be set to a
+higher value if the worker killer is replacing workers too often.
+
+Worker count is calculated based on CPU cores, so a small GitLab deployment
+wih 4-8 workers may experience performance issues if workers are being restarted
+frequently, once or more per minute. This is too often.
+
+A higher value of `1200` or more would be beneficial if the server has free memory.
+
+The worker killer checks every 20 seconds, and can be monitored using
+[the Puma log](../logs.md#puma_stdoutlog) `/var/log/gitlab/puma/puma_stdout.log`.
+For example, for GitLab 13.5:
+
+```plaintext
+PumaWorkerKiller: Out of memory. 4 workers consuming total: 4871.23828125 MB
+out of max: 4798.08 MB. Sending TERM to pid 26668 consuming 1001.00390625 MB.
+```
+
+From this output:
+
+- The formula that calculates the maximum memory value results in workers
+ being killed before they reach the `per_worker_max_memory_mb` value.
+- The default values for the formula before GitLab 13.5 were 550MB for the primary
+ and `per_worker_max_memory_mb` specified 850MB for each worker.
+- As of GitLab 13.5 the values are primary: 800MB, worker: 1024MB.
+- The threshold for workers to be killed is set at 98% of the limit:
+
+ ```plaintext
+ 0.98 * ( 800 + ( worker_processes * 1024MB ) )
+ ```
+
+- In the log output above, `0.98 * ( 800 + ( 4 * 1024 ) )` returns the
+ `max: 4798.08 MB` value.
+
+Increasing the maximum to `1200`, for example, would set a `max: 5488 MB` value.
+
+Workers use additional memory on top of the shared memory, how much
+depends on a site's use of GitLab.
+
## Worker timeout
A [timeout of 60 seconds](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/initializers/rack_timeout.rb)
@@ -95,7 +144,6 @@ considered as a fair tradeoff in a memory-constraint environment.
When running Puma in Single mode, some features are not supported:
-- Phased restart do not work: [issue](https://gitlab.com/gitlab-org/gitlab/-/issues/300665)
- [Phased restart](https://gitlab.com/gitlab-org/gitlab/-/issues/300665)
- [Puma Worker Killer](https://gitlab.com/gitlab-org/gitlab/-/issues/300664)
diff --git a/doc/administration/static_objects_external_storage.md b/doc/administration/static_objects_external_storage.md
index 5b55f73b179..21949388f19 100644
--- a/doc/administration/static_objects_external_storage.md
+++ b/doc/administration/static_objects_external_storage.md
@@ -17,7 +17,7 @@ storage such as a content delivery network (CDN).
To configure external storage for static objects:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > Repository**.
+1. On the left sidebar, select **Settings > Repository**.
1. Expand the **External storage for repository static objects** section.
1. Enter the base URL and an arbitrary token. When you [set up external storage](#set-up-external-storage),
use a script that sets these values as `ORIGIN_HOSTNAME` and `STORAGE_TOKEN`.
diff --git a/doc/development/documentation/styleguide/word_list.md b/doc/development/documentation/styleguide/word_list.md
index ca8aa284241..28cba974242 100644
--- a/doc/development/documentation/styleguide/word_list.md
+++ b/doc/development/documentation/styleguide/word_list.md
@@ -77,9 +77,9 @@ Use lowercase for **boards**, **issue boards**, and **epic boards**.
## box
-Use instead of **field** or **text box**. For example:
+Use **text box** to refer to the UI field. Do not use **field** or **box**. For example:
-- In the **Variable name** box, enter `my text`.
+- In the **Variable name** text box, enter `my text`.
## button
@@ -93,6 +93,15 @@ Don't use a descriptor.
One word, **checkbox**. Do not use **check box**.
You **select** (not **check** or **enable**) and **clear** (not **deselect** or **disable**) checkboxes.
+For example:
+
+- Select the **Protect environment** checkbox.
+- Clear the **Protect environment** checkbox.
+
+If you must refer to the checkbox, you can say it is selected or cleared. For example:
+
+- Ensure the **Protect environment** checkbox is cleared.
+- Ensure the **Protect environment** checkbox is selected.
## CI/CD
@@ -519,6 +528,10 @@ Lowercase. For example:
- Open a terminal.
- From a terminal, run the `docker login` command.
+## text box
+
+Use instead of **field** or **box** when referring to the UI element.
+
## there is, there are
Try to avoid. These phrases hide the subject.
diff --git a/doc/development/integrations/jenkins.md b/doc/development/integrations/jenkins.md
index ce23dd65595..3987c6658c3 100644
--- a/doc/development/integrations/jenkins.md
+++ b/doc/development/integrations/jenkins.md
@@ -25,7 +25,7 @@ GitLab does not allow requests to localhost or the local network by default. Whe
1. Log into your GitLab instance as an administrator.
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > Network**.
+1. On the left sidebar, select **Settings > Network**.
1. Expand **Outbound requests** and check the following checkboxes:
- **Allow requests to the local network from web hooks and services**
diff --git a/doc/development/issue_types.md b/doc/development/issue_types.md
index d02ff590352..31fa50e1d97 100644
--- a/doc/development/issue_types.md
+++ b/doc/development/issue_types.md
@@ -4,7 +4,10 @@ group: Project 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/#assignments
---
-# Issue Types
+# Issue Types (DEPRECATED)
+
+WARNING:
+We are deprecating Issue Types as of GitLab 14.2 in favor of [Work Items and Work Item Types](work_items.md).
Sometimes when a new resource type is added it's not clear if it should be only an
"extension" of Issue (Issue Type) or if it should be a new first-class resource type
diff --git a/doc/development/work_items.md b/doc/development/work_items.md
new file mode 100644
index 00000000000..d4a1073461a
--- /dev/null
+++ b/doc/development/work_items.md
@@ -0,0 +1,196 @@
+---
+stage: Plan
+group: Project 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/#assignments
+---
+# Work items and work item types
+
+## Challenges
+
+Issues have the potential to be a centralized hub for collaboration.
+We need to accept the
+fact that different issue types require different fields and different context, depending
+on what job they are being used to accomplish. For example:
+
+- A bug needs to list steps to reproduce.
+- An incident needs references to stack traces and other contextual information relevant only
+ to that incident.
+
+Instead of each object type diverging into a separate model, we can standardize on an underlying
+common model that we can customize with the widgets (one or more attributes) it contains.
+
+Here are some problems with current issues usage and why we are looking into work items:
+
+- Using labels to show issue types is cumbersome and makes reporting views more complex.
+- Issue types are one of the top two use cases of labels, so it makes sense to provide first class
+ support for them.
+- Issues are starting to become cluttered as we add more capabilities to them, and they are not
+ perfect:
+
+ - There is no consistent pattern for how to surface relationships to other objects.
+ - There is not a coherent interaction model across different types of issues because we use
+ labels for this.
+ - The various implementations of issue types lack flexibility and extensibility.
+
+- Epics, issues, requirements, and others all have similar but just subtle enough
+ differences in common interactions that the user needs to hold a complicated mental
+ model of how they each behave.
+- Issues are not extensible enough to support all of the emerging jobs they need to facilitate.
+- Codebase maintainability and feature development become bigger challenges as we grow the Issue type
+ beyond its core role of issue tracking into supporting the different work item types and handling
+ logic and structure differences.
+- New functionality is typically implemented with first class objects that import behavior from issues via
+ shared concerns. This leads to duplicated effort and ultimately small differences between common interactions. This
+ leads to inconsistent UX.
+- Codebase maintainability and feature development becomes a bigger challenges as we grow issues
+ beyond its core role of issue tracking into supporting the different types and subtle differences between them.
+
+## Work item and work item type terms
+
+Using the terms "issue" or "issuable" to reference the types of collaboration objects
+(for example, issue, bug, feature, or epic) often creates confusion. To avoid confusion, we will use the term
+work item type (WIT) when referring to the type of a collaboration object.
+An instance of a WIT is a work item (WI). For example, `issue#123`, `bug#456`, `requirement#789`.
+
+### Migration strategy
+
+WI model will be built on top of the existing `Issue` model and we'll gradually migrate `Issue`
+model code to the WI model.
+
+One way to approach it is:
+
+```ruby
+class WorkItems::WorkItem < ApplicationRecord
+ self.table_name = 'issues'
+
+ # ... all the current issue.rb code
+end
+
+class Issue < WorkItems::WorkItem
+ # Do not add code to this class add to WorkItems:WorkItem
+end
+```
+
+We already use the concept of WITs within `issues` table through `issue_type`
+column. There are `issue`, `incident`, and `test_case` issue types. To extend this
+so that in future we can allow users to define custom WITs, we will move the
+`issue_type` to a separate table: `work_item_types`. The migration process of `issue_type`
+to `work_item_types` will involve creating the set of WITs for all root-level groups.
+
+NOTE:
+At first, defining a WIT will only be possible at the root-level group, which would then be inherited by sub-groups.
+We will investigate the possibility of defining new WITs at sub-group levels at a later iteration.
+
+### Introducing work_item_types table
+
+For example, suppose there are three root-level groups with IDs: `11`, `12`, and `13`. Also,
+assume the following base types: `issue: 0`, `incident: 1`, `test_case: 2`.
+
+The respective `work_item_types` records:
+
+| `group_id` | `base_type` | `title` |
+| -------------- | ----------- | --------- |
+| 11 | 0 | Issue |
+| 11 | 1 | Incident |
+| 11 | 2 | Test Case |
+| 12 | 0 | Issue |
+| 12 | 1 | Incident |
+| 12 | 2 | Test Case |
+| 13 | 0 | Issue |
+| 13 | 1 | Incident |
+| 13 | 2 | Test Case |
+
+What we will do to achieve this:
+
+1. Add a `work_item_type_id` column to the `issues` table.
+1. Ensure we write to both `issues#issue_type` and `issues#work_item_type_id` columns for
+ new or updated issues.
+1. Backfill the `work_item_type_id` column to point to the `work_item_types#id` corresponding
+ to issue's project root groups. For example:
+
+ ```ruby
+ issue.project.root_group.work_item_types.where(base_type: issue.issue_type).first.id.
+ ```
+
+1. After `issues#work_item_type_id` is populated, we can switch our queries from
+ using `issue_type` to using `work_item_type_id`.
+
+To introduce a new WIT there are two options:
+
+- Follow the first step of the above process. We will still need to run a migration
+ that adds a new WIT for all root-level groups to make the WIT available to
+ all users. Besides a long-running migration, we'll need to
+ insert several million records to `work_item_types`. This might be unwanted for users
+ that do not want or need additional WITs in their workflow.
+- Create an opt-in flow, so that the record in `work_item_types` for specific root-level group
+ is created only when a customer opts in. However, this implies a lower discoverability
+ of the newly introduced work item type.
+
+### Work item type widgets
+
+All WITs will share the same pool of predefined widgets and will be customized by
+which widgets are active on a specific WIT. Every attribute (column or association)
+will become a widget with self-encapsulated functionality regardless of the WIT it belongs to.
+Because any WIT can have any widget, we only need to define which widget is active for a
+specific WIT. So, after switching the type of a specific work item, we display a different set
+of widgets.
+
+### Widgets metadata
+
+In order to customize each WIT with corresponding active widgets we will need a data
+structure to map each WIT to specific widgets.
+
+NOTE:
+The exact structure of the WITs widgets metadata is still to be defined.
+
+### Custom work item types
+
+With the WIT widget metadata and the workflow around mapping WIT to specific
+widgets, we will be able to expose custom WITs to the users. Users will be able
+to create their own WITs and customize them with widgets from the predefined pool.
+
+### Custom widgets
+
+The end goal is to allow users to define custom widgets and use these custom
+widgets on any WIT. But this is a much further iteration and requires additional
+investigation to determine both data and application architecture to be used.
+
+## Migrate requirements and epics to work item types
+
+We'll migrate requirements and epics into work item types, with their own set
+of widgets. To achieve that, we'll migrate data to the `issues` table,
+and we'll keep current `requirements` and `epics` tables to be used as proxies for old references to ensure
+backward compatibility with already existing references.
+
+### Migrate requirements to work item types
+
+Currently `Requirement` attributes are a subset of `Issue` attributes, so the migration
+consists mainly of:
+
+- Data migration.
+- Keeping backwards compatibility at API levels.
+- Ensuring that old references continue to work.
+
+The migration to a different underlying data structure should be seamless to the end user.
+
+### Migrate epics to work item types
+
+`Epic` has some extra functionality that the `Issue` WIT does not currently have.
+So, migrating epics to a work item type requires providing feature parity between the current `Epic` object and WITs.
+
+The main missing features are:
+
+- Get WIs to the group level. This is dependent on [Consolidate Groups and Projects](https://gitlab.com/gitlab-org/architecture/tasks/-/issues/7)
+ initiative.
+- A hierarchy widget: the ability to structure work items into hierarchies.
+- Inherited date widget.
+
+To avoid disrupting workflows for users who are already using epics, we will introduce a new WIT
+called `Feature` that will provide feature parity with epics at the project-level. Having that combined with progress
+on [Consolidate Groups and Projects](https://gitlab.com/gitlab-org/architecture/tasks/-/issues/7) front will help us
+provide a smooth migration path of epics to WIT with minimal disruption to user workflow.
+
+## Work item, work item type, and widgets roadmap
+
+We will move towards work items, work item types, and custom widgets (CW) in an iterative process.
+For a rough outline of the work ahead of us, see [epic 6033](https://gitlab.com/groups/gitlab-org/-/epics/6033).
diff --git a/doc/integration/akismet.md b/doc/integration/akismet.md
index 74f2c90f85a..efc293569fe 100644
--- a/doc/integration/akismet.md
+++ b/doc/integration/akismet.md
@@ -31,7 +31,7 @@ To use Akismet:
1. Click **Show** to reveal the API key, and copy the API key's value.
1. Sign in to GitLab as an administrator.
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > Reporting** (`/admin/application_settings/reporting`).
+1. On the left sidebar, select **Settings > Reporting** (`/admin/application_settings/reporting`).
1. Select the **Enable Akismet** checkbox.
1. Fill in the API key from step 3.
1. Save the configuration.
diff --git a/doc/integration/datadog.md b/doc/integration/datadog.md
index ab64088cc65..687be5adcf7 100644
--- a/doc/integration/datadog.md
+++ b/doc/integration/datadog.md
@@ -28,7 +28,7 @@ project, group, or instance level:
1. *For instance-level integrations:*
1. Sign in to GitLab as a user with the [Administrator role](../user/permissions.md).
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > Integrations**.
+1. On the left sidebar, select **Settings > Integrations**.
1. Scroll to **Add an integration**, and select **Datadog**.
1. Select **Active** to enable the integration.
1. Specify the [**Datadog site**](https://docs.datadoghq.com/getting_started/site/) to send data to.
diff --git a/doc/integration/github.md b/doc/integration/github.md
index f3192e0af6c..0a96d67ac0c 100644
--- a/doc/integration/github.md
+++ b/doc/integration/github.md
@@ -188,7 +188,7 @@ GitHub account` when signing in, in GitLab:
1. In the top-right corner, select your avatar.
1. Select **Edit profile**.
-1. In the left sidebar, select **Account**.
+1. On the left sidebar, select **Account**.
1. In the **Social sign-in** section, select **Connect to GitHub**.
After that, you should be able to sign in via GitHub successfully.
diff --git a/doc/integration/gitlab.md b/doc/integration/gitlab.md
index a0b438c9ffa..1f35faacc2e 100644
--- a/doc/integration/gitlab.md
+++ b/doc/integration/gitlab.md
@@ -14,7 +14,7 @@ GitLab.com generates an application ID and secret key for you to use.
1. Sign in to GitLab.com.
1. In the top-right corner, select your avatar.
1. Select **Edit profile**.
-1. In the left sidebar, select **Applications**.
+1. On the left sidebar, select **Applications**.
1. Provide the required details for **Add new application**.
- Name: This can be anything. Consider something like `<Organization>'s GitLab` or `<Your Name>'s GitLab` or something else descriptive.
- Redirect URI:
diff --git a/doc/integration/gitpod.md b/doc/integration/gitpod.md
index 9df85e61798..bafba2cdf02 100644
--- a/doc/integration/gitpod.md
+++ b/doc/integration/gitpod.md
@@ -48,7 +48,7 @@ For GitLab self-managed instances, a GitLab administrator needs to:
to get your instance up and running.
1. Enable it in GitLab:
1. On the top bar, select **Menu > Admin**.
- 1. In the left sidebar, select **Settings > General**.
+ 1. On the left sidebar, select **Settings > General**.
1. Expand the **Gitpod** configuration section.
1. Check the **Enable Gitpod integration** checkbox.
1. Add your Gitpod instance URL (for example, `https://gitpod.example.com`).
diff --git a/doc/integration/jenkins.md b/doc/integration/jenkins.md
index 8910e0978b0..18ae71a7059 100644
--- a/doc/integration/jenkins.md
+++ b/doc/integration/jenkins.md
@@ -74,7 +74,7 @@ Create a personal access token to authorize Jenkins' access to GitLab.
1. Sign in to GitLab as the user to be used with Jenkins.
1. In the top-right corner, select your avatar.
1. Select **Edit profile**.
-1. In the left sidebar, select **Access Tokens**.
+1. On the left sidebar, select **Access Tokens**.
1. Create a personal access token with the **API** scope checkbox checked. For more details, see
[Personal access tokens](../user/profile/personal_access_tokens.md).
1. Record the personal access token's value, because it's required in [Configure the Jenkins server](#configure-the-jenkins-server) section.
diff --git a/doc/integration/jira/dvcs.md b/doc/integration/jira/dvcs.md
index 0c2dfd2b92e..0a136237ba5 100644
--- a/doc/integration/jira/dvcs.md
+++ b/doc/integration/jira/dvcs.md
@@ -71,14 +71,14 @@ maintenance does not affect your integration.
this user must have an [Administrator](../../user/permissions.md) role.
1. Sign in as the `jira` user.
1. In the top right corner, click the account's avatar, and select **Edit profile**.
-1. In the left sidebar, select **Applications**.
+1. On the left sidebar, select **Applications**.
1. In the **Name** field, enter a descriptive name for the integration, such as `Jira`.
1. In the **Redirect URI** field, enter the URI appropriate for your version of GitLab,
replacing `<gitlab.example.com>` with your GitLab instance domain:
- *For GitLab versions 13.0 and later* **and** *Jira versions 8.14 and later,* use the
generated `Redirect URL` from
[Linking GitLab accounts with Jira](https://confluence.atlassian.com/adminjiraserver/linking-gitlab-accounts-1027142272.html).
- - *For GitLab versions 13.0 and later* **and** *Jira Cloud,* use `https://<gitlab.example.com>/login/oauth/callback`.
+ - *For GitLab versions 13.0 and later* **and** *Jira Cloud,* use `https://<gitlab.example.com>/login/oauth/callback`.
- *For GitLab versions 11.3 and later* **and** *Jira versions 8.13 and earlier,* use `https://<gitlab.example.com>/login/oauth/callback`.
If you use GitLab.com, the URL is `https://gitlab.com/login/oauth/callback`.
- *For GitLab versions 11.2 and earlier,* use
diff --git a/doc/integration/kerberos.md b/doc/integration/kerberos.md
index de71b88666a..d4c0f6402cb 100644
--- a/doc/integration/kerberos.md
+++ b/doc/integration/kerberos.md
@@ -118,7 +118,7 @@ If you're not an administrator:
1. In the top-right corner, select your avatar.
1. Select **Edit profile**.
-1. In the left sidebar, select **Account**.
+1. On the left sidebar, select **Account**.
1. In the **Social sign-in** section, select **Connect Kerberos SPNEGO**.
If you don't see a **Social sign-in** Kerberos option, follow the
requirements in [Enable single sign-on](#enable-single-sign-on).
diff --git a/doc/integration/oauth_provider.md b/doc/integration/oauth_provider.md
index b7578a452ea..5df6c4f28b7 100644
--- a/doc/integration/oauth_provider.md
+++ b/doc/integration/oauth_provider.md
@@ -48,7 +48,7 @@ To add a new application for your user:
1. In the top-right corner, select your avatar.
1. Select **Edit profile**.
-1. In the left sidebar, select **Applications**.
+1. On the left sidebar, select **Applications**.
1. Enter a **Name**, **Redirect URI** and OAuth 2 scopes as defined in [Authorized Applications](#authorized-applications).
The **Redirect URI** is the URL where users are sent after they authorize with GitLab.
1. Select **Save application**. GitLab provides:
diff --git a/doc/integration/omniauth.md b/doc/integration/omniauth.md
index 2ed7218cabb..7dc775c2557 100644
--- a/doc/integration/omniauth.md
+++ b/doc/integration/omniauth.md
@@ -153,7 +153,7 @@ OmniAuth provider for an existing user.
1. Sign in normally - whether standard sign in, LDAP, or another OmniAuth provider.
1. In the top-right corner, select your avatar.
1. Select **Edit profile**.
-1. In the left sidebar, select **Account**.
+1. On the left sidebar, select **Account**.
1. In the **Connected Accounts** section, select the desired OmniAuth provider, such as Twitter.
1. The user is redirected to the provider. After the user authorizes GitLab,
they are redirected back to GitLab.
@@ -270,7 +270,7 @@ By default, **Sign In** is enabled by using all the OAuth Providers that have be
To enable/disable an OmniAuth provider:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, go to **Settings**.
+1. On the left sidebar, go to **Settings**.
1. Scroll to the **Sign-in Restrictions** section, and click **Expand**.
1. Below **Enabled OAuth Sign-In sources**, select the checkbox for each provider you want to enable or disable.
diff --git a/doc/integration/sourcegraph.md b/doc/integration/sourcegraph.md
index 42c1722b69b..6f0027aedc7 100644
--- a/doc/integration/sourcegraph.md
+++ b/doc/integration/sourcegraph.md
@@ -77,7 +77,7 @@ You can skip this step if you already have your GitLab repositories searchable i
### Configure your GitLab instance with Sourcegraph
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**.
+1. On the left sidebar, select **Settings > General**.
1. Expand the **Sourcegraph** configuration section.
1. Check **Enable Sourcegraph**.
1. Set the Sourcegraph URL to your Sourcegraph instance, such as `https://sourcegraph.example.com`.
diff --git a/doc/integration/trello_power_up.md b/doc/integration/trello_power_up.md
index df1d9270bd5..96150440e53 100644
--- a/doc/integration/trello_power_up.md
+++ b/doc/integration/trello_power_up.md
@@ -42,7 +42,7 @@ To find it in GitLab:
1. In the top-right corner, select your avatar.
1. Select **Edit profile**.
-1. In the left sidebar, select **Access Tokens**.
+1. On the left sidebar, select **Access Tokens**.
Learn more about generating a personal access token in the
[Personal Access Token Documentation](../user/profile/personal_access_tokens.md).
diff --git a/doc/integration/vault.md b/doc/integration/vault.md
index c98990bcb0e..ebfa91c7516 100644
--- a/doc/integration/vault.md
+++ b/doc/integration/vault.md
@@ -23,7 +23,7 @@ The following assumes you already have Vault installed and running.
1. In the top-right corner, select your avatar.
1. Select **Edit profile**.
- 1. In the left sidebar, select **Applications**.
+ 1. On the left sidebar, select **Applications**.
1. Fill out the application **Name** and [**Redirect URI**](https://www.vaultproject.io/docs/auth/jwt#redirect-uris).
1. Select the **OpenID** scope.
1. Select **Save application**.
diff --git a/doc/raketasks/features.md b/doc/raketasks/features.md
index ba14293a9fd..5c2c7b9222f 100644
--- a/doc/raketasks/features.md
+++ b/doc/raketasks/features.md
@@ -19,7 +19,7 @@ To change your username:
1. In the top-right corner, select your avatar.
1. Select **Edit profile**.
-1. In the left sidebar, select **Account**.
+1. On the left sidebar, select **Account**.
1. In the **Change username** section, type the new username.
1. Select **Update username**.
diff --git a/doc/security/webhooks.md b/doc/security/webhooks.md
index 8a2c510e8f0..c0e5d0695cc 100644
--- a/doc/security/webhooks.md
+++ b/doc/security/webhooks.md
@@ -47,7 +47,7 @@ to `127.0.0.1`, `::1` and `0.0.0.0`, as well as IPv4 `10.0.0.0/8`, `172.16.0.0/1
This behavior can be overridden:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > Network**.
+1. On the left sidebar, select **Settings > Network**.
1. Expand the **Outbound requests** section:
![Outbound requests admin settings](img/outbound_requests_section_v12_2.png)
1. Select **Allow requests to the local network from web hooks and services**.
@@ -66,7 +66,7 @@ and *webhooks* even when local requests are not allowed by adding them to the
allowlist:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > Network** (`/admin/application_settings/network`)
+1. On the left sidebar, select **Settings > Network** (`/admin/application_settings/network`)
and expand **Outbound requests**:
![Outbound local requests allowlist](img/allowlist_v13_0.png)
diff --git a/doc/subscriptions/gitlab_com/index.md b/doc/subscriptions/gitlab_com/index.md
index 114f830268b..cecbb362cb9 100644
--- a/doc/subscriptions/gitlab_com/index.md
+++ b/doc/subscriptions/gitlab_com/index.md
@@ -339,7 +339,7 @@ Quotas apply to:
1. In the top-right corner, select your avatar.
1. Select **Edit profile**.
- 1. In the left sidebar, select **[Usage Quotas](https://gitlab.com/-/profile/usage_quotas#pipelines-quota-tab)**.
+ 1. On the left sidebar, select **[Usage Quotas](https://gitlab.com/-/profile/usage_quotas#pipelines-quota-tab)**.
Only pipeline minutes for GitLab shared runners are restricted. If you have a
specific runner set up for your projects, there is no limit to your build time on GitLab SaaS.
@@ -375,7 +375,7 @@ To purchase additional minutes for your personal namespace:
1. In the top-right corner, select your avatar.
1. Select **Edit profile**.
-1. In the left sidebar, select **Usage Quotas**.
+1. On the left sidebar, select **Usage Quotas**.
1. Select **Buy additional minutes** and GitLab redirects you to the Customers Portal.
1. Locate the subscription card that's linked to your personal namespace on GitLab SaaS, click **Buy more CI minutes**, and complete the details about the transaction. Once we have processed your payment, the extra CI minutes are synced to your personal namespace.
1. To confirm the available CI minutes for your personal projects, go to the **Usage Quotas** settings again.
diff --git a/doc/system_hooks/system_hooks.md b/doc/system_hooks/system_hooks.md
index fea0becafbe..7dd0701329d 100644
--- a/doc/system_hooks/system_hooks.md
+++ b/doc/system_hooks/system_hooks.md
@@ -53,7 +53,7 @@ for Push and Tag events, but we never display commits.
To create a system hook:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **System Hooks**.
+1. On the left sidebar, select **System Hooks**.
1. Provide the **URL** and **Secret Token**.
1. Select the checkbox next to each **Trigger** you want to enable.
1. Select **Enable SSL verification**, if desired.
diff --git a/doc/tools/email.md b/doc/tools/email.md
index 211b93a437e..0429b9b952e 100644
--- a/doc/tools/email.md
+++ b/doc/tools/email.md
@@ -23,7 +23,7 @@ For information about email notifications originating from GitLab, read
## Sending emails to users from within GitLab
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Overview > Users**.
+1. On the left sidebar, select **Overview > Users**.
1. Select **Send email to users**.
![admin users](email1.png)
diff --git a/doc/topics/autodevops/quick_start_guide.md b/doc/topics/autodevops/quick_start_guide.md
index 5d3a04c7096..59c61da0c45 100644
--- a/doc/topics/autodevops/quick_start_guide.md
+++ b/doc/topics/autodevops/quick_start_guide.md
@@ -6,7 +6,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Tutorial: Use Auto DevOps to deploy an application to Google Kubernetes Engine **(FREE)**
-This step-by-step guide helps you use [Auto DevOps](index.md) to
In this tutorial, we'll help you to get started with [Auto DevOps](index.md)
through an example of how to deploy an application to Google Kubernetes Engine (GKE).
diff --git a/doc/user/admin_area/appearance.md b/doc/user/admin_area/appearance.md
index 67fe8994080..0ffa8289d37 100644
--- a/doc/user/admin_area/appearance.md
+++ b/doc/user/admin_area/appearance.md
@@ -12,7 +12,7 @@ There are several options for customizing the appearance of a self-managed insta
of GitLab. To access these settings:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > Appearance**.
+1. On the left sidebar, select **Settings > Appearance**.
## Navigation bar
diff --git a/doc/user/admin_area/diff_limits.md b/doc/user/admin_area/diff_limits.md
index 2e7841374be..b50748ca97e 100644
--- a/doc/user/admin_area/diff_limits.md
+++ b/doc/user/admin_area/diff_limits.md
@@ -34,7 +34,7 @@ set values are presented as **Too large** are cannot be expanded in the UI.
To configure these values:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**.
+1. On the left sidebar, select **Settings > General**.
1. Expand **Diff limits**.
1. Enter a value for the diff limit.
1. Select **Save changes**.
diff --git a/doc/user/admin_area/index.md b/doc/user/admin_area/index.md
index faf1d8f1084..85eca17f6e7 100644
--- a/doc/user/admin_area/index.md
+++ b/doc/user/admin_area/index.md
@@ -72,7 +72,7 @@ You can administer all projects in the GitLab instance from the Admin Area's Pro
To access the Projects page:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Overview > Projects**.
+1. On the left sidebar, select **Overview > Projects**.
1. Select the **All**, **Private**, **Internal**, or **Public** tab to list only
projects of that criteria.
@@ -112,7 +112,7 @@ You can combine the filter options. For example, to list only public projects wi
You can administer all users in the GitLab instance from the Admin Area's Users page:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Overview > Users**.
+1. On the left sidebar, select **Overview > Users**.
To list users matching a specific criteria, click on one of the following tabs on the **Users** page:
@@ -157,7 +157,7 @@ You can impersonate a user in the following ways:
- Through the UI:
1. On the top bar, select **Menu > Admin**.
- 1. In the left sidebar, select **Overview > Users**.
+ 1. On the left sidebar, select **Overview > Users**.
1. From the list of users, select a user.
1. Select **Impersonate**.
- With the API, using [impersonation tokens](../../api/index.md#impersonation-tokens).
@@ -210,7 +210,7 @@ You can administer all groups in the GitLab instance from the Admin Area's Group
To access the Groups page:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Overview > Groups**.
+1. On the left sidebar, select **Overview > Groups**.
For each group, the page displays their name, description, size, number of projects in the group,
number of members, and whether the group is private, internal, or public. To edit a group, click
@@ -232,7 +232,7 @@ You can administer all jobs in the GitLab instance from the Admin Area's Jobs pa
To access the Jobs page:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Overview > Jobs**. All jobs are listed, in descending order of job ID.
+1. On the left sidebar, select **Overview > Jobs**. All jobs are listed, in descending order of job ID.
1. Click the **All** tab to list all jobs. Click the **Pending**, **Running**, or **Finished**
tab to list only jobs of that status.
@@ -258,7 +258,7 @@ You can administer all runners in the GitLab instance from the Admin Area's **Ru
To access the **Runners** page:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Overview > Runners**.
+1. On the left sidebar, select **Overview > Runners**.
The **Runners** page features:
@@ -308,7 +308,7 @@ page. For more details, see [Gitaly](../../administration/gitaly/index.md).
To access the **Gitaly Servers** page:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Overview > Gitaly Servers**.
+1. On the left sidebar, select **Overview > Gitaly Servers**.
For each Gitaly server, the following details are listed:
diff --git a/doc/user/admin_area/merge_requests_approvals.md b/doc/user/admin_area/merge_requests_approvals.md
index f4e99fbedc4..ffa08dee10d 100644
--- a/doc/user/admin_area/merge_requests_approvals.md
+++ b/doc/user/admin_area/merge_requests_approvals.md
@@ -16,7 +16,7 @@ project level.
To enable merge request approval rules for an instance:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **{push-rules}** **Push Rules**, and expand **Merge request (MR) approvals**.
+1. On the left sidebar, select **{push-rules}** **Push Rules**, and expand **Merge request (MR) approvals**.
1. Set the required rule.
1. Click **Save changes**.
diff --git a/doc/user/admin_area/monitoring/health_check.md b/doc/user/admin_area/monitoring/health_check.md
index 07704803da4..c5ffb032afd 100644
--- a/doc/user/admin_area/monitoring/health_check.md
+++ b/doc/user/admin_area/monitoring/health_check.md
@@ -147,7 +147,7 @@ An access token needs to be provided while accessing the probe endpoints. You ca
find the current accepted token in the user interface:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Monitoring > Health Check**. (`admin/health_check`)
+1. On the left sidebar, select **Monitoring > Health Check**. (`admin/health_check`)
![access token](img/health_check_token.png)
diff --git a/doc/user/admin_area/settings/account_and_limit_settings.md b/doc/user/admin_area/settings/account_and_limit_settings.md
index 17ea4ce04bb..dd578f5dc9b 100644
--- a/doc/user/admin_area/settings/account_and_limit_settings.md
+++ b/doc/user/admin_area/settings/account_and_limit_settings.md
@@ -12,7 +12,7 @@ type: reference
You can change the default maximum number of projects that users can create in their personal namespace:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**, then expand **Account and limit**.
+1. On the left sidebar, select **Settings > General**, then expand **Account and limit**.
1. Increase or decrease that **Default projects limit** value.
If you set **Default projects limit** to 0, users are not allowed to create projects
@@ -23,7 +23,7 @@ in their users personal namespace. However, projects can still be created in a g
You can change the maximum file size for attachments in comments and replies in GitLab:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**, then expand **Account and limit**.
+1. On the left sidebar, select **Settings > General**, then expand **Account and limit**.
1. Increase or decrease by changing the value in **Maximum attachment size (MB)**.
NOTE:
@@ -36,7 +36,7 @@ details.
You can change the maximum push size for your repository:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**, then expand **Account and limit**.
+1. On the left sidebar, select **Settings > General**, then expand **Account and limit**.
1. Increase or decrease by changing the value in **Maximum push size (MB)**.
NOTE:
@@ -51,7 +51,7 @@ Use [Git LFS](../../../topics/git/lfs/index.md) to add large files to a reposito
You can change the maximum file size for imports in GitLab:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**, then expand **Account and limit**.
+1. On the left sidebar, select **Settings > General**, then expand **Account and limit**.
1. Increase or decrease by changing the value in **Maximum import size (MB)**.
NOTE:
@@ -71,7 +71,7 @@ Only a GitLab administrator can set the prefix, which is a global setting applie
to any PAT generated in the system by any user:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**.
+1. On the left sidebar, select **Settings > General**.
1. Expand the **Account and limit** section.
1. Fill in the **Personal Access Token prefix** field.
1. Click **Save changes**.
@@ -114,7 +114,7 @@ These settings can be found in:
1. Click **Save changes**.
- GitLab global settings:
1. On the top bar, select **Menu > Admin**.
- 1. In the left sidebar, select **Settings > General**.
+ 1. On the left sidebar, select **Settings > General**.
1. Expand the **Account and limit** section.
1. Fill in the **Size limit per repository (MB)** field.
1. Click **Save changes**.
@@ -166,7 +166,7 @@ GitLab administrators can choose to customize the session duration (in minutes)
To set a limit on how long these sessions are valid:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**.
+1. On the left sidebar, select **Settings > General**.
1. Expand the **Account and limit** section.
1. Fill in the **Session duration for Git operations when 2FA is enabled (minutes)** field.
1. Click **Save changes**.
@@ -191,7 +191,7 @@ there are no restrictions.
To set a lifetime on how long personal access tokens are valid:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**.
+1. On the left sidebar, select **Settings > General**.
1. Expand the **Account and limit** section.
1. Fill in the **Maximum allowable lifetime for personal access tokens (days)** field.
1. Click **Save changes**.
@@ -214,7 +214,7 @@ By default, expired SSH keys **are not usable**.
To allow the use of expired SSH keys:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**.
+1. On the left sidebar, select **Settings > General**.
1. Expand the **Account and limit** section.
1. Uncheck the **Enforce SSH key expiration** checkbox.
@@ -230,7 +230,7 @@ By default, expired personal access tokens (PATs) **are not usable**.
To allow the use of expired PATs:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**.
+1. On the left sidebar, select **Settings > General**.
1. Expand the **Account and limit** section.
1. Uncheck the **Enforce personal access token expiration** checkbox.
@@ -243,7 +243,7 @@ To maintain integrity of user details in [Audit Events](../../../administration/
To do this:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**, then expand **Account and limit**.
+1. On the left sidebar, select **Settings > General**, then expand **Account and limit**.
1. Select the **Prevent users from changing their profile name** checkbox.
NOTE:
diff --git a/doc/user/admin_area/settings/external_authorization.md b/doc/user/admin_area/settings/external_authorization.md
index eb3f77f6807..985f3c133d5 100644
--- a/doc/user/admin_area/settings/external_authorization.md
+++ b/doc/user/admin_area/settings/external_authorization.md
@@ -42,7 +42,7 @@ the [Omnibus GitLab documentation](https://docs.gitlab.com/omnibus/settings/logs
The external authorization service can be enabled by an administrator:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**:
+1. On the left sidebar, select **Settings > General**:
![Enable external authorization service](img/external_authorization_service_settings.png)
The available required properties are:
diff --git a/doc/user/admin_area/settings/floc.md b/doc/user/admin_area/settings/floc.md
index d9a2815bc26..17c390aef0e 100644
--- a/doc/user/admin_area/settings/floc.md
+++ b/doc/user/admin_area/settings/floc.md
@@ -23,7 +23,7 @@ Permissions-Policy: interest-cohort=()
To enable it:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**.
+1. On the left sidebar, select **Settings > General**.
1. Expand **Federated Learning of Cohorts**.
1. Check the box.
1. Click **Save changes**.
diff --git a/doc/user/admin_area/settings/help_page.md b/doc/user/admin_area/settings/help_page.md
index 0912f043712..cf08b9b71db 100644
--- a/doc/user/admin_area/settings/help_page.md
+++ b/doc/user/admin_area/settings/help_page.md
@@ -85,7 +85,7 @@ You can redirect these `/help` links to either:
- A destination that meets [necessary requirements](#destination-requirements).
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > Preferences**.
+1. On the left sidebar, select **Settings > Preferences**.
1. Expand **Sign-in and Help page**.
1. In the **Documentation pages URL** field, enter the URL.
1. Select **Save changes**.
diff --git a/doc/user/admin_area/settings/index.md b/doc/user/admin_area/settings/index.md
index 18b8833320b..78c1e01c33b 100644
--- a/doc/user/admin_area/settings/index.md
+++ b/doc/user/admin_area/settings/index.md
@@ -18,7 +18,7 @@ documentation for all current settings and limits on the GitLab.com instance.
To access the default page for Admin Area settings:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**.
+1. On the left sidebar, select **Settings > General**.
| Option | Description |
| ------ | ----------- |
@@ -127,5 +127,5 @@ You can change the [Default first day of the week](../../profile/preferences.md)
for the entire GitLab instance:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > Preferences**.
+1. On the left sidebar, select **Settings > Preferences**.
1. Scroll to the **Localization** section, and select your desired first day of the week.
diff --git a/doc/user/admin_area/settings/instance_template_repository.md b/doc/user/admin_area/settings/instance_template_repository.md
index a63444308b6..862bf3b1652 100644
--- a/doc/user/admin_area/settings/instance_template_repository.md
+++ b/doc/user/admin_area/settings/instance_template_repository.md
@@ -20,7 +20,7 @@ while the project remains secure.
To select a project to serve as the custom template repository:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > Templates**.
+1. On the left sidebar, select **Settings > Templates**.
1. Select the project:
![File templates in the Admin Area](img/file_template_admin_area_v14_0.png)
diff --git a/doc/user/admin_area/settings/project_integration_management.md b/doc/user/admin_area/settings/project_integration_management.md
index 597e6f4d80f..aadabe4d6ad 100644
--- a/doc/user/admin_area/settings/project_integration_management.md
+++ b/doc/user/admin_area/settings/project_integration_management.md
@@ -23,7 +23,7 @@ Only the complete settings for an integration can be inherited. Per-field inheri
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/2543) in GitLab 13.6 for group-level integrations.
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > Integrations**.
+1. On the left sidebar, select **Settings > Integrations**.
1. Select an integration.
1. Enter configuration details and click **Save changes**.
@@ -55,7 +55,7 @@ integration on all non-configured groups and projects by default.
### Remove an instance-level default setting
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > Integrations**.
+1. On the left sidebar, select **Settings > Integrations**.
1. Select an integration.
1. Click **Reset** and confirm.
@@ -69,7 +69,7 @@ You can view which projects in your instance use custom settings that [override
for an integration.
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > Integrations**.
+1. On the left sidebar, select **Settings > Integrations**.
1. Select an integration.
1. Select the **Projects using custom settings** tab.
diff --git a/doc/user/admin_area/settings/push_event_activities_limit.md b/doc/user/admin_area/settings/push_event_activities_limit.md
index e36339cdaaf..760ce96d987 100644
--- a/doc/user/admin_area/settings/push_event_activities_limit.md
+++ b/doc/user/admin_area/settings/push_event_activities_limit.md
@@ -27,7 +27,7 @@ To modify this setting:
- In the Admin Area:
1. On the top bar, select **Menu > Admin**.
- 1. In the left sidebar, select **Settings > Network**, then expand **Performance optimization**.
+ 1. On the left sidebar, select **Settings > Network**, then expand **Performance optimization**.
- Through the [Application settings API](../../../api/settings.md#list-of-settings-that-can-be-accessed-via-api-calls)
as `push_event_activities_limit`.
diff --git a/doc/user/admin_area/settings/rate_limits_on_raw_endpoints.md b/doc/user/admin_area/settings/rate_limits_on_raw_endpoints.md
index f2d42beca5a..020d02b1635 100644
--- a/doc/user/admin_area/settings/rate_limits_on_raw_endpoints.md
+++ b/doc/user/admin_area/settings/rate_limits_on_raw_endpoints.md
@@ -12,7 +12,7 @@ type: reference
This setting defaults to `300` requests per minute, and allows you to rate limit the requests to raw endpoints:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > Network**.
+1. On the left sidebar, select **Settings > Network**.
1. Expand **Performance optimization**.
For example, requests over `300` per minute to `https://gitlab.com/gitlab-org/gitlab-foss/raw/master/app/controllers/application_controller.rb` are blocked. Access to the raw file is released after 1 minute.
diff --git a/doc/user/admin_area/settings/sign_in_restrictions.md b/doc/user/admin_area/settings/sign_in_restrictions.md
index 1037ad25276..223ffeebd44 100644
--- a/doc/user/admin_area/settings/sign_in_restrictions.md
+++ b/doc/user/admin_area/settings/sign_in_restrictions.md
@@ -14,7 +14,7 @@ You can use **Sign-in restrictions** to customize authentication restrictions fo
To access sign-in restriction settings:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**.
+1. On the left sidebar, select **Settings > General**.
1. Expand the **Sign-in restrictions** section.
## Password authentication enabled
@@ -118,7 +118,7 @@ For example, if you include the following information in the noted text box:
To access this text box:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**, and expand the **Sign-in restrictions** section.
+1. On the left sidebar, select **Settings > General**, and expand the **Sign-in restrictions** section.
```
Your users see the **Custom sign-in text** when they navigate to the sign-in screen for your
diff --git a/doc/user/admin_area/settings/sign_up_restrictions.md b/doc/user/admin_area/settings/sign_up_restrictions.md
index cb96b537e3d..62adbfff238 100644
--- a/doc/user/admin_area/settings/sign_up_restrictions.md
+++ b/doc/user/admin_area/settings/sign_up_restrictions.md
@@ -23,7 +23,7 @@ you do not expect public users to sign up for an account.
To disable sign ups:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**, and expand **Sign-up restrictions**.
+1. On the left sidebar, select **Settings > General**, and expand **Sign-up restrictions**.
1. Clear the **Sign-up enabled** checkbox, then select **Save changes**.
## Require administrator approval for new sign ups
@@ -39,7 +39,7 @@ enabled by default for new GitLab instances. It is only applicable if sign ups a
To require administrator approval for new sign ups:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**, and expand **Sign-up restrictions**.
+1. On the left sidebar, select **Settings > General**, and expand **Sign-up restrictions**.
1. Select the **Require admin approval for new sign-ups** checkbox, then select **Save changes**.
In [GitLab 13.7 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/273258), if an administrator disables this setting, the users in pending approval state are
@@ -53,7 +53,7 @@ their email address before they are allowed to sign in.
To enforce confirmation of the email address used for new sign ups:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**, and expand **Sign-up restrictions**.
+1. On the left sidebar, select **Settings > General**, and expand **Sign-up restrictions**.
1. Select the **Enable email restrictions for sign ups** checkbox, then select **Save changes**.
## User cap **(FREE SELF)**
@@ -71,7 +71,7 @@ user cap, the users in pending approval state are automatically approved in a ba
### Set the user cap number
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**.
+1. On the left sidebar, select **Settings > General**.
1. Expand **Sign-up restrictions**.
1. Enter a number in **User cap**.
1. Select **Save changes**.
@@ -81,7 +81,7 @@ New user sign ups are subject to the user cap restriction.
## Remove the user cap
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**.
+1. On the left sidebar, select **Settings > General**.
1. Expand **Sign-up restrictions**.
1. Remove the number from **User cap**.
1. Select **Save changes**.
@@ -139,7 +139,7 @@ reduce the risk of malicious users creating spam accounts with disposable email
To create an email domain allowlist or denylist:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**, and expand **Sign-up restrictions**.
+1. On the left sidebar, select **Settings > General**, and expand **Sign-up restrictions**.
1. For the allowlist, you must enter the list manually. For the denylist, you can enter the list
manually or upload a `.txt` file that contains list entries.
diff --git a/doc/user/admin_area/settings/terms.md b/doc/user/admin_area/settings/terms.md
index dd3cc0a16fb..c7c41e665ec 100644
--- a/doc/user/admin_area/settings/terms.md
+++ b/doc/user/admin_area/settings/terms.md
@@ -18,7 +18,7 @@ for example `https://gitlab.example.com/-/users/terms`.
To enforce acceptance of a Terms of Service and Privacy Policy:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**.
+1. On the left sidebar, select **Settings > General**.
1. Expand the **Terms of Service and Privacy Policy** section.
1. Check the **All users must accept the Terms of Service and Privacy Policy to access GitLab** checkbox.
1. Input the text of the **Terms of Service and Privacy Policy**. You can use [Markdown](../../markdown.md)
diff --git a/doc/user/admin_area/settings/user_and_ip_rate_limits.md b/doc/user/admin_area/settings/user_and_ip_rate_limits.md
index 7e547541079..28c78fd8837 100644
--- a/doc/user/admin_area/settings/user_and_ip_rate_limits.md
+++ b/doc/user/admin_area/settings/user_and_ip_rate_limits.md
@@ -20,7 +20,7 @@ The following limits are disabled by default:
To enforce any or all of them:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > Network**, and expand **User and IP rate limits**:
+1. On the left sidebar, select **Settings > Network**, and expand **User and IP rate limits**:
![user-and-ip-rate-limits](img/user_and_ip_rate_limits.png)
NOTE:
diff --git a/doc/user/admin_area/settings/visibility_and_access_controls.md b/doc/user/admin_area/settings/visibility_and_access_controls.md
index 5d7b90ab44f..7f3f4b32802 100644
--- a/doc/user/admin_area/settings/visibility_and_access_controls.md
+++ b/doc/user/admin_area/settings/visibility_and_access_controls.md
@@ -14,7 +14,7 @@ To access the visibility and access control options:
1. Sign in to GitLab as a user with [Administrator role](../../permissions.md).
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**.
+1. On the left sidebar, select **Settings > General**.
1. Expand the **Visibility and access controls** section.
## Protect default branches
@@ -34,7 +34,7 @@ To change the default branch protection for the entire instance:
1. Sign in to GitLab as a user with [Administrator role](../../permissions.md).
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**.
+1. On the left sidebar, select **Settings > General**.
1. Expand the **Visibility and access controls** section.
1. Select a **Default branch protection**:
- **Not protected** - Both developers and maintainers can push new commits,
@@ -60,7 +60,7 @@ disable this privilege for group owners, enforcing the instance-level protection
1. Sign in to GitLab as a user with [Administrator role](../../permissions.md).
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**.
+1. On the left sidebar, select **Settings > General**.
1. Expand the **Visibility and access controls** section.
1. Deselect the **Allow owners to manage default branch protection per group** checkbox.
1. Select **Save changes**.
@@ -76,7 +76,7 @@ on the instance. To alter which roles have permission to create projects:
1. Sign in to GitLab as a user with [Administrator role](../../permissions.md).
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**.
+1. On the left sidebar, select **Settings > General**.
1. Expand the **Visibility and access controls** section.
1. For **Default project creation protection**, select the desired roles:
- No one.
@@ -91,7 +91,7 @@ delete a project. To allow only users with the Administrator role to delete proj
1. Sign in to GitLab as a user with [Administrator role](../../permissions.md).
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**.
+1. On the left sidebar, select **Settings > General**.
1. Expand the **Visibility and access controls** section.
1. Scroll to **Default project deletion protection**, and select **Only admins can delete project**.
1. Select **Save changes**.
@@ -143,7 +143,7 @@ To set the default [visibility levels for new projects](../../../public_access/p
1. Sign in to GitLab as a user with [Administrator role](../../permissions.md).
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**.
+1. On the left sidebar, select **Settings > General**.
1. Expand the **Visibility and access controls** section.
1. Select the desired default project visibility:
- **Private** - Project access must be granted explicitly to each user. If this
@@ -158,7 +158,7 @@ To set the default visibility levels for new [snippets](../../snippets.md):
1. Sign in to GitLab as a user with [Administrator role](../../permissions.md).
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**.
+1. On the left sidebar, select **Settings > General**.
1. Expand the **Visibility and access controls** section.
1. Select the desired default snippet visibility.
1. Select **Save changes**.
@@ -172,7 +172,7 @@ To set the default visibility levels for new groups:
1. Sign in to GitLab as a user with [Administrator role](../../permissions.md).
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**.
+1. On the left sidebar, select **Settings > General**.
1. Expand the **Visibility and access controls** section.
1. Select the desired default group visibility:
- **Private** - The group and its projects can only be viewed by members.
@@ -189,7 +189,7 @@ To restrict visibility levels for projects, snippets, and selected pages:
1. Sign in to GitLab as a user with [Administrator role](../../permissions.md).
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**.
+1. On the left sidebar, select **Settings > General**.
1. Expand the **Visibility and access controls** section.
1. In the **Restricted visibility levels** section, select the desired visibility levels to restrict.
1. Select **Save changes**.
@@ -203,7 +203,7 @@ You can specify from which hosting sites users can [import their projects](../..
1. Sign in to GitLab as a user with [Administrator role](../../permissions.md).
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**.
+1. On the left sidebar, select **Settings > General**.
1. Expand the **Visibility and access controls** section.
1. Select each of **Import sources** to allow.
1. Select **Save changes**.
@@ -215,7 +215,7 @@ To enable the export of
1. Sign in to GitLab as a user with [Administrator role](../../permissions.md).
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**.
+1. On the left sidebar, select **Settings > General**.
1. Expand the **Visibility and access controls** section.
1. Select **Project export enabled**.
1. Select **Save changes**.
@@ -231,7 +231,7 @@ To specify the enabled Git access protocols:
1. Sign in to GitLab as a user with [Administrator role](../../permissions.md).
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**.
+1. On the left sidebar, select **Settings > General**.
1. Expand the **Visibility and access controls** section.
1. Select the desired Git access protocols:
- Both SSH and HTTP(S)
diff --git a/doc/user/admin_area/user_cohorts.md b/doc/user/admin_area/user_cohorts.md
index ea40d9be2a1..89026e56a27 100644
--- a/doc/user/admin_area/user_cohorts.md
+++ b/doc/user/admin_area/user_cohorts.md
@@ -11,7 +11,7 @@ You can analyze your users' GitLab activities over time.
To view user cohorts:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Overview > Users**.
+1. On the left sidebar, select **Overview > Users**.
1. Select the **Cohorts** tab.
## Overview
diff --git a/doc/user/discussions/index.md b/doc/user/discussions/index.md
index a1d8863710c..7bff0a83532 100644
--- a/doc/user/discussions/index.md
+++ b/doc/user/discussions/index.md
@@ -13,7 +13,7 @@ GitLab encourages communication through comments, threads, and
There are two types of comments:
- A standard comment.
-- A comment in a thread, which has to be resolved.
+- A comment in a thread, which can be [resolved](#resolve-a-thread).
In a comment, you can enter [Markdown](../markdown.md) and use [quick actions](../project/quick_actions.md).
@@ -218,16 +218,16 @@ A threaded comment is created.
## Resolve a thread
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/5022) in GitLab 8.11.
-> - Resolvable threads can be added only to merge request diffs.
> - Resolving comments individually was [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/28750) in GitLab 13.6.
-You can resolve a thread when you want to finish a conversation.
+In a merge request, you can resolve a thread when you want to finish a conversation.
Prerequisites:
- You must have at least the [Developer role](../permissions.md#project-members-permissions)
or be the author of the change being reviewed.
-- You must be in an issue, merge request, commit, or snippet.
+- Resolvable threads can be added only to merge requests. It doesn't work
+ for comments in issues, commits, or snippets.
To resolve a thread:
diff --git a/doc/user/group/index.md b/doc/user/group/index.md
index f69aabf4d14..84f23eecc08 100644
--- a/doc/user/group/index.md
+++ b/doc/user/group/index.md
@@ -316,7 +316,7 @@ In GitLab 13.11, you can optionally replace the sharing form with a modal window
To share a group after enabling this feature:
1. Go to your group's page.
-1. In the left sidebar, go to **Group information > Members**, and then select **Invite a group**.
+1. On the left sidebar, go to **Group information > Members**, and then select **Invite a group**.
1. Select a group, and select a **Max role**.
1. (Optional) Select an **Access expiration date**.
1. Select **Invite**.
diff --git a/doc/user/group/saml_sso/index.md b/doc/user/group/saml_sso/index.md
index 18b0cdbbd63..1c6fad73efe 100644
--- a/doc/user/group/saml_sso/index.md
+++ b/doc/user/group/saml_sso/index.md
@@ -310,7 +310,7 @@ For example, to unlink the `MyOrg` account:
1. In the top-right corner, select your avatar.
1. Select **Edit profile**.
-1. In the left sidebar, select **Account**.
+1. On the left sidebar, select **Account**.
1. In the **Social sign-in** section, select **Disconnect** next to the connected account.
![Unlink Group SAML](img/unlink_group_saml.png)
diff --git a/doc/user/group/settings/import_export.md b/doc/user/group/settings/import_export.md
index cacfe0a6f10..516f3504a98 100644
--- a/doc/user/group/settings/import_export.md
+++ b/doc/user/group/settings/import_export.md
@@ -69,7 +69,7 @@ Users with the [Owner role](../../permissions.md) for a group can export the
contents of that group:
1. On the top bar, select **Menu >** **Groups** and find your group.
-1. In the left sidebar, select **Settings**.
+1. On the left sidebar, select **Settings**.
1. Scroll to the **Advanced** section, and select **Export Group**.
1. After the export is generated, you should receive an email with a link to the [exported contents](#exported-contents)
in a compressed tar archive, with contents in NDJSON format.
diff --git a/doc/user/instance/clusters/index.md b/doc/user/instance/clusters/index.md
index 149ef376dcc..20cd30b6110 100644
--- a/doc/user/instance/clusters/index.md
+++ b/doc/user/instance/clusters/index.md
@@ -17,7 +17,7 @@ projects.
To view the instance level Kubernetes clusters:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Kubernetes**.
+1. On the left sidebar, select **Kubernetes**.
## Cluster precedence
diff --git a/doc/user/packages/terraform_module_registry/index.md b/doc/user/packages/terraform_module_registry/index.md
index 6fc870425a8..7f101adccad 100644
--- a/doc/user/packages/terraform_module_registry/index.md
+++ b/doc/user/packages/terraform_module_registry/index.md
@@ -41,6 +41,10 @@ PUT /projects/:id/packages/terraform/modules/:module_name/:module_system/:module
Provide the file content in the request body.
+Note that, in the following example, the request must end with `/file`.
+If you send a request ending with something else, it results in a 404
+error `{"error":"404 Not Found"}`.
+
Example request using a personal access token:
```shell
diff --git a/doc/user/profile/account/delete_account.md b/doc/user/profile/account/delete_account.md
index 991d035c301..41b4e508c38 100644
--- a/doc/user/profile/account/delete_account.md
+++ b/doc/user/profile/account/delete_account.md
@@ -21,7 +21,7 @@ As a user, to delete your own account:
1. In the top-right corner, select your avatar.
1. Select **Edit profile**.
-1. In the left sidebar, select **Account**.
+1. On the left sidebar, select **Account**.
1. Select **Delete account**.
## As an administrator
diff --git a/doc/user/profile/active_sessions.md b/doc/user/profile/active_sessions.md
index e55b92378bd..25f349d9272 100644
--- a/doc/user/profile/active_sessions.md
+++ b/doc/user/profile/active_sessions.md
@@ -18,7 +18,7 @@ To list all active sessions:
1. In the top-right corner, select your avatar.
1. Select **Edit profile**.
-1. In the left sidebar, select **Active Sessions**.
+1. On the left sidebar, select **Active Sessions**.
![Active sessions list](img/active_sessions_list.png)
@@ -35,7 +35,7 @@ To revoke an active session:
1. In the top-right corner, select your avatar.
1. Select **Edit profile**.
-1. In the left sidebar, select **Active Sessions**.
+1. On the left sidebar, select **Active Sessions**.
1. Select **Revoke** next to a session. The current session cannot be revoked, as this would sign you out of GitLab.
NOTE:
diff --git a/doc/user/profile/index.md b/doc/user/profile/index.md
index 38e7c37ddb1..82a56d00118 100644
--- a/doc/user/profile/index.md
+++ b/doc/user/profile/index.md
@@ -31,7 +31,7 @@ To change your password:
1. In the top-right corner, select your avatar.
1. Select **Edit profile**.
-1. In the left sidebar, select **Password**.
+1. On the left sidebar, select **Password**.
1. In the **Current password** field, enter your current password.
1. In the **New password** and **Password confirmation** field, enter your new password.
1. Select **Save password**.
@@ -55,7 +55,7 @@ To change your username:
1. In the top-right corner, select your avatar.
1. Select **Edit profile**.
-1. In the left sidebar, select **Account**.
+1. On the left sidebar, select **Account**.
1. In the **Change username** section, enter a new username as the path.
1. Select **Update username**.
diff --git a/doc/user/profile/notifications.md b/doc/user/profile/notifications.md
index cd4d4e370db..ffb1db062b8 100644
--- a/doc/user/profile/notifications.md
+++ b/doc/user/profile/notifications.md
@@ -48,7 +48,7 @@ To edit your notification settings:
1. In the top-right corner, select your avatar.
1. Select **Preferences**.
-1. In the left sidebar, select **Notifications**.
+1. On the left sidebar, select **Notifications**.
1. Edit the desired notification settings. Edited settings are automatically saved and enabled.
## Notification scope
@@ -90,7 +90,7 @@ To select a notification level for a group, use either of these methods:
1. In the top-right corner, select your avatar.
1. Select **Preferences**.
-1. In the left sidebar, select **Notifications**.
+1. On the left sidebar, select **Notifications**.
1. Locate the project in the **Groups** section.
1. Select the desired [notification level](#notification-levels).
@@ -108,7 +108,7 @@ You can select an email address to receive notifications for each group you belo
1. In the top-right corner, select your avatar.
1. Select **Preferences**.
-1. In the left sidebar, select **Notifications**.
+1. On the left sidebar, select **Notifications**.
1. Locate the project in the **Groups** section.
1. Select the desired email address.
@@ -120,7 +120,7 @@ To select a notification level for a project, use either of these methods:
1. In the top-right corner, select your avatar.
1. Select **Preferences**.
-1. In the left sidebar, select **Notifications**.
+1. On the left sidebar, select **Notifications**.
1. Locate the project in the **Projects** section.
1. Select the desired [notification level](#notification-levels).
diff --git a/doc/user/profile/personal_access_tokens.md b/doc/user/profile/personal_access_tokens.md
index ca9460793cf..9bd5153d6d5 100644
--- a/doc/user/profile/personal_access_tokens.md
+++ b/doc/user/profile/personal_access_tokens.md
@@ -38,7 +38,7 @@ You can create as many personal access tokens as you like.
1. In the top-right corner, select your avatar.
1. Select **Edit profile**.
-1. In the left sidebar, select **Access Tokens**.
+1. On the left sidebar, select **Access Tokens**.
1. Enter a name and optional expiry date for the token.
1. Select the [desired scopes](#personal-access-token-scopes).
1. Select **Create personal access token**.
@@ -62,7 +62,7 @@ At any time, you can revoke a personal access token.
1. In the top-right corner, select your avatar.
1. Select **Edit profile**.
-1. In the left sidebar, select **Access Tokens**.
+1. On the left sidebar, select **Access Tokens**.
1. In the **Active personal access tokens** area, next to the key, select **Revoke**.
## View the last time a token was used
@@ -74,7 +74,7 @@ To view the last time a token was used:
1. In the top-right corner, select your avatar.
1. Select **Edit profile**.
-1. In the left sidebar, select **Access Tokens**.
+1. On the left sidebar, select **Access Tokens**.
1. In the **Active personal access tokens** area, next to the key, view the **Last Used** date.
## Personal access token scopes
diff --git a/doc/user/project/issues/managing_issues.md b/doc/user/project/issues/managing_issues.md
index bcf76ad53f6..7033b90b736 100644
--- a/doc/user/project/issues/managing_issues.md
+++ b/doc/user/project/issues/managing_issues.md
@@ -72,7 +72,7 @@ When you're creating a new issue, these are the fields you can fill in:
To visit the issue tracker for all projects in your group:
1. Go to the group dashboard.
-1. In the left sidebar, select **Issues**.
+1. On the left sidebar, select **Issues**.
1. In the top-right, select the **Select project to create issue** button.
1. Select the project you'd like to create an issue for. The button now reflects the selected
project.
diff --git a/doc/user/project/members/share_project_with_groups.md b/doc/user/project/members/share_project_with_groups.md
index 353ce73329e..e1149b85cd5 100644
--- a/doc/user/project/members/share_project_with_groups.md
+++ b/doc/user/project/members/share_project_with_groups.md
@@ -59,7 +59,7 @@ In GitLab 13.11, you can optionally replace the sharing form with a modal window
To share a project after enabling this feature:
1. Go to your project's page.
-1. In the left sidebar, go to **Project information > Members**, and then select **Invite a group**.
+1. On the left sidebar, go to **Project information > Members**, and then select **Invite a group**.
1. Select a group, and select a **Max role**.
1. (Optional) Select an **Access expiration date**.
1. Select **Invite**.
diff --git a/doc/user/project/pages/pages_access_control.md b/doc/user/project/pages/pages_access_control.md
index 532a36b2327..4b4d479e3e9 100644
--- a/doc/user/project/pages/pages_access_control.md
+++ b/doc/user/project/pages/pages_access_control.md
@@ -52,6 +52,6 @@ To sign out of your GitLab Pages website, revoke the application access token
for GitLab Pages:
1. In the top menu, select your profile, and then select **Settings**.
-1. In the left sidebar, select **Applications**.
+1. On the left sidebar, select **Applications**.
1. Scroll to the **Authorized applications** section, find the **GitLab Pages**
entry, and select its **Revoke** button.
diff --git a/doc/user/project/repository/branches/default.md b/doc/user/project/repository/branches/default.md
index cb920184d65..a1ea929bb49 100644
--- a/doc/user/project/repository/branches/default.md
+++ b/doc/user/project/repository/branches/default.md
@@ -64,7 +64,7 @@ customize the initial branch for projects hosted on that instance. Individual
groups and subgroups can override this instance-wide setting for their projects.
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > Repository**.
+1. On the left sidebar, select **Settings > Repository**.
1. Expand **Default initial branch name**.
1. Change the default initial branch to a custom name of your choice.
1. Select **Save changes**.
diff --git a/doc/user/project/repository/gpg_signed_commits/index.md b/doc/user/project/repository/gpg_signed_commits/index.md
index 91d3a06d7da..23d7aecc960 100644
--- a/doc/user/project/repository/gpg_signed_commits/index.md
+++ b/doc/user/project/repository/gpg_signed_commits/index.md
@@ -155,7 +155,7 @@ You can add a GPG key in your user settings:
1. In the top-right corner, select your avatar.
1. Select **Edit profile**.
-1. In the left sidebar, select **GPG Keys**.
+1. On the left sidebar, select **GPG Keys**.
1. Paste your _public_ key in the **Key** text box.
![Paste GPG public key](img/profile_settings_gpg_keys_paste_pub.png)
@@ -253,7 +253,7 @@ To revoke a GPG key:
1. In the top-right corner, select your avatar.
1. Select **Edit profile**.
-1. In the left sidebar, select **GPG Keys**.
+1. On the left sidebar, select **GPG Keys**.
1. Select **Revoke** next to the GPG key you want to delete.
## Removing a GPG key
@@ -267,7 +267,7 @@ To remove a GPG key from your account:
1. In the top-right corner, select your avatar.
1. Select **Edit profile**.
-1. In the left sidebar, select **GPG Keys**.
+1. On the left sidebar, select **GPG Keys**.
1. Select the trash icon (**{remove}**) next to the GPG key you want to delete.
## Rejecting commits that are not signed **(PREMIUM)**
diff --git a/doc/user/project/repository/repository_mirroring.md b/doc/user/project/repository/repository_mirroring.md
index 6e5fbdd140a..5a02a35fce1 100644
--- a/doc/user/project/repository/repository_mirroring.md
+++ b/doc/user/project/repository/repository_mirroring.md
@@ -613,7 +613,7 @@ If you receive this error after creating a new project using
Check if the repository owner is specified in the URL of your mirrored repository:
1. Go to your project.
-1. In the left sidebar, select **Settings > Repository**.
+1. On the left sidebar, select **Settings > Repository**.
1. Select **Mirroring repositories**.
1. If no repository owner is specified, delete and add the URL again in this format:
diff --git a/doc/user/project/web_ide/index.md b/doc/user/project/web_ide/index.md
index c5ce9364f0e..010a63b7957 100644
--- a/doc/user/project/web_ide/index.md
+++ b/doc/user/project/web_ide/index.md
@@ -294,7 +294,7 @@ Live Preview is enabled for all projects on GitLab.com. If you are an administra
of a self-managed GitLab instance, and you want to enable Live Preview:
1. On the top bar, select **Menu > Admin**.
-1. In the left sidebar, select **Settings > General**.
+1. On the left sidebar, select **Settings > General**.
1. Scroll to **Web IDE** and select **Expand**:
![Administrator Live Preview setting](img/admin_live_preview_v13_0.png)
1. Select **Enable Live Preview** and select **Save changes**.
diff --git a/lib/gitlab/pagination/offset_pagination.rb b/lib/gitlab/pagination/offset_pagination.rb
index 4f8a6ffb2cc..7b5013f137b 100644
--- a/lib/gitlab/pagination/offset_pagination.rb
+++ b/lib/gitlab/pagination/offset_pagination.rb
@@ -29,7 +29,7 @@ module Gitlab
return pagination_data unless Feature.enabled?(:api_kaminari_count_with_limit, type: :ops)
limited_total_count = pagination_data.total_count_with_limit
- if limited_total_count > Kaminari::ActiveRecordRelationMethods::MAX_COUNT_LIMIT
+ if limited_total_count > max_limit
# The call to `total_count_with_limit` memoizes `@arel` because of a call to `references_eager_loaded_tables?`
# We need to call `reset` because `without_count` relies on `@arel` being unmemoized
pagination_data.reset.without_count
@@ -38,6 +38,14 @@ module Gitlab
end
end
+ def max_limit
+ if Feature.enabled?(:lower_relation_max_count_limit, type: :ops)
+ Kaminari::ActiveRecordRelationMethods::MAX_COUNT_NEW_LOWER_LIMIT
+ else
+ Kaminari::ActiveRecordRelationMethods::MAX_COUNT_LIMIT
+ end
+ end
+
def needs_pagination?(relation)
return true unless relation.respond_to?(:current_page)
return true if params[:page].present? && relation.current_page != params[:page].to_i
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index f2be91efca0..cc356b20caa 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -11729,6 +11729,16 @@ msgstr ""
msgid "DiffsCompareBaseBranch|(base)"
msgstr ""
+msgid "Diffs|%d addition"
+msgid_plural "Diffs|%d additions"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Diffs|%d deletion"
+msgid_plural "Diffs|%d deletions"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Diffs|No file name available"
msgstr ""
@@ -11738,9 +11748,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
+msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Diffs|with %{additions} and %{deletions}"
+msgstr ""
+
msgid "Direct member"
msgstr ""
@@ -13297,6 +13315,9 @@ msgstr ""
msgid "Error: %{error_message}"
msgstr ""
+msgid "Error: Couldn't load some or all of the changes."
+msgstr ""
+
msgid "Error: No AWS credentials were supplied"
msgstr ""
@@ -13635,9 +13656,6 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
-msgid "Experienced"
-msgstr ""
-
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
@@ -16555,9 +16573,6 @@ msgstr ""
msgid "Hello %{name},"
msgstr ""
-msgid "Hello there"
-msgstr ""
-
msgid "Hello, %{name}!"
msgstr ""
@@ -18964,15 +18979,9 @@ msgstr ""
msgid "Iteration|cannot be more than 500 years in the future"
msgstr ""
-msgid "I’m familiar with the basics of DevOps."
-msgstr ""
-
msgid "I’m joining my team who’s already on GitLab"
msgstr ""
-msgid "I’m not familiar with the basics of DevOps."
-msgstr ""
-
msgid "Jaeger URL"
msgstr ""
@@ -23130,9 +23139,6 @@ msgstr ""
msgid "November"
msgstr ""
-msgid "Novice"
-msgstr ""
-
msgid "Now, personalize your GitLab experience"
msgstr ""
@@ -23825,6 +23831,9 @@ msgstr ""
msgid "PackageRegistry|Composer"
msgstr ""
+msgid "PackageRegistry|Composer.json with license: %{license} and version: %{version}"
+msgstr ""
+
msgid "PackageRegistry|Conan"
msgstr ""
@@ -23888,6 +23897,9 @@ msgstr ""
msgid "PackageRegistry|Copy require package include"
msgstr ""
+msgid "PackageRegistry|Copy target SHA"
+msgstr ""
+
msgid "PackageRegistry|Copy yarn command"
msgstr ""
@@ -24062,6 +24074,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Target SHA: %{sha}"
+msgstr ""
+
msgid "PackageRegistry|There are no other versions of this package."
msgstr ""
@@ -27825,6 +27840,9 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details."
msgstr ""
+msgid "Reload page"
+msgstr ""
+
msgid "Remediations"
msgstr ""
@@ -30905,15 +30923,9 @@ msgstr ""
msgid "Show list"
msgstr ""
-msgid "Show me advanced features"
-msgstr ""
-
msgid "Show me how to add a pipeline"
msgstr ""
-msgid "Show me the basics"
-msgstr ""
-
msgid "Show one file at a time"
msgstr ""
@@ -37698,9 +37710,6 @@ msgstr ""
msgid "Welcome to GitLab,%{br_tag}%{name}!"
msgstr ""
-msgid "Welcome to the guided GitLab tour"
-msgstr ""
-
msgid "Welcome, %{name}!"
msgstr ""
@@ -37719,9 +37728,6 @@ msgstr ""
msgid "What are you searching for?"
msgstr ""
-msgid "What describes you best?"
-msgstr ""
-
msgid "What does this command do?"
msgstr ""
@@ -37749,9 +37755,6 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "What’s your experience level?"
-msgstr ""
-
msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
msgstr ""
diff --git a/package.json b/package.json
index f72418b160b..f5f1ffbb881 100644
--- a/package.json
+++ b/package.json
@@ -57,7 +57,7 @@
"@gitlab/favicon-overlay": "2.0.0",
"@gitlab/svgs": "1.211.0",
"@gitlab/tributejs": "1.0.0",
- "@gitlab/ui": "32.9.0",
+ "@gitlab/ui": "32.9.1",
"@gitlab/visual-review-tools": "1.6.1",
"@rails/actioncable": "6.1.3-2",
"@rails/ujs": "6.1.3-2",
@@ -92,7 +92,7 @@
"@tiptap/extension-task-item": "^2.0.0-beta.17",
"@tiptap/extension-task-list": "^2.0.0-beta.17",
"@tiptap/extension-text": "^2.0.0-beta.13",
- "@tiptap/vue-2": "^2.0.0-beta.49",
+ "@tiptap/vue-2": "^2.0.0-beta.50",
"@toast-ui/editor": "^2.5.2",
"@toast-ui/vue-editor": "^2.5.2",
"apollo-cache-inmemory": "^1.6.6",
diff --git a/spec/controllers/registrations/experience_levels_controller_spec.rb b/spec/controllers/registrations/experience_levels_controller_spec.rb
deleted file mode 100644
index ad145264bb8..00000000000
--- a/spec/controllers/registrations/experience_levels_controller_spec.rb
+++ /dev/null
@@ -1,159 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Registrations::ExperienceLevelsController do
- include AfterNextHelpers
-
- let_it_be(:namespace) { create(:group, path: 'group-path' ) }
- let_it_be(:user) { create(:user) }
-
- let(:params) { { namespace_path: namespace.to_param } }
-
- describe 'GET #show' do
- subject { get :show, params: params }
-
- context 'with an unauthenticated user' do
- it { is_expected.to have_gitlab_http_status(:redirect) }
- it { is_expected.to redirect_to(new_user_session_path) }
- end
-
- context 'with an authenticated user' do
- before do
- sign_in(user)
- end
-
- it { is_expected.to have_gitlab_http_status(:ok) }
- it { is_expected.to render_template('layouts/minimal') }
- it { is_expected.to render_template(:show) }
- end
- end
-
- describe 'PUT/PATCH #update' do
- subject { patch :update, params: params }
-
- context 'with an unauthenticated user' do
- it { is_expected.to have_gitlab_http_status(:redirect) }
- it { is_expected.to redirect_to(new_user_session_path) }
- end
-
- context 'with an authenticated user' do
- let_it_be(:project) { build(:project, namespace: namespace, creator: user, path: 'project-path') }
- let_it_be(:issues_board) { build(:board, id: 123, project: project) }
-
- before do
- sign_in(user)
- end
-
- context 'when user is successfully updated' do
- context 'when no experience_level is sent' do
- before do
- user.user_preference.update_attribute(:experience_level, :novice)
- end
-
- it 'will unset the user’s experience level' do
- expect { subject }.to change { user.reload.experience_level }.to(nil)
- end
- end
-
- context 'when an expected experience level is sent' do
- let(:params) { super().merge(experience_level: :novice) }
-
- it 'sets the user’s experience level' do
- expect { subject }.to change { user.reload.experience_level }.from(nil).to('novice')
- end
- end
-
- context 'when an unexpected experience level is sent' do
- let(:params) { super().merge(experience_level: :nonexistent) }
-
- it 'raises an exception' do
- expect { subject }.to raise_error(ArgumentError, "'nonexistent' is not a valid experience_level")
- end
- end
-
- context 'when "Learn GitLab" project exists' do
- let(:learn_gitlab_available?) { true }
-
- before do
- allow_next_instance_of(LearnGitlab::Project) do |learn_gitlab|
- allow(learn_gitlab).to receive(:available?).and_return(learn_gitlab_available?)
- allow(learn_gitlab).to receive(:project).and_return(project)
- allow(learn_gitlab).to receive(:board).and_return(issues_board)
- allow(learn_gitlab).to receive(:label).and_return(double(id: 1))
- end
- end
-
- context 'redirection' do
- context 'when namespace_path param is missing' do
- let(:params) { super().merge(namespace_path: nil) }
-
- where(
- learn_gitlab_available?: [true, false]
- )
-
- with_them do
- it { is_expected.to redirect_to('/') }
- end
- end
-
- context 'when we have a namespace_path param' do
- using RSpec::Parameterized::TableSyntax
-
- where(:learn_gitlab_available?, :path) do
- true | '/group-path/project-path/-/boards/123'
- false | '/group-path'
- end
-
- with_them do
- it { is_expected.to redirect_to(path) }
- end
- end
- end
-
- context 'when novice' do
- let(:params) { super().merge(experience_level: :novice) }
-
- it 'adds a BoardLabel' do
- expect_next(Boards::UpdateService).to receive(:execute)
-
- subject
- end
- end
-
- context 'when experienced' do
- let(:params) { super().merge(experience_level: :experienced) }
-
- it 'does not add a BoardLabel' do
- expect(Boards::UpdateService).not_to receive(:new)
-
- subject
- end
- end
- end
-
- context 'when no "Learn GitLab" project exists' do
- let(:params) { super().merge(experience_level: :novice) }
-
- before do
- allow_next(LearnGitlab::Project).to receive(:available?).and_return(false)
- end
-
- it 'does not add a BoardLabel' do
- expect(Boards::UpdateService).not_to receive(:new)
-
- subject
- end
- end
- end
-
- context 'when user update fails' do
- before do
- allow_any_instance_of(User).to receive(:save).and_return(false)
- end
-
- it { is_expected.to render_template(:show) }
- end
- end
- end
-end
diff --git a/spec/features/commit_spec.rb b/spec/features/commit_spec.rb
index 80a30ab01b2..3fd613ce393 100644
--- a/spec/features/commit_spec.rb
+++ b/spec/features/commit_spec.rb
@@ -42,7 +42,7 @@ RSpec.describe 'Commit' do
visit project_commit_path(project, commit)
end
- it "shows an adjusted count for changed files on this page" do
+ it "shows an adjusted count for changed files on this page", :js do
expect(page).to have_content("Showing 1 changed file")
end
diff --git a/spec/features/projects/commits/user_browses_commits_spec.rb b/spec/features/projects/commits/user_browses_commits_spec.rb
index 76162fb800a..863fdbdadaa 100644
--- a/spec/features/projects/commits/user_browses_commits_spec.rb
+++ b/spec/features/projects/commits/user_browses_commits_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe 'User browses commits' do
sign_in(user)
end
- it 'renders commit' do
+ it 'renders commit', :js do
visit project_commit_path(project, sample_commit.id)
expect(page).to have_content(sample_commit.message.gsub(/\s+/, ' '))
@@ -103,7 +103,7 @@ RSpec.describe 'User browses commits' do
context 'when the blob does not exist' do
let(:commit) { create(:commit, project: project) }
- it 'renders successfully' do
+ it 'renders successfully', :js do
allow_next_instance_of(Gitlab::Diff::File) do |instance|
allow(instance).to receive(:blob).and_return(nil)
end
@@ -113,7 +113,9 @@ RSpec.describe 'User browses commits' do
visit(project_commit_path(project, commit))
- expect(find('.diff-file-changes', visible: false)).to have_content('files/ruby/popen.rb')
+ click_button '2 changed files'
+
+ expect(find('[data-testid="diff-stats-dropdown"]')).to have_content('files/ruby/popen.rb')
end
end
diff --git a/spec/features/registrations/experience_level_spec.rb b/spec/features/registrations/experience_level_spec.rb
deleted file mode 100644
index f432215d4a8..00000000000
--- a/spec/features/registrations/experience_level_spec.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'Experience level screen' do
- let_it_be(:user) { create(:user, :unconfirmed) }
- let_it_be(:group) { create(:group) }
-
- before do
- group.add_owner(user)
- gitlab_sign_in(user)
- visit users_sign_up_experience_level_path(namespace_path: group.to_param)
- end
-
- subject { page }
-
- it 'shows the intro content' do
- is_expected.to have_content('Hello there')
- is_expected.to have_content('Welcome to the guided GitLab tour')
- is_expected.to have_content('What describes you best?')
- end
-
- it 'shows the option for novice' do
- is_expected.to have_content('Novice')
- is_expected.to have_content('I’m not familiar with the basics of DevOps')
- is_expected.to have_content('Show me the basics')
- end
-
- it 'shows the option for experienced' do
- is_expected.to have_content('Experienced')
- is_expected.to have_content('I’m familiar with the basics of DevOps')
- is_expected.to have_content('Show me advanced features')
- end
-
- it 'does not display any flash messages' do
- is_expected.not_to have_selector('.flash-container')
- is_expected.not_to have_content("Please check your email (#{user.email}) to verify that you own this address and unlock the power of CI/CD")
- end
-
- it 'does not include the footer links' do
- is_expected.not_to have_link('Help')
- is_expected.not_to have_link('About GitLab')
- end
-end
diff --git a/spec/frontend/diffs/components/app_spec.js b/spec/frontend/diffs/components/app_spec.js
index 1464dd84666..1a9e182ee2b 100644
--- a/spec/frontend/diffs/components/app_spec.js
+++ b/spec/frontend/diffs/components/app_spec.js
@@ -183,7 +183,7 @@ describe('diffs/components/app', () => {
it('displays loading icon on batch loading', () => {
createComponent({}, ({ state }) => {
- state.diffs.isBatchLoading = true;
+ state.diffs.batchLoadingState = 'loading';
});
expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
diff --git a/spec/frontend/diffs/store/actions_spec.js b/spec/frontend/diffs/store/actions_spec.js
index 6d005b868a9..b35abc9da02 100644
--- a/spec/frontend/diffs/store/actions_spec.js
+++ b/spec/frontend/diffs/store/actions_spec.js
@@ -186,15 +186,16 @@ describe('DiffsStoreActions', () => {
{},
{ endpointBatch, diffViewType: 'inline' },
[
- { type: types.SET_BATCH_LOADING, payload: true },
+ { type: types.SET_BATCH_LOADING_STATE, payload: 'loading' },
{ type: types.SET_RETRIEVING_BATCHES, payload: true },
{ type: types.SET_DIFF_DATA_BATCH, payload: { diff_files: res1.diff_files } },
- { type: types.SET_BATCH_LOADING, payload: false },
+ { type: types.SET_BATCH_LOADING_STATE, payload: 'loaded' },
{ type: types.VIEW_DIFF_FILE, payload: 'test' },
{ type: types.SET_DIFF_DATA_BATCH, payload: { diff_files: res2.diff_files } },
- { type: types.SET_BATCH_LOADING, payload: false },
+ { type: types.SET_BATCH_LOADING_STATE, payload: 'loaded' },
{ type: types.VIEW_DIFF_FILE, payload: 'test2' },
{ type: types.SET_RETRIEVING_BATCHES, payload: false },
+ { type: types.SET_BATCH_LOADING_STATE, payload: 'error' },
],
[{ type: 'startRenderDiffsQueue' }, { type: 'startRenderDiffsQueue' }],
done,
diff --git a/spec/frontend/diffs/store/mutations_spec.js b/spec/frontend/diffs/store/mutations_spec.js
index b549ca42634..fc9ba223d5a 100644
--- a/spec/frontend/diffs/store/mutations_spec.js
+++ b/spec/frontend/diffs/store/mutations_spec.js
@@ -31,13 +31,13 @@ describe('DiffsStoreMutations', () => {
});
});
- describe('SET_BATCH_LOADING', () => {
+ describe('SET_BATCH_LOADING_STATE', () => {
it('should set loading state', () => {
const state = {};
- mutations[types.SET_BATCH_LOADING](state, false);
+ mutations[types.SET_BATCH_LOADING_STATE](state, false);
- expect(state.isBatchLoading).toEqual(false);
+ expect(state.batchLoadingState).toEqual(false);
});
});
diff --git a/spec/frontend/milestones/stores/mutations_spec.js b/spec/frontend/milestones/stores/mutations_spec.js
index 91b2acf23c5..a53d6ca5de1 100644
--- a/spec/frontend/milestones/stores/mutations_spec.js
+++ b/spec/frontend/milestones/stores/mutations_spec.js
@@ -174,6 +174,35 @@ describe('Milestones combobox Vuex store mutations', () => {
});
});
+ it('falls back to the length of list if pagination headers are missing', () => {
+ const response = {
+ data: [
+ {
+ title: 'v0.1',
+ },
+ {
+ title: 'v0.2',
+ },
+ ],
+ headers: {},
+ };
+
+ mutations[types.RECEIVE_PROJECT_MILESTONES_SUCCESS](state, response);
+
+ expect(state.matches.projectMilestones).toEqual({
+ list: [
+ {
+ title: 'v0.1',
+ },
+ {
+ title: 'v0.2',
+ },
+ ],
+ error: null,
+ totalCount: 2,
+ });
+ });
+
describe(`${types.RECEIVE_PROJECT_MILESTONES_ERROR}`, () => {
it('updates state.matches.projectMilestones to an empty state with the error object', () => {
const error = new Error('Something went wrong!');
@@ -227,6 +256,35 @@ describe('Milestones combobox Vuex store mutations', () => {
});
});
+ it('falls back to the length of data received if pagination headers are missing', () => {
+ const response = {
+ data: [
+ {
+ title: 'group-0.1',
+ },
+ {
+ title: 'group-0.2',
+ },
+ ],
+ headers: {},
+ };
+
+ mutations[types.RECEIVE_GROUP_MILESTONES_SUCCESS](state, response);
+
+ expect(state.matches.groupMilestones).toEqual({
+ list: [
+ {
+ title: 'group-0.1',
+ },
+ {
+ title: 'group-0.2',
+ },
+ ],
+ error: null,
+ totalCount: 2,
+ });
+ });
+
describe(`${types.RECEIVE_GROUP_MILESTONES_ERROR}`, () => {
it('updates state.matches.groupMilestones to an empty state with the error object', () => {
const error = new Error('Something went wrong!');
diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/additional_metadata_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/additional_metadata_spec.js
index 0504a42dfcf..e5147b0b6b1 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/details/additional_metadata_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/details/additional_metadata_spec.js
@@ -5,6 +5,7 @@ import {
mavenMetadata,
nugetMetadata,
packageData,
+ composerMetadata,
} from 'jest/packages_and_registries/package_registry/mock_data';
import component from '~/packages_and_registries/package_registry/components/details/additional_metadata.vue';
import {
@@ -12,12 +13,15 @@ import {
PACKAGE_TYPE_CONAN,
PACKAGE_TYPE_MAVEN,
PACKAGE_TYPE_NPM,
+ PACKAGE_TYPE_COMPOSER,
} from '~/packages_and_registries/package_registry/constants';
+import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import DetailsRow from '~/vue_shared/components/registry/details_row.vue';
const mavenPackage = { packageType: PACKAGE_TYPE_MAVEN, metadata: mavenMetadata() };
const conanPackage = { packageType: PACKAGE_TYPE_CONAN, metadata: conanMetadata() };
const nugetPackage = { packageType: PACKAGE_TYPE_NUGET, metadata: nugetMetadata() };
+const composerPackage = { packageType: PACKAGE_TYPE_COMPOSER, metadata: composerMetadata() };
const npmPackage = { packageType: PACKAGE_TYPE_NPM, metadata: {} };
describe('Package Additional Metadata', () => {
@@ -51,6 +55,9 @@ describe('Package Additional Metadata', () => {
const findMavenApp = () => wrapper.findByTestId('maven-app');
const findMavenGroup = () => wrapper.findByTestId('maven-group');
const findElementLink = (container) => container.findComponent(GlLink);
+ const findComposerTargetSha = () => wrapper.findByTestId('composer-target-sha');
+ const findComposerTargetShaCopyButton = () => wrapper.findComponent(ClipboardButton);
+ const findComposerJson = () => wrapper.findByTestId('composer-json');
it('has the correct title', () => {
mountComponent();
@@ -62,11 +69,12 @@ describe('Package Additional Metadata', () => {
});
it.each`
- packageEntity | visible | packageType
- ${mavenPackage} | ${true} | ${PACKAGE_TYPE_MAVEN}
- ${conanPackage} | ${true} | ${PACKAGE_TYPE_CONAN}
- ${nugetPackage} | ${true} | ${PACKAGE_TYPE_NUGET}
- ${npmPackage} | ${false} | ${PACKAGE_TYPE_NPM}
+ packageEntity | visible | packageType
+ ${mavenPackage} | ${true} | ${PACKAGE_TYPE_MAVEN}
+ ${conanPackage} | ${true} | ${PACKAGE_TYPE_CONAN}
+ ${nugetPackage} | ${true} | ${PACKAGE_TYPE_NUGET}
+ ${composerPackage} | ${true} | ${PACKAGE_TYPE_COMPOSER}
+ ${npmPackage} | ${false} | ${PACKAGE_TYPE_NPM}
`(
`It is $visible that the component is visible when the package is $packageType`,
({ packageEntity, visible }) => {
@@ -127,4 +135,29 @@ describe('Package Additional Metadata', () => {
expect(element.props('icon')).toBe(icon);
});
});
+
+ describe('composer metadata', () => {
+ beforeEach(() => {
+ mountComponent({ packageEntity: composerPackage });
+ });
+
+ it.each`
+ name | finderFunction | text | icon
+ ${'target-sha'} | ${findComposerTargetSha} | ${'Target SHA: b83d6e391c22777fca1ed3012fce84f633d7fed0'} | ${'information-o'}
+ ${'composer-json'} | ${findComposerJson} | ${'Composer.json with license: MIT and version: 1.0.0'} | ${'information-o'}
+ `('$name element', ({ finderFunction, text, icon }) => {
+ const element = finderFunction();
+ expect(element.exists()).toBe(true);
+ expect(element.text()).toBe(text);
+ expect(element.props('icon')).toBe(icon);
+ });
+
+ it('target-sha has a copy button', () => {
+ expect(findComposerTargetShaCopyButton().exists()).toBe(true);
+ expect(findComposerTargetShaCopyButton().props()).toMatchObject({
+ text: 'b83d6e391c22777fca1ed3012fce84f633d7fed0',
+ title: 'Copy target SHA',
+ });
+ });
+ });
});
diff --git a/spec/frontend/vue_shared/components/diff_stats_dropdown_spec.js b/spec/frontend/vue_shared/components/diff_stats_dropdown_spec.js
new file mode 100644
index 00000000000..04f63b4bd45
--- /dev/null
+++ b/spec/frontend/vue_shared/components/diff_stats_dropdown_spec.js
@@ -0,0 +1,176 @@
+import {
+ GlSprintf,
+ GlDropdown,
+ GlDropdownItem,
+ GlDropdownText,
+ GlSearchBoxByType,
+} from '@gitlab/ui';
+import fuzzaldrinPlus from 'fuzzaldrin-plus';
+import { nextTick } from 'vue';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import DiffStatsDropdown, { i18n } from '~/vue_shared/components/diff_stats_dropdown.vue';
+
+jest.mock('fuzzaldrin-plus', () => ({
+ filter: jest.fn().mockReturnValue([]),
+}));
+
+const mockFiles = [
+ {
+ added: 0,
+ href: '#a5cc2925ca8258af241be7e5b0381edf30266302',
+ icon: 'file-modified',
+ iconColor: '',
+ name: '',
+ path: '.gitignore',
+ removed: 3,
+ title: '.gitignore',
+ },
+ {
+ added: 1,
+ href: '#fa288d1472d29beccb489a676f68739ad365fc47',
+ icon: 'file-modified',
+ iconColor: 'danger',
+ name: 'package-lock.json',
+ path: 'lock/file/path',
+ removed: 1,
+ },
+];
+
+describe('Diff Stats Dropdown', () => {
+ let wrapper;
+
+ const createComponent = ({ changed = 0, added = 0, deleted = 0, files = [] } = {}) => {
+ wrapper = shallowMountExtended(DiffStatsDropdown, {
+ propsData: {
+ changed,
+ added,
+ deleted,
+ files,
+ },
+ stubs: {
+ GlSprintf,
+ GlDropdown,
+ },
+ });
+ };
+
+ const findChanged = () => wrapper.findComponent(GlDropdown);
+ const findChangedFiles = () => findChanged().findAllComponents(GlDropdownItem);
+ const findNoFilesText = () => findChanged().findComponent(GlDropdownText);
+ const findCollapsed = () => wrapper.findByTestId('diff-stats-additions-deletions-expanded');
+ const findExpanded = () => wrapper.findByTestId('diff-stats-additions-deletions-collapsed');
+ const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType);
+
+ describe('file item', () => {
+ beforeEach(() => {
+ createComponent({ files: mockFiles });
+ });
+
+ it('when no file name provided ', () => {
+ expect(findChangedFiles().at(0).text()).toContain(i18n.noFileNameAvailable);
+ });
+
+ it('when all file data is available', () => {
+ const fileData = findChangedFiles().at(1);
+ const fileText = findChangedFiles().at(1).text();
+ expect(fileText).toContain(mockFiles[1].name);
+ expect(fileText).toContain(mockFiles[1].path);
+ expect(fileData.props()).toMatchObject({
+ iconName: mockFiles[1].icon,
+ iconColor: mockFiles[1].iconColor,
+ });
+ });
+
+ it('when no files changed', () => {
+ createComponent({ files: [] });
+ expect(findNoFilesText().text()).toContain(i18n.noFilesFound);
+ });
+ });
+
+ describe.each`
+ changed | added | deleted | expectedDropdownHeader | expectedAddedDeletedExpanded | expectedAddedDeletedCollapsed
+ ${0} | ${0} | ${0} | ${'0 changed files'} | ${'+0 -0'} | ${'with 0 additions and 0 deletions'}
+ ${2} | ${0} | ${2} | ${'2 changed files'} | ${'+0 -2'} | ${'with 0 additions and 2 deletions'}
+ ${2} | ${2} | ${0} | ${'2 changed files'} | ${'+2 -0'} | ${'with 2 additions and 0 deletions'}
+ ${2} | ${1} | ${1} | ${'2 changed files'} | ${'+1 -1'} | ${'with 1 addition and 1 deletion'}
+ ${1} | ${0} | ${1} | ${'1 changed file'} | ${'+0 -1'} | ${'with 0 additions and 1 deletion'}
+ ${1} | ${1} | ${0} | ${'1 changed file'} | ${'+1 -0'} | ${'with 1 addition and 0 deletions'}
+ ${4} | ${2} | ${2} | ${'4 changed files'} | ${'+2 -2'} | ${'with 2 additions and 2 deletions'}
+ `(
+ 'when there are $changed changed file(s), $added added and $deleted deleted file(s)',
+ ({
+ changed,
+ added,
+ deleted,
+ expectedDropdownHeader,
+ expectedAddedDeletedExpanded,
+ expectedAddedDeletedCollapsed,
+ }) => {
+ beforeAll(() => {
+ createComponent({ changed, added, deleted });
+ });
+
+ afterAll(() => {
+ wrapper.destroy();
+ });
+
+ it(`dropdown header should be '${expectedDropdownHeader}'`, () => {
+ expect(findChanged().props('text')).toBe(expectedDropdownHeader);
+ });
+
+ it(`added and deleted count in expanded section should be '${expectedAddedDeletedExpanded}'`, () => {
+ expect(findExpanded().text()).toBe(expectedAddedDeletedExpanded);
+ });
+
+ it(`added and deleted count in collapsed section should be '${expectedAddedDeletedCollapsed}'`, () => {
+ expect(findCollapsed().text()).toBe(expectedAddedDeletedCollapsed);
+ });
+ },
+ );
+
+ describe('fuzzy file search', () => {
+ beforeEach(() => {
+ createComponent({ files: mockFiles });
+ });
+
+ it('should call `fuzzaldrinPlus.filter` to search for files when the search query is NOT empty', async () => {
+ const searchStr = 'file name';
+ findSearchBox().vm.$emit('input', searchStr);
+ await nextTick();
+ expect(fuzzaldrinPlus.filter).toHaveBeenCalledWith(mockFiles, searchStr, { key: 'name' });
+ });
+
+ it('should NOT call `fuzzaldrinPlus.filter` to search for files when the search query is empty', async () => {
+ const searchStr = '';
+ findSearchBox().vm.$emit('input', searchStr);
+ await nextTick();
+ expect(fuzzaldrinPlus.filter).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('selecting file dropdown item', () => {
+ beforeEach(() => {
+ createComponent({ files: mockFiles });
+ });
+
+ it('updates the URL ', () => {
+ findChangedFiles().at(0).vm.$emit('click');
+ expect(window.location.hash).toBe(mockFiles[0].href);
+ findChangedFiles().at(1).vm.$emit('click');
+ expect(window.location.hash).toBe(mockFiles[1].href);
+ });
+ });
+
+ describe('on dropdown open', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('should set the search input focus', () => {
+ wrapper.vm.$refs.search.focusInput = jest.fn();
+ findChanged().vm.$emit('shown');
+
+ expect(wrapper.vm.$refs.search.focusInput).toHaveBeenCalled();
+ });
+ });
+});
diff --git a/spec/lib/gitlab/pagination/offset_pagination_spec.rb b/spec/lib/gitlab/pagination/offset_pagination_spec.rb
index f8d50fbc517..ffecbb06ff8 100644
--- a/spec/lib/gitlab/pagination/offset_pagination_spec.rb
+++ b/spec/lib/gitlab/pagination/offset_pagination_spec.rb
@@ -82,7 +82,7 @@ RSpec.describe Gitlab::Pagination::OffsetPagination do
context 'when the api_kaminari_count_with_limit feature flag is enabled' do
before do
- stub_feature_flags(api_kaminari_count_with_limit: true)
+ stub_feature_flags(api_kaminari_count_with_limit: true, lower_relation_max_count_limit: false)
end
context 'when resources count is less than MAX_COUNT_LIMIT' do
@@ -120,6 +120,41 @@ RSpec.describe Gitlab::Pagination::OffsetPagination do
end
end
+ context 'when lower_relation_max_count_limit FF is enabled' do
+ before do
+ stub_feature_flags(lower_relation_max_count_limit: true)
+ end
+
+ it_behaves_like 'paginated response'
+ it_behaves_like 'response with pagination headers'
+
+ context 'when limit is met' do
+ before do
+ stub_const("::Kaminari::ActiveRecordRelationMethods::MAX_COUNT_NEW_LOWER_LIMIT", 2)
+ end
+
+ it_behaves_like 'paginated response'
+
+ it 'does not return the X-Total and X-Total-Pages headers' do
+ expect_no_header('X-Total')
+ expect_no_header('X-Total-Pages')
+ expect_header('X-Per-Page', '2')
+ expect_header('X-Page', '1')
+ expect_header('X-Next-Page', '2')
+ expect_header('X-Prev-Page', '')
+
+ expect_header('Link', anything) do |_key, val|
+ expect(val).to include(%Q(<#{incoming_api_projects_url}?#{query.merge(page: 1).to_query}>; rel="first"))
+ expect(val).to include(%Q(<#{incoming_api_projects_url}?#{query.merge(page: 2).to_query}>; rel="next"))
+ expect(val).not_to include('rel="last"')
+ expect(val).not_to include('rel="prev"')
+ end
+
+ subject.paginate(resource)
+ end
+ end
+ end
+
it 'does not return the total headers when excluding them' do
expect_no_header('X-Total')
expect_no_header('X-Total-Pages')
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 50520f9bce4..4a83d62c401 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -65,9 +65,6 @@ RSpec.describe User do
it { is_expected.to delegate_method(:render_whitespace_in_code).to(:user_preference) }
it { is_expected.to delegate_method(:render_whitespace_in_code=).to(:user_preference).with_arguments(:args) }
- it { is_expected.to delegate_method(:experience_level).to(:user_preference) }
- it { is_expected.to delegate_method(:experience_level=).to(:user_preference).with_arguments(:args) }
-
it { is_expected.to delegate_method(:markdown_surround_selection).to(:user_preference) }
it { is_expected.to delegate_method(:markdown_surround_selection=).to(:user_preference).with_arguments(:args) }
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index bc88fdfcd5d..7d4f2b69fc7 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -14,6 +14,7 @@ RSpec.describe API::Users do
let(:private_user) { create(:user, private_profile: true) }
let(:deactivated_user) { create(:user, state: 'deactivated') }
let(:banned_user) { create(:user, :banned) }
+ let(:internal_user) { create(:user, :bot) }
context 'admin notes' do
let_it_be(:admin) { create(:admin, note: '2019-10-06 | 2FA added | user requested | www.gitlab.com') }
@@ -2869,53 +2870,73 @@ RSpec.describe API::Users do
end
end
- describe 'POST /users/:id/block' do
- let(:blocked_user) { create(:user, state: 'blocked') }
+ describe 'POST /users/:id/block', :aggregate_failures do
+ context 'when admin' do
+ subject(:block_user) { post api("/users/#{user_id}/block", admin) }
- it 'blocks existing user' do
- post api("/users/#{user.id}/block", admin)
+ context 'with an existing user' do
+ let(:user_id) { user.id }
- aggregate_failures do
- expect(response).to have_gitlab_http_status(:created)
- expect(response.body).to eq('true')
- expect(user.reload.state).to eq('blocked')
+ it 'blocks existing user' do
+ block_user
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(response.body).to eq('true')
+ expect(user.reload.state).to eq('blocked')
+ end
end
- end
- it 'does not re-block ldap blocked users' do
- post api("/users/#{ldap_blocked_user.id}/block", admin)
- expect(response).to have_gitlab_http_status(:forbidden)
- expect(ldap_blocked_user.reload.state).to eq('ldap_blocked')
- end
+ context 'with an ldap blocked user' do
+ let(:user_id) { ldap_blocked_user.id }
- it 'does not be available for non admin users' do
- post api("/users/#{user.id}/block", user)
- expect(response).to have_gitlab_http_status(:forbidden)
- expect(user.reload.state).to eq('active')
- end
+ it 'does not re-block ldap blocked users' do
+ block_user
- it 'returns a 404 error if user id not found' do
- post api('/users/0/block', admin)
- expect(response).to have_gitlab_http_status(:not_found)
- expect(json_response['message']).to eq('404 User Not Found')
- end
+ expect(response).to have_gitlab_http_status(:forbidden)
+ expect(ldap_blocked_user.reload.state).to eq('ldap_blocked')
+ end
+ end
- it 'returns a 403 error if user is internal' do
- internal_user = create(:user, :bot)
+ context 'with a non existent user' do
+ let(:user_id) { non_existing_record_id }
- post api("/users/#{internal_user.id}/block", admin)
+ it 'does not block non existent user, returns 404' do
+ block_user
- expect(response).to have_gitlab_http_status(:forbidden)
- expect(json_response['message']).to eq('An internal user cannot be blocked')
- end
+ expect(response).to have_gitlab_http_status(:not_found)
+ expect(json_response['message']).to eq('404 User Not Found')
+ end
+ end
- it 'returns a 201 if user is already blocked' do
- post api("/users/#{blocked_user.id}/block", admin)
+ context 'with an internal user' do
+ let(:user_id) { internal_user.id }
- aggregate_failures do
- expect(response).to have_gitlab_http_status(:created)
- expect(response.body).to eq('null')
+ it 'does not block internal user, returns 403' do
+ block_user
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ expect(json_response['message']).to eq('An internal user cannot be blocked')
+ end
end
+
+ context 'with a blocked user' do
+ let(:blocked_user) { create(:user, state: 'blocked') }
+ let(:user_id) { blocked_user.id }
+
+ it 'returns a 201 if user is already blocked' do
+ block_user
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(response.body).to eq('null')
+ end
+ end
+ end
+
+ it 'is not available for non admin users' do
+ post api("/users/#{user.id}/block", user)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ expect(user.reload.state).to eq('active')
end
end
diff --git a/spec/support/shared_examples/features/wiki/user_views_wiki_page_shared_examples.rb b/spec/support/shared_examples/features/wiki/user_views_wiki_page_shared_examples.rb
index 61feeff57bb..96df5a5f972 100644
--- a/spec/support/shared_examples/features/wiki/user_views_wiki_page_shared_examples.rb
+++ b/spec/support/shared_examples/features/wiki/user_views_wiki_page_shared_examples.rb
@@ -157,7 +157,7 @@ RSpec.shared_examples 'User views a wiki page' do
expect(page).to have_link('updated home', href: wiki_page_path(wiki, wiki_page, version_id: commit2, action: :diff))
end
- it 'between the current and the previous version of a page' do
+ it 'between the current and the previous version of a page', :js do
commit = wiki.commit
visit wiki_page_path(wiki, wiki_page, version_id: commit, action: :diff)
@@ -169,7 +169,7 @@ RSpec.shared_examples 'User views a wiki page' do
expect_diff_links(commit)
end
- it 'between two old versions of a page' do
+ it 'between two old versions of a page', :js do
wiki_page.update(message: 'latest home change', content: 'updated [another link](other-page)') # rubocop:disable Rails/SaveBang:
commit = wiki.commit('HEAD^')
visit wiki_page_path(wiki, wiki_page, version_id: commit, action: :diff)
@@ -184,7 +184,7 @@ RSpec.shared_examples 'User views a wiki page' do
expect_diff_links(commit)
end
- it 'for the oldest version of a page' do
+ it 'for the oldest version of a page', :js do
commit = wiki.commit('HEAD^')
visit wiki_page_path(wiki, wiki_page, version_id: commit, action: :diff)
diff --git a/spec/views/projects/diffs/_stats.html.haml_spec.rb b/spec/views/projects/diffs/_stats.html.haml_spec.rb
deleted file mode 100644
index f0580b50349..00000000000
--- a/spec/views/projects/diffs/_stats.html.haml_spec.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'projects/diffs/_stats.html.haml' do
- let(:project) { create(:project, :repository) }
- let(:commit) { project.commit('570e7b2abdd848b95f2f578043fc23bd6f6fd24d') }
-
- def render_view
- render partial: "projects/diffs/stats", locals: { diff_files: commit.diffs.diff_files }
- end
-
- context 'when the commit contains several changes' do
- it 'uses plural for additions' do
- render_view
-
- expect(rendered).to have_text('additions')
- end
-
- it 'uses plural for deletions' do
- render_view
- end
- end
-
- context 'when the commit contains no addition and no deletions' do
- let(:commit) { project.commit('4cd80ccab63c82b4bad16faa5193fbd2aa06df40') }
-
- it 'uses plural for additions' do
- render_view
-
- expect(rendered).to have_text('additions')
- end
-
- it 'uses plural for deletions' do
- render_view
-
- expect(rendered).to have_text('deletions')
- end
- end
-
- context 'when the commit contains exactly one addition and one deletion' do
- let(:commit) { project.commit('08f22f255f082689c0d7d39d19205085311542bc') }
-
- it 'uses singular for additions' do
- render_view
-
- expect(rendered).to have_text('addition')
- expect(rendered).not_to have_text('additions')
- end
-
- it 'uses singular for deletions' do
- render_view
-
- expect(rendered).to have_text('deletion')
- expect(rendered).not_to have_text('deletions')
- end
- end
-end
diff --git a/yarn.lock b/yarn.lock
index 5122daee396..19f3c5aeee1 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -974,10 +974,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/tributejs/-/tributejs-1.0.0.tgz#672befa222aeffc83e7d799b0500a7a4418e59b8"
integrity sha512-nmKw1+hB6MHvlmPz63yPwVs1qQkycHwsKgxpEbzmky16Y6mL4EJMk3w1b8QlOAF/AIAzjCERPhe/R4MJiohbZw==
-"@gitlab/ui@32.9.0":
- version "32.9.0"
- resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-32.9.0.tgz#12e226e9c2a29c15d94c4d107619f78192621c15"
- integrity sha512-eb9Cz80qrZuoun+JluDND4+kAzrgYjtG5WtSDsfHXVpBOpQ6SE7tr8sMxWl/F9eASSq1+fAitC78kX5Myrq78Q==
+"@gitlab/ui@32.9.1":
+ version "32.9.1"
+ resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-32.9.1.tgz#a02a21c772cd1b9bb7f929764d587082724f8d4c"
+ integrity sha512-Cx9BGC5KJ1KPphRC+J90GPxDATTf3s1y01VMgXngXPB2ZJMl75aue3swBOsAmgre91NL4RUqiG+TJMmMCs3xuA==
dependencies:
"@babel/standalone" "^7.0.0"
bootstrap-vue "2.18.1"
@@ -1501,10 +1501,10 @@
resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-2.0.0-beta.15.tgz#cf9ddb3fc316be9707753ad4e497bfb8a3ebb0c2"
integrity sha512-jKyV6iiwhxwa0+7uuKD74jNDVNLNOS1GmU14MgaA95pY5e1fyaRBPPX8Gtt89niz2CLOY711AV17RPZTe/e60w==
-"@tiptap/extension-bubble-menu@^2.0.0-beta.32":
- version "2.0.0-beta.32"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.0.0-beta.32.tgz#5f9358c775760bac057c444c1a52a3bfe54358e5"
- integrity sha512-ZrP7yoYBTEZZg5L612jIRzGwwmuV5Jf68cHlPaMY4R11F5wn2Z+J/v+QcJUuRxEtIraUFnL03IV0VWJC7gUMSg==
+"@tiptap/extension-bubble-menu@^2.0.0-beta.33":
+ version "2.0.0-beta.33"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.0.0-beta.33.tgz#50ee84c25118f7ee932385961211b64496355c74"
+ integrity sha512-EvXSXyeLFnOAEPvbVz9B4ppP+paDGyK/Fy9b36fkH0hacFLS/lKb/8HrfTXItc0uZIe6xY6RhXTdkx1eAPTdTA==
dependencies:
prosemirror-state "^1.3.4"
prosemirror-view "^1.20.0"
@@ -1554,10 +1554,10 @@
"@types/prosemirror-dropcursor" "^1.0.3"
prosemirror-dropcursor "^1.3.5"
-"@tiptap/extension-floating-menu@^2.0.0-beta.26":
- version "2.0.0-beta.26"
- resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-2.0.0-beta.26.tgz#949672fd16820b2cd695d93189814d9f9f6e9468"
- integrity sha512-qxC9ndyLf/H0H8ilVBGczOF66gFMUmQBqhZJ15hQpRFPeNNUMbLjn9Hka/BLNcQ83ypGN/mulXADIRuD9o6VhA==
+"@tiptap/extension-floating-menu@^2.0.0-beta.27":
+ version "2.0.0-beta.27"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-2.0.0-beta.27.tgz#692686854116823be624028fd8d73aa900cf71a9"
+ integrity sha512-PgoqO5OxBDMFZroXFD7mpwfDLxeG44xFHu6WK4Gf3O8jqGAQpEr4rMKyTnoNL9PYFhEwtNBzxUopumOT0Po/zQ==
dependencies:
prosemirror-state "^1.3.4"
prosemirror-view "^1.20.0"
@@ -1687,13 +1687,13 @@
resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.0.0-beta.13.tgz#da0af8d9a3f149d20076e15d88c6af21fb6d940f"
integrity sha512-0EtAwuRldCAoFaL/iXgkRepEeOd55rPg5N4FQUN1xTwZT7PDofukP0DG/2jff/Uj17x4uTaJAa9qlFWuNnDvjw==
-"@tiptap/vue-2@^2.0.0-beta.49":
- version "2.0.0-beta.49"
- resolved "https://registry.yarnpkg.com/@tiptap/vue-2/-/vue-2-2.0.0-beta.49.tgz#4511ce8099c6f7e8e086430b22f0be0898029290"
- integrity sha512-kHEsJGo3puqi9kyJj86DvorNFqUl4xICguB1Hhwv5PbeRbFN8aiIjM7I8xElfL6KCoIsWGeBIJJILHZ4YlIMrA==
+"@tiptap/vue-2@^2.0.0-beta.50":
+ version "2.0.0-beta.50"
+ resolved "https://registry.yarnpkg.com/@tiptap/vue-2/-/vue-2-2.0.0-beta.50.tgz#1c1c3e7d696aaa167fc776e11b393b182f1bfbb4"
+ integrity sha512-o325eQbSoxxd6QXc27Mjd+T+yj1CnSTo0IQkbjbzYure8E0ReYXzW2wx5oE6DZA43Ejss2KPXZDEgiUNYRyX1Q==
dependencies:
- "@tiptap/extension-bubble-menu" "^2.0.0-beta.32"
- "@tiptap/extension-floating-menu" "^2.0.0-beta.26"
+ "@tiptap/extension-bubble-menu" "^2.0.0-beta.33"
+ "@tiptap/extension-floating-menu" "^2.0.0-beta.27"
prosemirror-view "^1.20.0"
"@toast-ui/editor@^2.5.2":