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:
authorGitLab Bot <gitlab-bot@gitlab.com>2024-01-15 15:10:21 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2024-01-15 15:10:21 +0300
commitf58a5001b9c4988d8b95178b028a3d82bb346e28 (patch)
treee6092641f71f45c88d833f66b95b91de1f0ebcb3
parent7cd86149222a2dab444a28bb999ecedd3e50e242 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.markdownlint.yml50
-rw-r--r--Gemfile.checksum2
-rw-r--r--Gemfile.lock5
-rw-r--r--app/assets/javascripts/groups/components/overview_tabs.vue27
-rw-r--r--app/assets/javascripts/pages/sessions/new/index.js2
-rw-r--r--app/assets/javascripts/pages/sessions/new/oauth_remember_me.js4
-rw-r--r--app/assets/javascripts/pages/sessions/new/preserve_url_fragment.js4
-rw-r--r--app/assets/javascripts/vue_shared/components/timezone_dropdown/timezone_dropdown.vue1
-rw-r--r--app/helpers/application_settings_helper.rb1
-rw-r--r--app/helpers/time_zone_helper.rb13
-rw-r--r--app/models/application_setting.rb6
-rw-r--r--app/models/application_setting_implementation.rb1
-rw-r--r--app/models/integrations/diffblue_cover.rb18
-rw-r--r--app/validators/json_schemas/application_setting_rate_limits.json13
-rw-r--r--app/views/admin/application_settings/_members_api_limits.html.haml21
-rw-r--r--app/views/admin/application_settings/network.html.haml2
-rw-r--r--app/views/admin/sessions/new.html.haml2
-rw-r--r--app/views/admin/sessions/two_factor.html.haml2
-rw-r--r--app/views/devise/sessions/new.html.haml33
-rw-r--r--app/views/devise/shared/_omniauth_box.html.haml3
-rw-r--r--app/views/devise/shared/_omniauth_provider_button.haml2
-rw-r--r--app/views/profiles/show.html.haml2
-rw-r--r--data/deprecations/15-3-omniauth-crowd.yml4
-rw-r--r--db/docs/agent_project_authorizations.yml13
-rw-r--r--db/docs/compliance_management_frameworks.yml10
-rw-r--r--db/docs/external_status_checks.yml10
-rw-r--r--db/docs/project_compliance_framework_settings.yml10
-rw-r--r--db/docs/project_compliance_standards_adherence.yml4
-rw-r--r--db/migrate/20240110085226_add_rate_limits_to_application_settings.rb10
-rw-r--r--db/schema_migrations/202401100852261
-rw-r--r--db/structure.sql1
-rw-r--r--doc/administration/settings/rate_limit_on_members_api.md33
-rw-r--r--doc/api/integrations.md34
-rw-r--r--doc/development/git_object_deduplication.md4
-rw-r--r--doc/update/deprecations.md34
-rw-r--r--doc/user/group/insights/img/insights_example_stacked_bar_chart_v15_4.pngbin75321 -> 0 bytes
-rw-r--r--doc/user/group/insights/index.md97
-rw-r--r--doc/user/project/insights/index.md81
-rw-r--r--lib/api/members.rb2
-rw-r--r--lib/gitlab/application_rate_limiter.rb2
-rw-r--r--locale/gitlab.pot31
-rw-r--r--spec/features/groups/show_spec.rb1
-rw-r--r--spec/features/projects/user_sorts_projects_spec.rb16
-rw-r--r--spec/frontend/fixtures/static/oauth_remember_me.html8
-rw-r--r--spec/frontend/groups/components/overview_tabs_spec.js15
-rw-r--r--spec/frontend/oauth_remember_me_spec.js8
-rw-r--r--spec/frontend/pages/sessions/new/preserve_url_fragment_spec.js6
-rw-r--r--spec/helpers/application_settings_helper_spec.rb1
-rw-r--r--spec/helpers/markup_helper_spec.rb6
-rw-r--r--spec/helpers/time_zone_helper_spec.rb23
-rw-r--r--spec/models/application_setting_spec.rb6
-rw-r--r--spec/requests/api/members_spec.rb2
-rw-r--r--spec/support/helpers/login_helpers.rb2
-rw-r--r--spec/views/admin/application_settings/network.html.haml_spec.rb8
-rw-r--r--spec/views/admin/sessions/new.html.haml_spec.rb2
55 files changed, 451 insertions, 248 deletions
diff --git a/.markdownlint.yml b/.markdownlint.yml
index 5a9e1f05e0e..4107e8d1073 100644
--- a/.markdownlint.yml
+++ b/.markdownlint.yml
@@ -1,31 +1,39 @@
---
# Base Markdownlint configuration
# Extended Markdownlint configuration in doc/.markdownlint/
+# See https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md for explanations of each rule
+# First, set the default
default: true
-first-header-h1: true
-header-style:
+
+# Per-rule settings in alphabetical order
+code-block-style: # MD046
+ style: "fenced"
+emphasis-style: false # MD049
+first-header-h1: true # MD002
+first-line-h1: false # MD041
+header-style: # MD003
style: "atx"
-ul-style:
- style: "dash"
-no-trailing-spaces: false
-line-length: false
-no-duplicate-header:
+hr-style: # MD035
+ style: "---"
+line-length: false # MD013
+link-fragments: false # MD051
+no-duplicate-header: # MD024
allow_different_nesting: true
-no-trailing-punctuation:
+no-emphasis-as-heading: false # MD036
+no-inline-html: false # MD033
+no-trailing-punctuation: # MD026
punctuation: ".,;:!。,;:!?"
-ol-prefix:
+no-trailing-spaces: false # MD009
+ol-prefix: # MD029
style: "one"
-no-inline-html: false
-hr-style:
- style: "---"
-no-emphasis-as-heading: false
-first-line-h1: false
-code-block-style:
- style: "fenced"
-emphasis-style: false
-link-fragments: false
-reference-links-images: false
-proper-names:
+reference-links-images: false # MD052
+ul-style: # MD004
+ style: "dash"
+
+# Keep this item last due to length
+proper-names: # MD044
+ code_blocks: false
+ html_elements: false
names: [
"Akismet",
"Alertmanager",
@@ -150,5 +158,3 @@ proper-names:
"YAML",
"YouTrack"
]
- code_blocks: false
- html_elements: false
diff --git a/Gemfile.checksum b/Gemfile.checksum
index 7a8040c629c..7c3fe677ea8 100644
--- a/Gemfile.checksum
+++ b/Gemfile.checksum
@@ -492,7 +492,7 @@
{"name":"rails","version":"7.0.8","platform":"ruby","checksum":"8e43af921acf766fb429126f020ec90c3b25809631f8fbdff95c3553828d5867"},
{"name":"rails-controller-testing","version":"1.0.5","platform":"ruby","checksum":"741448db59366073e86fc965ba403f881c636b79a2c39a48d0486f2607182e94"},
{"name":"rails-dom-testing","version":"2.0.3","platform":"ruby","checksum":"b140c4f39f6e609c8113137b9a60dfc2ecb89864e496f87f23a68b3b8f12d8d1"},
-{"name":"rails-html-sanitizer","version":"1.5.0","platform":"ruby","checksum":"bf326075e8a968cd882c30b15a4c9100059be3af2356093dc68324ec3bd9ea79"},
+{"name":"rails-html-sanitizer","version":"1.6.0","platform":"ruby","checksum":"86e9f19d2e6748890dcc2633c8945ca45baa08a1df9d8c215ce17b3b0afaa4de"},
{"name":"rails-i18n","version":"7.0.3","platform":"ruby","checksum":"e3158e98c5332d129fd5131f171ac575eb30dbb8919b21595382b08850cf2bd3"},
{"name":"railties","version":"7.0.8","platform":"ruby","checksum":"12325c3933efd33f8ead640197dec3b8c27c8d45607dd68b7b925896bf09cc69"},
{"name":"rainbow","version":"3.1.1","platform":"ruby","checksum":"039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a"},
diff --git a/Gemfile.lock b/Gemfile.lock
index ba111827700..c7be326191a 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1324,8 +1324,9 @@ GEM
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
- rails-html-sanitizer (1.5.0)
- loofah (~> 2.19, >= 2.19.1)
+ rails-html-sanitizer (1.6.0)
+ loofah (~> 2.21)
+ nokogiri (~> 1.14)
rails-i18n (7.0.3)
i18n (>= 0.7, < 2)
railties (>= 6.0.0, < 8)
diff --git a/app/assets/javascripts/groups/components/overview_tabs.vue b/app/assets/javascripts/groups/components/overview_tabs.vue
index 8781f03a412..82bd4765986 100644
--- a/app/assets/javascripts/groups/components/overview_tabs.vue
+++ b/app/assets/javascripts/groups/components/overview_tabs.vue
@@ -1,5 +1,5 @@
<script>
-import { GlTabs, GlTab, GlSearchBoxByType, GlSorting, GlSortingItem } from '@gitlab/ui';
+import { GlTabs, GlTab, GlSearchBoxByType, GlSorting } from '@gitlab/ui';
import { isString, debounce } from 'lodash';
import { __ } from '~/locale';
import { DEBOUNCE_DELAY } from '~/vue_shared/components/filtered_search_bar/constants';
@@ -30,7 +30,6 @@ export default {
GroupsApp,
GlSearchBoxByType,
GlSorting,
- GlSortingItem,
SubgroupsAndProjectsEmptyState,
SharedProjectsEmptyState,
ArchivedProjectsEmptyState,
@@ -84,6 +83,9 @@ export default {
sortQueryStringValue() {
return this.isAscending ? this.sort.asc : this.sort.desc;
},
+ activeTabSortOptions() {
+ return this.activeTab.sortingItems.map(({ label }) => ({ value: label, text: label }));
+ },
},
mounted() {
this.search = this.$route.query?.filter || '';
@@ -178,12 +180,14 @@ export default {
this.handleSearchOrSortChange();
},
- handleSortingItemClick(sortingItem) {
- if (sortingItem === this.sort) {
+ handleSortingItemClick(value) {
+ const selectedSortingItem = this.activeTab.sortingItems.find((item) => item.label === value);
+
+ if (selectedSortingItem === this.sort) {
return;
}
- this.sort = sortingItem;
+ this.sort = selectedSortingItem;
this.handleSearchOrSortChange();
},
@@ -239,16 +243,11 @@ export default {
data-testid="group_sort_by_dropdown"
:text="sort.label"
:is-ascending="isAscending"
+ :sort-options="activeTabSortOptions"
+ :sort-by="sort.label"
+ @sortByChange="handleSortingItemClick"
@sortDirectionChange="handleSortDirectionChange"
- >
- <gl-sorting-item
- v-for="sortingItem in activeTab.sortingItems"
- :key="sortingItem.label"
- :active="sortingItem === sort"
- @click="handleSortingItemClick(sortingItem)"
- >{{ sortingItem.label }}</gl-sorting-item
- >
- </gl-sorting>
+ />
</div>
</div>
</li>
diff --git a/app/assets/javascripts/pages/sessions/new/index.js b/app/assets/javascripts/pages/sessions/new/index.js
index 32df2911a48..ee1a7633a11 100644
--- a/app/assets/javascripts/pages/sessions/new/index.js
+++ b/app/assets/javascripts/pages/sessions/new/index.js
@@ -16,7 +16,7 @@ new SigninTabsMemoizer(); // eslint-disable-line no-new
new NoEmojiValidator(); // eslint-disable-line no-new
new OAuthRememberMe({
- container: $('.omniauth-container'),
+ container: $('.js-oauth-login'),
}).bindEvents();
// Save the URL fragment from the current window location. This will be present if the user was
diff --git a/app/assets/javascripts/pages/sessions/new/oauth_remember_me.js b/app/assets/javascripts/pages/sessions/new/oauth_remember_me.js
index bad8a7cedc6..3336b094560 100644
--- a/app/assets/javascripts/pages/sessions/new/oauth_remember_me.js
+++ b/app/assets/javascripts/pages/sessions/new/oauth_remember_me.js
@@ -20,8 +20,8 @@ export default class OAuthRememberMe {
toggleRememberMe(event) {
const rememberMe = $(event.target).is(':checked');
- $('.js-oauth-login', this.container).each((i, element) => {
- const $form = $(element).parent('form');
+ $('.js-oauth-login form', this.container).each((_, form) => {
+ const $form = $(form);
const href = $form.attr('action');
if (rememberMe) {
diff --git a/app/assets/javascripts/pages/sessions/new/preserve_url_fragment.js b/app/assets/javascripts/pages/sessions/new/preserve_url_fragment.js
index 70e5e336e78..54ec3c52f62 100644
--- a/app/assets/javascripts/pages/sessions/new/preserve_url_fragment.js
+++ b/app/assets/javascripts/pages/sessions/new/preserve_url_fragment.js
@@ -12,7 +12,7 @@ export default function preserveUrlFragment(fragment = '') {
// Append the fragment to all sign-in/sign-up form actions so it is preserved when the user is
// eventually redirected back to the originally requested URL.
- const forms = document.querySelectorAll('#signin-container .tab-content form');
+ const forms = document.querySelectorAll('.js-non-oauth-login form');
Array.prototype.forEach.call(forms, (form) => {
const actionWithFragment = setUrlFragment(form.getAttribute('action'), `#${normalFragment}`);
form.setAttribute('action', actionWithFragment);
@@ -20,7 +20,7 @@ export default function preserveUrlFragment(fragment = '') {
// Append a redirect_fragment query param to all oauth provider links. The redirect_fragment
// query param will be available in the omniauth callback upon successful authentication
- const oauthForms = document.querySelectorAll('#signin-container .omniauth-container form');
+ const oauthForms = document.querySelectorAll('.js-oauth-login form');
Array.prototype.forEach.call(oauthForms, (oauthForm) => {
const newHref = mergeUrlParams(
{ redirect_fragment: normalFragment },
diff --git a/app/assets/javascripts/vue_shared/components/timezone_dropdown/timezone_dropdown.vue b/app/assets/javascripts/vue_shared/components/timezone_dropdown/timezone_dropdown.vue
index 6764ad4ce73..d4d241b12ec 100644
--- a/app/assets/javascripts/vue_shared/components/timezone_dropdown/timezone_dropdown.vue
+++ b/app/assets/javascripts/vue_shared/components/timezone_dropdown/timezone_dropdown.vue
@@ -110,6 +110,7 @@ export default {
:no-results-text="$options.translations.noResultsText"
:selected="tzValue"
block
+ fluid-width
searchable
@search="setSearchTerm"
@select="selectTimezone"
diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb
index b9a59047238..1affdd8f433 100644
--- a/app/helpers/application_settings_helper.rb
+++ b/app/helpers/application_settings_helper.rb
@@ -450,6 +450,7 @@ module ApplicationSettingsHelper
:issues_create_limit,
:notes_create_limit,
:notes_create_limit_allowlist_raw,
+ :members_delete_limit,
:raw_blob_request_limit,
:project_import_limit,
:project_export_limit,
diff --git a/app/helpers/time_zone_helper.rb b/app/helpers/time_zone_helper.rb
index 29bd5a84651..3ea043557b8 100644
--- a/app/helpers/time_zone_helper.rb
+++ b/app/helpers/time_zone_helper.rb
@@ -33,6 +33,19 @@ module TimeZoneHelper
end
end
+ # The identifiers in `timezone_data` are not unique. Some cities (e.g. London and Edinburgh) have
+ # the same `identifier` value (e.g. "Europe/London").
+ # This method merges such entries into one, joining the city names.
+ # This unique list is better suited for selectboxes etc.
+ def timezone_data_with_unique_identifiers(format: :short)
+ timezone_data(format: format)
+ .group_by { |entry| entry[:identifier] }
+ .map do |_identifier, entries|
+ names = entries.map { |entry| entry[:name] }.sort.join(', ') # rubocop:disable Rails/Pluck -- Not a ActiveRecord object
+ entries.first.merge({ name: names })
+ end
+ end
+
def local_timezone_instance(timezone)
return Time.zone if timezone.blank?
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index 71dc5521a4d..35d4722b711 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -579,6 +579,7 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
:max_import_size,
:max_pages_custom_domains_per_project,
:max_terraform_state_size_bytes,
+ :members_delete_limit,
:notes_create_limit,
:package_registry_cleanup_policies_worker_capacity,
:packages_cleanup_package_file_worker_capacity,
@@ -594,6 +595,11 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
:users_get_by_id_limit
end
+ jsonb_accessor :rate_limits,
+ members_delete_limit: [:integer, { default: 60 }]
+
+ validates :rate_limits, json_schema: { filename: "application_setting_rate_limits" }
+
validates :search_rate_limit_allowlist,
length: { maximum: 100, message: N_('is too long (maximum is 100 entries)') },
allow_nil: false
diff --git a/app/models/application_setting_implementation.rb b/app/models/application_setting_implementation.rb
index e18476bbae6..d1899b18a4f 100644
--- a/app/models/application_setting_implementation.rb
+++ b/app/models/application_setting_implementation.rb
@@ -137,6 +137,7 @@ module ApplicationSettingImplementation
mirror_available: true,
notes_create_limit: 300,
notes_create_limit_allowlist: [],
+ members_delete_limit: 60,
notify_on_unknown_sign_in: true,
outbound_local_requests_whitelist: [],
password_authentication_enabled_for_git: true,
diff --git a/app/models/integrations/diffblue_cover.rb b/app/models/integrations/diffblue_cover.rb
index 888aa9a5ffd..c0e0cae2b33 100644
--- a/app/models/integrations/diffblue_cover.rb
+++ b/app/models/integrations/diffblue_cover.rb
@@ -6,7 +6,7 @@ module Integrations
section: SECTION_TYPE_CONNECTION,
type: :password,
title: -> { s_('DiffblueCover|License key') },
- description: -> { s_('DiffblueCover|Diffblue Cover license key') },
+ description: -> { s_('DiffblueCover|Diffblue Cover license key.') },
non_empty_password_title: -> { s_('DiffblueCover|License key') },
non_empty_password_help: -> {
s_(
@@ -21,7 +21,7 @@ module Integrations
format(
s_(
'DiffblueCover|Enter your Diffblue Cover license key or ' \
- 'visit %{diffblue_link} to obtain a free trial license.'
+ 'go to %{diffblue_link} to obtain a free trial license.'
),
diffblue_link: diffblue_link
)
@@ -30,7 +30,7 @@ module Integrations
field :diffblue_access_token_name,
section: SECTION_TYPE_CONFIGURATION,
title: -> { s_('DiffblueCover|Name') },
- description: -> { s_('DiffblueCover|Access token name used by Diffblue Cover in pipelines') },
+ description: -> { s_('DiffblueCover|Access token name used by Diffblue Cover in pipelines.') },
required: true,
placeholder: -> { s_('DiffblueCover|My token name') }
@@ -38,7 +38,7 @@ module Integrations
section: SECTION_TYPE_CONFIGURATION,
type: :password,
title: -> { s_('DiffblueCover|Secret') },
- description: -> { s_('DiffblueCover|Access token secret used by Diffblue Cover in pipelines') },
+ description: -> { s_('DiffblueCover|Access token secret used by Diffblue Cover in pipelines.') },
non_empty_password_title: -> { s_('DiffblueCover|Secret') },
non_empty_password_help: -> { s_('DiffblueCover|Leave blank to use your current secret value.') },
required: true,
@@ -82,8 +82,8 @@ module Integrations
title: s_('DiffblueCover|Integration details'),
description:
s_(
- 'DiffblueCover|Diffblue Cover is a reinforcement learning AI platform that automatically ' \
- 'writes comprehensive, human-like Java unit tests. Integrate the power of Diffblue ' \
+ 'DiffblueCover|Diffblue Cover is a generative AI platform that automatically ' \
+ 'writes comprehensive, human-like Java unit tests. Integrate Diffblue ' \
'Cover into your CI/CD workflow for fully autonomous operation.'
)
},
@@ -91,9 +91,9 @@ module Integrations
type: SECTION_TYPE_CONFIGURATION,
title: s_('DiffblueCover|Access token'),
description:
- 'A GitLab access token is required in allow Diffblue Cover to access your project. ' \
- 'Use a GitLab access token with a <code>Developer</code> role, plus ' \
- '<code>api</code> and <code>write_repository</code> scopes.'
+ 'You must have a GitLab access token for Diffblue Cover to access your project. ' \
+ 'Use a GitLab access token with at least the Developer role and ' \
+ 'the <code>api</code> and <code>write_repository</code> permissions.'
}
]
end
diff --git a/app/validators/json_schemas/application_setting_rate_limits.json b/app/validators/json_schemas/application_setting_rate_limits.json
new file mode 100644
index 00000000000..e74295291df
--- /dev/null
+++ b/app/validators/json_schemas/application_setting_rate_limits.json
@@ -0,0 +1,13 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "description": "Application rate limits",
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "members_delete_limit": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "Number of project or group members a user can delete per minute."
+ }
+ }
+}
diff --git a/app/views/admin/application_settings/_members_api_limits.html.haml b/app/views/admin/application_settings/_members_api_limits.html.haml
new file mode 100644
index 00000000000..3065c62b7e2
--- /dev/null
+++ b/app/views/admin/application_settings/_members_api_limits.html.haml
@@ -0,0 +1,21 @@
+%section.settings.as-members-api-limits.no-animate#js-members-api-limits-settings{ class: ('expanded' if expanded_by_default?) }
+ .settings-header
+ %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
+ = _('Members API rate limit')
+ = render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do
+ = expanded_by_default? ? _('Collapse') : _('Expand')
+ %p.gl-text-secondary
+ = _('Limit the number of project or group members a user can delete per minute through API requests.')
+ = link_to _('Learn more.'), help_page_path('administration/settings/rate_limit_on_members_api'), target: '_blank', rel: 'noopener noreferrer'
+ .settings-content
+ = gitlab_ui_form_for @application_setting, url: network_admin_application_settings_path(anchor: 'js-members-api-limits-settings'), html: { class: 'fieldset-form' } do |f|
+ = form_errors(@application_setting)
+
+ %fieldset
+ .form-group
+ = f.label :members_delete_limit, _('Maximum requests per minute per group / project'), class: 'label-bold'
+ = f.number_field :members_delete_limit, min: 0, class: 'form-control gl-form-input'
+ .form-text.gl-text-gray-600
+ = _("Set to 0 to disable the limit.")
+
+ = f.submit _('Save changes'), pajamas_button: true
diff --git a/app/views/admin/application_settings/network.html.haml b/app/views/admin/application_settings/network.html.haml
index ae5f7a5cec3..c2f19c11b4e 100644
--- a/app/views/admin/application_settings/network.html.haml
+++ b/app/views/admin/application_settings/network.html.haml
@@ -151,6 +151,8 @@
= render 'projects_api_limits'
+= render 'members_api_limits'
+
%section.settings.as-import-export-limits.no-animate#js-import-export-limits-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
diff --git a/app/views/admin/sessions/new.html.haml b/app/views/admin/sessions/new.html.haml
index 8ba5329d15e..e2f5ef5d786 100644
--- a/app/views/admin/sessions/new.html.haml
+++ b/app/views/admin/sessions/new.html.haml
@@ -4,7 +4,7 @@
.row.gl-mt-5.justify-content-center
.col-md-5
.login-page
- #signin-container.borderless
+ .borderless
- if any_form_based_providers_enabled?
= render 'devise/shared/tabs_ldap', show_password_form: allow_admin_mode_password_authentication_for_web?, render_signup_link: false
.tab-content
diff --git a/app/views/admin/sessions/two_factor.html.haml b/app/views/admin/sessions/two_factor.html.haml
index 4b78a6ce748..898d47f446a 100644
--- a/app/views/admin/sessions/two_factor.html.haml
+++ b/app/views/admin/sessions/two_factor.html.haml
@@ -4,7 +4,7 @@
.row.justify-content-center
.col-md-5
.login-page
- #signin-container.borderless
+ .borderless
.login-box.gl-p-5
.login-body
- if current_user.two_factor_enabled?
diff --git a/app/views/devise/sessions/new.html.haml b/app/views/devise/sessions/new.html.haml
index c7cbf09d846..728728ea653 100644
--- a/app/views/devise/sessions/new.html.haml
+++ b/app/views/devise/sessions/new.html.haml
@@ -9,26 +9,23 @@
= render_if_exists "layouts/google_tag_manager_body"
-#signin-container
+.js-non-oauth-login
- if any_form_based_providers_enabled?
= render 'devise/shared/tabs_ldap', render_signup_link: false
.tab-content
- if password_authentication_enabled_for_web? || ldap_sign_in_enabled? || crowd_enabled?
= render 'devise/shared/signin_box'
-
- -# Show a message if none of the mechanisms above are enabled
- - if !password_authentication_enabled_for_web? && !ldap_sign_in_enabled? && !(omniauth_enabled? && devise_mapping.omniauthable?)
- %div
- = _('No authentication methods configured.')
-
- - if Gitlab::CurrentSettings.current_application_settings.terms
- %p.gl-px-5
- = html_escape(s_("SignUp|By signing in you accept the %{link_start}Terms of Use and acknowledge the Privacy Statement and Cookie Policy%{link_end}.")) % { link_start: "<a href='#{terms_path}' target='_blank' rel='noreferrer noopener'>".html_safe,
- link_end: '</a>'.html_safe }
-
- - if allow_signup?
- %p.gl-mt-3.gl-text-center
- = _("Don't have an account yet?")
- = link_to _("Register now"), new_registration_path(:user, invite_email: @invite_email), data: { testid: 'register-link' }
- - if omniauth_enabled? && devise_mapping.omniauthable? && button_based_providers_enabled?
- = render 'devise/shared/omniauth_box'
+-# Show a message if none of the mechanisms above are enabled
+- if !password_authentication_enabled_for_web? && !ldap_sign_in_enabled? && !(omniauth_enabled? && devise_mapping.omniauthable?)
+ %div
+ = _('No authentication methods configured.')
+- if Gitlab::CurrentSettings.current_application_settings.terms
+ %p.gl-px-5
+ = html_escape(s_("SignUp|By signing in you accept the %{link_start}Terms of Use and acknowledge the Privacy Statement and Cookie Policy%{link_end}.")) % { link_start: "<a href='#{terms_path}' target='_blank' rel='noreferrer noopener'>".html_safe,
+ link_end: '</a>'.html_safe }
+- if allow_signup?
+ %p.gl-mt-3.gl-text-center
+ = _("Don't have an account yet?")
+ = link_to _("Register now"), new_registration_path(:user, invite_email: @invite_email), data: { testid: 'register-link' }
+- if omniauth_enabled? && devise_mapping.omniauthable? && button_based_providers_enabled?
+ = render 'devise/shared/omniauth_box'
diff --git a/app/views/devise/shared/_omniauth_box.html.haml b/app/views/devise/shared/_omniauth_box.html.haml
index be559b30ce9..8197abcc787 100644
--- a/app/views/devise/shared/_omniauth_box.html.haml
+++ b/app/views/devise/shared/_omniauth_box.html.haml
@@ -4,12 +4,11 @@
.omniauth-divider.gl-display-flex.gl-align-items-center
= _("or sign in with")
-.gl-mt-5.gl-px-5.omniauth-container.gl-text-center.gl-display-flex.gl-flex-direction-column.gl-gap-3
+.gl-mt-5.gl-px-5.gl-text-center.gl-display-flex.gl-flex-direction-column.gl-gap-3.js-oauth-login
- enabled_button_based_providers.each do |provider|
= render 'devise/shared/omniauth_provider_button',
href: omniauth_authorize_path(:user, provider),
provider: provider,
- classes: 'js-oauth-login',
data: { testid: test_id_for_provider(provider) },
id: "oauth-login-#{provider}"
- if render_remember_me
diff --git a/app/views/devise/shared/_omniauth_provider_button.haml b/app/views/devise/shared/_omniauth_provider_button.haml
index e92b41a6254..c33e2253bb1 100644
--- a/app/views/devise/shared/_omniauth_provider_button.haml
+++ b/app/views/devise/shared/_omniauth_provider_button.haml
@@ -1,4 +1,4 @@
-- button_options = { class: classes, data: data, id: id }
+- button_options = { class: local_assigns.fetch(:classes, nil) || nil, data: data, id: id }
= render Pajamas::ButtonComponent.new(href: href, method: :post, form: true, block: true, button_options: button_options) do
- if provider_has_icon?(provider)
diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml
index 79b2726ed2d..9f33ad0c2d4 100644
--- a/app/views/profiles/show.html.haml
+++ b/app/views/profiles/show.html.haml
@@ -66,7 +66,7 @@
%h4.gl-my-0= s_("Profiles|Time settings")
%p.gl-text-secondary= s_("Profiles|Set your local time zone.")
= f.label :user_timezone, _("Time zone")
- .js-timezone-dropdown{ data: { timezone_data: timezone_data.to_json, initial_value: @user.timezone, name: 'user[timezone]' } }
+ .js-timezone-dropdown{ data: { timezone_data: timezone_data_with_unique_identifiers.to_json, initial_value: @user.timezone, name: 'user[timezone]' } }
.settings-section.js-search-settings-section.gl-border-t.gl-pt-6
.settings-sticky-header
diff --git a/data/deprecations/15-3-omniauth-crowd.yml b/data/deprecations/15-3-omniauth-crowd.yml
index 7c28226a674..2230bbd17ed 100644
--- a/data/deprecations/15-3-omniauth-crowd.yml
+++ b/data/deprecations/15-3-omniauth-crowd.yml
@@ -3,13 +3,13 @@
#
- title: "Atlassian Crowd OmniAuth provider" # (required) The name of the feature to be deprecated
announcement_milestone: "15.3" # (required) The milestone when this feature was first announced as deprecated.
- removal_milestone: "17.0" # (required) The milestone when this feature is planned to be removed
+ removal_milestone: "18.0" # (required) The milestone when this feature is planned to be removed
breaking_change: true # (required) If this deprecation is a breaking change, set this value to true
reporter: hsutor # (required) GitLab username of the person reporting the deprecation
stage: Manage # (required) String value of the stage that the feature was created in. e.g., Growth
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/369117 # (required) Link to the deprecation issue in GitLab
body: | # (required) Do not modify this line, instead modify the lines below.
The `omniauth_crowd` gem that provides GitLab with the Atlassian Crowd OmniAuth provider will be removed in our
- next major release, GitLab 16.0. This gem sees very little use and its
+ next major release, GitLab 18.0. This gem sees very little use and its
[lack of compatibility](https://github.com/robdimarco/omniauth_crowd/issues/37) with OmniAuth 2.0 is
[blocking our upgrade](https://gitlab.com/gitlab-org/gitlab/-/issues/30073).
diff --git a/db/docs/agent_project_authorizations.yml b/db/docs/agent_project_authorizations.yml
index 77c26571c28..144598b8109 100644
--- a/db/docs/agent_project_authorizations.yml
+++ b/db/docs/agent_project_authorizations.yml
@@ -4,7 +4,16 @@ classes:
- Clusters::Agents::Authorizations::CiAccess::ProjectAuthorization
feature_categories:
- deployment_management
-description: Configuration for a project that is authorized to use a particular cluster agent
+description: Configuration for a project that is authorized to use a particular cluster
+ agent
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67295
milestone: '14.3'
-gitlab_schema: gitlab_main
+gitlab_schema: gitlab_main_cell
+allow_cross_joins:
+- gitlab_main_clusterwide
+allow_cross_transactions:
+- gitlab_main_clusterwide
+allow_cross_foreign_keys:
+- gitlab_main_clusterwide
+sharding_key:
+ project_id: projects
diff --git a/db/docs/compliance_management_frameworks.yml b/db/docs/compliance_management_frameworks.yml
index 9a75e43a938..40697a5a28b 100644
--- a/db/docs/compliance_management_frameworks.yml
+++ b/db/docs/compliance_management_frameworks.yml
@@ -7,4 +7,12 @@ feature_categories:
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/44098
milestone: '13.5'
-gitlab_schema: gitlab_main
+gitlab_schema: gitlab_main_cell
+allow_cross_joins:
+- gitlab_main_clusterwide
+allow_cross_transactions:
+- gitlab_main_clusterwide
+allow_cross_foreign_keys:
+- gitlab_main_clusterwide
+sharding_key:
+ namespace_id: namespaces
diff --git a/db/docs/external_status_checks.yml b/db/docs/external_status_checks.yml
index 5f7ea9b5314..c8263d921bf 100644
--- a/db/docs/external_status_checks.yml
+++ b/db/docs/external_status_checks.yml
@@ -7,4 +7,12 @@ feature_categories:
description: Stores project's external status checks
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/62186
milestone: '14.0'
-gitlab_schema: gitlab_main
+gitlab_schema: gitlab_main_cell
+allow_cross_joins:
+- gitlab_main_clusterwide
+allow_cross_transactions:
+- gitlab_main_clusterwide
+allow_cross_foreign_keys:
+- gitlab_main_clusterwide
+sharding_key:
+ project_id: projects
diff --git a/db/docs/project_compliance_framework_settings.yml b/db/docs/project_compliance_framework_settings.yml
index ab68259e87e..3a9d82dfb27 100644
--- a/db/docs/project_compliance_framework_settings.yml
+++ b/db/docs/project_compliance_framework_settings.yml
@@ -7,4 +7,12 @@ feature_categories:
description: TODO
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28182
milestone: '13.0'
-gitlab_schema: gitlab_main
+gitlab_schema: gitlab_main_cell
+allow_cross_joins:
+- gitlab_main_clusterwide
+allow_cross_transactions:
+- gitlab_main_clusterwide
+allow_cross_foreign_keys:
+- gitlab_main_clusterwide
+sharding_key:
+ project_id: projects
diff --git a/db/docs/project_compliance_standards_adherence.yml b/db/docs/project_compliance_standards_adherence.yml
index 78fbf8a8a46..0eae8b3fbb6 100644
--- a/db/docs/project_compliance_standards_adherence.yml
+++ b/db/docs/project_compliance_standards_adherence.yml
@@ -1,10 +1,12 @@
---
table_name: project_compliance_standards_adherence
classes:
- - Projects::ComplianceStandards::Adherence
+- Projects::ComplianceStandards::Adherence
feature_categories:
- compliance_management
description: Stores the details about projects and their adherence to compliance standards
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/122293
milestone: '16.1'
gitlab_schema: gitlab_main_cell
+sharding_key:
+ project_id: projects
diff --git a/db/migrate/20240110085226_add_rate_limits_to_application_settings.rb b/db/migrate/20240110085226_add_rate_limits_to_application_settings.rb
new file mode 100644
index 00000000000..2560977f979
--- /dev/null
+++ b/db/migrate/20240110085226_add_rate_limits_to_application_settings.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+class AddRateLimitsToApplicationSettings < Gitlab::Database::Migration[2.2]
+ milestone '16.9'
+ enable_lock_retries!
+
+ def change
+ add_column :application_settings, :rate_limits, :jsonb, default: {}, null: false
+ end
+end
diff --git a/db/schema_migrations/20240110085226 b/db/schema_migrations/20240110085226
new file mode 100644
index 00000000000..35e3cc7237a
--- /dev/null
+++ b/db/schema_migrations/20240110085226
@@ -0,0 +1 @@
+9c9eb37365dae73fb68000d18675a280e063711eaed8f96f64724bff20326957 \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index b7368d8b289..793fa64b53e 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -12633,6 +12633,7 @@ CREATE TABLE application_settings (
lock_toggle_security_policy_custom_ci boolean DEFAULT false NOT NULL,
toggle_security_policies_policy_scope boolean DEFAULT false NOT NULL,
lock_toggle_security_policies_policy_scope boolean DEFAULT false NOT NULL,
+ rate_limits jsonb DEFAULT '{}'::jsonb NOT NULL,
CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)),
CONSTRAINT app_settings_container_registry_pre_import_tags_rate_positive CHECK ((container_registry_pre_import_tags_rate >= (0)::numeric)),
CONSTRAINT app_settings_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)),
diff --git a/doc/administration/settings/rate_limit_on_members_api.md b/doc/administration/settings/rate_limit_on_members_api.md
new file mode 100644
index 00000000000..3e8868adc91
--- /dev/null
+++ b/doc/administration/settings/rate_limit_on_members_api.md
@@ -0,0 +1,33 @@
+---
+stage: Data Stores
+group: Tenant Scale
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Rate limit on Members API **(FREE SELF)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/140633) in GitLab 16.9.
+
+You can configure the rate limit per group (or project) per user to the
+[delete members API](../../api/members.md#remove-a-member-from-a-group-or-project).
+
+To change the rate limit:
+
+1. On the left sidebar, at the bottom, select **Admin Area**.
+1. Select **Settings > Network**.
+1. Expand **Members API rate limit**.
+1. In the **Maximum requests per minute per group / project** text box, enter the new value.
+1. Select **Save changes**.
+
+The rate limit:
+
+- Applies per group or project per user.
+- Can be set to 0 to disable rate limiting.
+
+The default value of the rate limit is `60`.
+
+Requests over the rate limit are logged into the `auth.log` file.
+
+For example, if you set a limit of 60, requests sent to the
+[delete members API](../../api/members.md#remove-a-member-from-a-group-or-project) exceeding a rate of 300 per minute
+are blocked. Access to the endpoint is allowed after one minute.
diff --git a/doc/api/integrations.md b/doc/api/integrations.md
index 9aec4e0b17d..3e2286fa0a5 100644
--- a/doc/api/integrations.md
+++ b/doc/api/integrations.md
@@ -462,6 +462,40 @@ Get the Datadog integration settings for a project.
GET /projects/:id/integrations/datadog
```
+## Diffblue Cover
+
+### Set up Diffblue Cover
+
+Set up the Diffblue Cover integration for a project.
+
+```plaintext
+PUT /projects/:id/integrations/diffblue-cover
+```
+
+Parameters:
+
+| Parameter | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `diffblue_license_key` | string | true | Diffblue Cover license key. |
+| `diffblue_access_token_name` | string | true | Access token name used by Diffblue Cover in pipelines. |
+| `diffblue_access_token_secret` | string | true | Access token secret used by Diffblue Cover in pipelines. |
+
+### Disable Diffblue Cover
+
+Disable the Diffblue Cover integration for a project. Integration settings are reset.
+
+```plaintext
+DELETE /projects/:id/integrations/diffblue-cover
+```
+
+### Get Diffblue Cover settings
+
+Get the Diffblue Cover integration settings for a project.
+
+```plaintext
+GET /projects/:id/integrations/diffblue-cover
+```
+
## Discord Notifications
### Set up Discord Notifications
diff --git a/doc/development/git_object_deduplication.md b/doc/development/git_object_deduplication.md
index f3e35f9cdf8..5bfa77e2aa3 100644
--- a/doc/development/git_object_deduplication.md
+++ b/doc/development/git_object_deduplication.md
@@ -42,7 +42,7 @@ repositories that depend on the object pool.
The danger lies in `git prune`, and `git gc` calls `git prune`. The
problem is that `git prune`, when running in a pool repository, cannot
-reliable decide if an object is no longer needed.
+reliably decide if an object is no longer needed.
### Git alternates in GitLab: pool repositories
@@ -51,7 +51,7 @@ which are hidden from the user. We then use Git
alternates to let a collection of project repositories borrow from a
single pool repository. We call such a collection of project
repositories a pool. Pools form star-shaped networks of repositories
-that borrow from a single pool, which resemble (but not be
+that borrow from a single pool, which resemble (but are not
identical to) the fork networks that get formed when users fork
projects.
diff --git a/doc/update/deprecations.md b/doc/update/deprecations.md
index 02fd4b3454e..a7eb061fa47 100644
--- a/doc/update/deprecations.md
+++ b/doc/update/deprecations.md
@@ -52,6 +52,23 @@ For deprecation reviewers (Technical Writers only):
<div class="deprecation breaking-change" data-milestone="18.0">
+### Atlassian Crowd OmniAuth provider
+
+<div class="deprecation-notes">
+- Announced in GitLab <span class="milestone">15.3</span>
+- Removal in GitLab <span class="milestone">18.0</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
+- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/369117).
+</div>
+
+The `omniauth_crowd` gem that provides GitLab with the Atlassian Crowd OmniAuth provider will be removed in our
+next major release, GitLab 18.0. This gem sees very little use and its
+[lack of compatibility](https://github.com/robdimarco/omniauth_crowd/issues/37) with OmniAuth 2.0 is
+[blocking our upgrade](https://gitlab.com/gitlab-org/gitlab/-/issues/30073).
+
+</div>
+
+<div class="deprecation breaking-change" data-milestone="18.0">
+
### GitLab Runner registration token in Runner Operator
<div class="deprecation-notes">
@@ -194,23 +211,6 @@ From GitLab 18.0 and later, the methods to register runners introduced by the ne
<div class="deprecation breaking-change" data-milestone="17.0">
-### Atlassian Crowd OmniAuth provider
-
-<div class="deprecation-notes">
-- Announced in GitLab <span class="milestone">15.3</span>
-- Removal in GitLab <span class="milestone">17.0</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
-- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/369117).
-</div>
-
-The `omniauth_crowd` gem that provides GitLab with the Atlassian Crowd OmniAuth provider will be removed in our
-next major release, GitLab 16.0. This gem sees very little use and its
-[lack of compatibility](https://github.com/robdimarco/omniauth_crowd/issues/37) with OmniAuth 2.0 is
-[blocking our upgrade](https://gitlab.com/gitlab-org/gitlab/-/issues/30073).
-
-</div>
-
-<div class="deprecation breaking-change" data-milestone="17.0">
-
### Auto DevOps support for Herokuish is deprecated
<div class="deprecation-notes">
diff --git a/doc/user/group/insights/img/insights_example_stacked_bar_chart_v15_4.png b/doc/user/group/insights/img/insights_example_stacked_bar_chart_v15_4.png
deleted file mode 100644
index f7963c170e1..00000000000
--- a/doc/user/group/insights/img/insights_example_stacked_bar_chart_v15_4.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/group/insights/index.md b/doc/user/group/insights/index.md
index ad93e783b88..0cb1ad093a5 100644
--- a/doc/user/group/insights/index.md
+++ b/doc/user/group/insights/index.md
@@ -1,94 +1,11 @@
---
-stage: Plan
-group: Optimize
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
+redirect_to: '../../project/insights/index.md'
+remove_date: '2024-04-20'
---
-# Insights for groups **(ULTIMATE ALL)**
+This document was moved to [another location](../../project/insights/index.md).
-> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/725) in GitLab 12.0.
-
-Configure insights to explore data about you group's activity, such as
-triage hygiene, issues created or closed in a given period, and average time for merge
-requests to be merged.
-You can also create custom insights reports that are relevant for your group.
-
-## View group insights
-
-Prerequisites:
-
-- You must have [permission](../../permissions.md#group-members-permissions) to view the group.
-- You must have access to a project to view information about its merge requests and issues,
- and permission to view them if they are confidential.
-
-To access your group's insights:
-
-1. On the left sidebar, select **Search or go to** and find your group.
-1. Select **Analyze > Insights**.
-
-## Interact with insights charts
-
-You can interact with the insights charts to view details about your group's activity.
-
-![Insights example stacked bar chart](img/insights_example_stacked_bar_chart_v15_4.png)
-
-### Display different reports
-
-To display one of the available reports on the insights page, from the **Select report** dropdown list,
-select the report you want to display.
-
-### View bar chart annotations
-
-To view annotations, hover over each bar in the chart.
-
-### Zoom in on chart
-
-Insights display data from the last 90 days. You can zoom in to display data only from a subset of the 90-day range.
-
-To do this, select the pause icons (**{status-paused}**) and slide them along the horizontal axis:
-
-- To change the start date, slide the left pause icon to the left or right.
-- To change the end date, slide the right pause icon to the left or right.
-
-### Exclude dimensions from charts
-
-By default, insights display all available dimensions on the chart.
-
-To exclude a dimension, from the legend below the chart, select the name of the dimension.
-
-### Drill down on charts
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/372215/) in GitLab 16.7.
-
-You can drill down into the data of the **Bugs created per month by priority** and **Bugs created per month by severity** charts from the [default configuration file](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/fixtures/insights/default.yml).
-
-To view a drill-down report of the data for a specific priority or severity in a month:
-
-- On the chart, select the bar stack you want to drill down on.
-
-## Configure group insights
-
-GitLab reads insights from the
-[default configuration file](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/fixtures/insights/default.yml).
-
-To configure group insights:
-
-1. Create a new file [`.gitlab/insights.yml`](../../project/insights/index.md#configure-project-insights)
- in a project that belongs to your group.
-1. On the left sidebar, select **Search or go to** and find your group.
-1. Select **Settings > General**.
-1. Expand **Analytics** and find the **Insights** section.
-1. Select the project that contains your `.gitlab/insights.yml` configuration file.
-1. Select **Save changes**.
-
-<!-- ## Troubleshooting
-
-Include any troubleshooting steps that you can foresee. If you know beforehand what issues
-one might have when setting this up, or when something is changed, or on upgrading, it's
-important to describe those, too. Think of things that may go wrong and include them here.
-This is important to minimize requests for support, and to avoid doc comments with
-questions that you know someone might ask.
-
-Each scenario can be a third-level heading, for example `### Getting error message X`.
-If you have none to add when creating a doc, leave this section in place
-but commented out to help encourage others to add to it in the future. -->
+<!-- This redirect file can be deleted after <YYYY-MM-DD>. -->
+<!-- Redirects that point to other docs in the same project expire in three months. -->
+<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
+<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
diff --git a/doc/user/project/insights/index.md b/doc/user/project/insights/index.md
index 8a91a0c4621..b7addb5131f 100644
--- a/doc/user/project/insights/index.md
+++ b/doc/user/project/insights/index.md
@@ -4,27 +4,28 @@ group: Optimize
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Insights for projects **(ULTIMATE ALL)**
+# Insights **(ULTIMATE ALL)**
-Configure project insights to explore data such as:
+> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/725) in GitLab 12.0.
+
+Configure insights for your projects and groups to explore data such as:
- Issues created and closed during a specified period.
- Average time for merge requests to be merged.
- Triage hygiene.
-Insights are also available for [groups](../../group/insights/index.md).
+You can also create custom Insights reports that are relevant for your group.
## View project insights
Prerequisites:
-- You must have:
- - Access to a project to view information about its merge requests and issues.
- - Permission to view confidential merge requests and issues in the project.
+- For project insights, you must have access to the project and permission to view information about its merge requests and issues.
+- For group insights, you must have permission to view the group.
-To view project insights:
+To view insights for a project or group:
-1. On the left sidebar, select **Search or go to** and find your project.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Analyze > Insights**.
1. To view a report, select the **Select report** dropdown list.
@@ -35,23 +36,61 @@ You can direct users to a specific report in Insights by using the deep-linked U
To create a deep link, append the report key to the end of the Insights report URL.
For example, a GitLab report with the key `bugsCharts` has the deep link URL `https://gitlab.com/gitlab-org/gitlab/insights/#/bugsCharts`.
+## Interact with Insights charts
+
+You can interact with the insights charts to view details about your group's activity.
+
+### Display different reports
+
+To display one of the available reports on the insights page, from the **Select report** dropdown list,
+select the report you want to display.
+
+### View bar chart annotations
+
+To view annotations, hover over each bar in the chart.
+
+### Zoom in on chart
+
+Insights display data from the last 90 days. You can zoom in to display data only from a subset of the 90-day range.
+
+To do this, select the pause icons (**{status-paused}**) and slide them along the horizontal axis:
+
+- To change the start date, slide the left pause icon to the left or right.
+- To change the end date, slide the right pause icon to the left or right.
+
+### Exclude dimensions from charts
+
+By default, insights display all available dimensions on the chart.
+
+To exclude a dimension, from the legend below the chart, select the name of the dimension.
+
+### Drill down on charts
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/372215/) in GitLab 16.7.
+
+You can drill down into the data of the **Bugs created per month by priority** and **Bugs created per month by severity** charts from the [default configuration file](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/fixtures/insights/default.yml).
+
+To view a drill-down report of the data for a specific priority or severity in a month:
+
+- On the chart, select the bar stack you want to drill down on.
+
## Configure project insights
Prerequisites:
- Depending on your project configuration, you must have at least the Developer role.
-Project insights are configured with the [`.gitlab/insights.yml`](#insights-configuration-file) file in the project. If a project doesn't have a configuration file, it uses the [group configuration](../../group/insights/index.md#configure-group-insights).
+Project insights are configured with the [`.gitlab/insights.yml`](#insights-configuration-file) file in the project. If a project doesn't have a configuration file, it uses the [group configuration](#configure-group-insights).
The `.gitlab/insights.yml` file is a YAML file where you define:
- The structure and order of charts in a report.
- The style of charts displayed in the report of your project or group.
-To configure project insights, either:
+To configure project insights, create a file `.gitlab/insights.yml` either:
-- Create a `.gitlab/insights.yml` file locally in the root directory of your project, and push your changes.
-- Create a `.gitlab/insights.yml` file in the UI:
+- Locally, in the root directory of your project, and push your changes.
+- From the UI:
1. On the left sidebar, select **Search or go to** and find your project.
1. Above the file list, select the branch you want to commit to, select the plus icon, then select **New file**.
1. In the **File name** text box, enter `.gitlab/insights.yml`.
@@ -59,7 +98,21 @@ To configure project insights, either:
1. Select **Commit changes**.
After you create the configuration file, you can also
-[use it for the project's group](../../group/insights/index.md#configure-group-insights).
+use it for the project's group.
+
+## Configure group insights
+
+GitLab reads insights from the
+[default configuration file](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/fixtures/insights/default.yml).
+
+To configure group insights:
+
+1. In a project that belongs to your group, [create a `.gitlab/insights.yml` file](#configure-project-insights).
+1. On the left sidebar, select **Search or go to** and find your group.
+1. Select **Settings > General**.
+1. Expand **Analytics** and find the **Insights** section.
+1. Select the project that contains your `.gitlab/insights.yml` configuration file.
+1. Select **Save changes**.
## Insights configuration file
@@ -403,7 +456,7 @@ Use `query.environment_tiers` to define an array of environments to include the
Use `projects` to limit where issuables are queried from:
-- If `.gitlab/insights.yml` is used for a [group's insights](../../group/insights/index.md#configure-group-insights), use `projects` to define the projects from which to query issuables. By default, all projects under the group are used.
+- If `.gitlab/insights.yml` is used for a group's insights, use `projects` to define the projects from which to query issuables. By default, all projects under the group are used.
- If `.gitlab/insights.yml` is used for a project's insights, specifying other projects does not yield results. By default, the project is used.
#### `projects.only`
diff --git a/lib/api/members.rb b/lib/api/members.rb
index 56a15c41e1c..908733d4aa1 100644
--- a/lib/api/members.rb
+++ b/lib/api/members.rb
@@ -176,7 +176,7 @@ module API
source = find_source(source_type, params[:id])
member = source_members(source).find_by!(user_id: params[:user_id])
- check_rate_limit!(:member_delete, scope: [source, current_user])
+ check_rate_limit!(:members_delete, scope: [source, current_user])
destroy_conditionally!(member) do
::Members::DestroyService.new(current_user).execute(member, skip_subresources: params[:skip_subresources], unassign_issuables: params[:unassign_issuables])
diff --git a/lib/gitlab/application_rate_limiter.rb b/lib/gitlab/application_rate_limiter.rb
index df7f2986304..5a2881e6c96 100644
--- a/lib/gitlab/application_rate_limiter.rb
+++ b/lib/gitlab/application_rate_limiter.rb
@@ -30,7 +30,7 @@ module Gitlab
group_download_export: { threshold: -> { application_settings.group_download_export_limit }, interval: 1.minute },
group_import: { threshold: -> { application_settings.group_import_limit }, interval: 1.minute },
group_testing_hook: { threshold: 5, interval: 1.minute },
- member_delete: { threshold: 60, interval: 1.minute },
+ members_delete: { threshold: -> { application_settings.members_delete_limit }, interval: 1.minute },
profile_add_new_email: { threshold: 5, interval: 1.minute },
web_hook_calls: { interval: 1.minute },
web_hook_calls_mid: { interval: 1.minute },
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index fab424dc159..b41845620a1 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -16658,6 +16658,9 @@ msgstr ""
msgid "Dependencies|Export as JSON"
msgstr ""
+msgid "Dependencies|Filtering unavailable"
+msgstr ""
+
msgid "Dependencies|Job failed to generate the dependency list"
msgstr ""
@@ -16682,6 +16685,9 @@ msgstr ""
msgid "Dependencies|Projects"
msgstr ""
+msgid "Dependencies|Search or filter dependencies..."
+msgstr ""
+
msgid "Dependencies|Software Bill of Materials (SBOM) based on the %{linkStart}latest successful%{linkEnd} scan"
msgstr ""
@@ -16706,6 +16712,9 @@ msgstr ""
msgid "Dependencies|There was an error fetching the projects for this group. Please try again later."
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of 600 sub-groups. We cannot accurately filter or search the dependency list above this maximum. To view or filter a subset of this information, go to a subgroup's dependency list."
+msgstr ""
+
msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
msgstr ""
@@ -17733,22 +17742,22 @@ msgstr ""
msgid "DiffblueCover|Access token"
msgstr ""
-msgid "DiffblueCover|Access token name used by Diffblue Cover in pipelines"
+msgid "DiffblueCover|Access token name used by Diffblue Cover in pipelines."
msgstr ""
-msgid "DiffblueCover|Access token secret used by Diffblue Cover in pipelines"
+msgid "DiffblueCover|Access token secret used by Diffblue Cover in pipelines."
msgstr ""
msgid "DiffblueCover|Automatically write comprehensive, human-like Java unit tests."
msgstr ""
-msgid "DiffblueCover|Diffblue Cover is a reinforcement learning AI platform that automatically writes comprehensive, human-like Java unit tests. Integrate the power of Diffblue Cover into your CI/CD workflow for fully autonomous operation."
+msgid "DiffblueCover|Diffblue Cover is a generative AI platform that automatically writes comprehensive, human-like Java unit tests. Integrate Diffblue Cover into your CI/CD workflow for fully autonomous operation."
msgstr ""
-msgid "DiffblueCover|Diffblue Cover license key"
+msgid "DiffblueCover|Diffblue Cover license key."
msgstr ""
-msgid "DiffblueCover|Enter your Diffblue Cover license key or visit %{diffblue_link} to obtain a free trial license."
+msgid "DiffblueCover|Enter your Diffblue Cover license key or go to %{diffblue_link} to obtain a free trial license."
msgstr ""
msgid "DiffblueCover|Integration details"
@@ -29013,6 +29022,9 @@ msgstr ""
msgid "Limit the number of pipeline creation requests per minute. This limit includes pipelines created through the UI, the API, and by background processing."
msgstr ""
+msgid "Limit the number of project or group members a user can delete per minute through API requests."
+msgstr ""
+
msgid "Limit the size of Sidekiq jobs stored in Redis."
msgstr ""
@@ -29882,6 +29894,9 @@ msgstr ""
msgid "Maximum requests per minute"
msgstr ""
+msgid "Maximum requests per minute per group / project"
+msgstr ""
+
msgid "Maximum running slices"
msgstr ""
@@ -30071,6 +30086,9 @@ msgstr ""
msgid "Members"
msgstr ""
+msgid "Members API rate limit"
+msgstr ""
+
msgid "Members can be added by project %{i_open}Maintainers%{i_close} or %{i_open}Owners%{i_close}"
msgstr ""
@@ -43389,9 +43407,6 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter dependencies..."
-msgstr ""
-
msgid "Search or filter results…"
msgstr ""
diff --git a/spec/features/groups/show_spec.rb b/spec/features/groups/show_spec.rb
index c2ab5edf79c..553c2f0266e 100644
--- a/spec/features/groups/show_spec.rb
+++ b/spec/features/groups/show_spec.rb
@@ -81,6 +81,7 @@ RSpec.describe 'Group show page', feature_category: :groups_and_projects do
expect(find('.group-row:nth-child(1) .namespace-title > a')).to have_content(project2.title)
expect(find('.group-row:nth-child(2) .namespace-title > a')).to have_content(project1.title)
expect(find('.group-row:nth-child(3) .namespace-title > a')).to have_content(project3.title)
+ expect(page).to have_selector('button[data-testid="base-dropdown-toggle"]', text: 'Stars')
end
end
end
diff --git a/spec/features/projects/user_sorts_projects_spec.rb b/spec/features/projects/user_sorts_projects_spec.rb
index b80caca5810..3576225a417 100644
--- a/spec/features/projects/user_sorts_projects_spec.rb
+++ b/spec/features/projects/user_sorts_projects_spec.rb
@@ -10,6 +10,10 @@ RSpec.describe 'User sorts projects and order persists', feature_category: :grou
let_it_be(:group_member) { create(:group_member, :maintainer, user: user, group: group) }
let_it_be(:project) { create(:project, :public, group: group) }
+ def find_dropdown_toggle
+ find('button[data-testid=base-dropdown-toggle]')
+ end
+
shared_examples_for "sort order persists across all views" do |project_paths_label, group_paths_label|
it "is set on the dashboard_projects_path" do
visit(dashboard_projects_path)
@@ -27,7 +31,7 @@ RSpec.describe 'User sorts projects and order persists', feature_category: :grou
visit(group_canonical_path(group))
within '[data-testid=group_sort_by_dropdown]' do
- expect(find('.gl-dropdown-toggle')).to have_content(group_paths_label)
+ expect(find_dropdown_toggle).to have_content(group_paths_label)
end
end
@@ -35,7 +39,7 @@ RSpec.describe 'User sorts projects and order persists', feature_category: :grou
visit(details_group_path(group))
within '[data-testid=group_sort_by_dropdown]' do
- expect(find('.gl-dropdown-toggle')).to have_content(group_paths_label)
+ expect(find_dropdown_toggle).to have_content(group_paths_label)
end
end
end
@@ -67,8 +71,8 @@ RSpec.describe 'User sorts projects and order persists', feature_category: :grou
sign_in(user)
visit(group_canonical_path(group))
within '[data-testid=group_sort_by_dropdown]' do
- find('button.gl-dropdown-toggle').click
- first(:button, 'Created').click
+ find_dropdown_toggle.click
+ find('li', text: 'Created').click
wait_for_requests
end
end
@@ -81,8 +85,8 @@ RSpec.describe 'User sorts projects and order persists', feature_category: :grou
sign_in(user)
visit(details_group_path(group))
within '[data-testid=group_sort_by_dropdown]' do
- find('button.gl-dropdown-toggle').click
- first(:button, 'Updated').click
+ find_dropdown_toggle.click
+ find('li', text: 'Updated').click
wait_for_requests
end
end
diff --git a/spec/frontend/fixtures/static/oauth_remember_me.html b/spec/frontend/fixtures/static/oauth_remember_me.html
index 60277ecf66e..d7519dd695f 100644
--- a/spec/frontend/fixtures/static/oauth_remember_me.html
+++ b/spec/frontend/fixtures/static/oauth_remember_me.html
@@ -1,20 +1,20 @@
-<div id="oauth-container">
+<div class="js-oauth-login">
<input id="remember_me_omniauth" type="checkbox" />
<form method="post" action="http://example.com/">
- <button class="js-oauth-login twitter" type="submit">
+ <button class="twitter" type="submit">
<span>Twitter</span>
</button>
</form>
<form method="post" action="http://example.com/">
- <button class="js-oauth-login github" type="submit">
+ <button class="github" type="submit">
<span>GitHub</span>
</button>
</form>
<form method="post" action="http://example.com/?redirect_fragment=L1">
- <button class="js-oauth-login facebook" type="submit">
+ <button class="facebook" type="submit">
<span>Facebook</span>
</button>
</form>
diff --git a/spec/frontend/groups/components/overview_tabs_spec.js b/spec/frontend/groups/components/overview_tabs_spec.js
index 0ca59e9c6bf..8b80330c910 100644
--- a/spec/frontend/groups/components/overview_tabs_spec.js
+++ b/spec/frontend/groups/components/overview_tabs_spec.js
@@ -1,4 +1,4 @@
-import { GlSorting, GlSortingItem, GlTab } from '@gitlab/ui';
+import { GlSorting, GlTab } from '@gitlab/ui';
import Vue, { nextTick } from 'vue';
import AxiosMockAdapter from 'axios-mock-adapter';
import { mountExtended } from 'helpers/vue_test_utils_helper';
@@ -17,6 +17,7 @@ import {
ACTIVE_TAB_SUBGROUPS_AND_PROJECTS,
ACTIVE_TAB_SHARED,
ACTIVE_TAB_ARCHIVED,
+ OVERVIEW_TABS_SORTING_ITEMS,
SORTING_ITEM_NAME,
SORTING_ITEM_UPDATED,
SORTING_ITEM_STARS,
@@ -74,6 +75,7 @@ describe('OverviewTabs', () => {
const findTab = (name) => wrapper.findByRole('tab', { name });
const findSelectedTab = () => wrapper.findByRole('tab', { selected: true });
const findSearchInput = () => wrapper.findByPlaceholderText(OverviewTabs.i18n.searchPlaceholder);
+ const findGlSorting = () => wrapper.findComponent(GlSorting);
beforeEach(() => {
axiosMock = new AxiosMockAdapter(axios);
@@ -301,7 +303,7 @@ describe('OverviewTabs', () => {
describe('when sort is changed', () => {
beforeEach(async () => {
await setup();
- wrapper.findAllComponents(GlSortingItem).at(2).vm.$emit('click');
+ findGlSorting().vm.$emit('sortByChange', SORTING_ITEM_UPDATED.label);
await nextTick();
});
@@ -403,12 +405,15 @@ describe('OverviewTabs', () => {
});
it('sets sort dropdown', () => {
- expect(wrapper.findComponent(GlSorting).props()).toMatchObject({
+ const expectedSortOptions = OVERVIEW_TABS_SORTING_ITEMS.map(({ label }) => {
+ return { value: label, text: label };
+ });
+ expect(findGlSorting().props()).toMatchObject({
text: SORTING_ITEM_UPDATED.label,
isAscending: false,
+ sortBy: SORTING_ITEM_UPDATED.label,
+ sortOptions: expectedSortOptions,
});
-
- expect(wrapper.findAllComponents(GlSortingItem).at(2).vm.$attrs.active).toBe(true);
});
});
});
diff --git a/spec/frontend/oauth_remember_me_spec.js b/spec/frontend/oauth_remember_me_spec.js
index 33295d46fea..4fea216302f 100644
--- a/spec/frontend/oauth_remember_me_spec.js
+++ b/spec/frontend/oauth_remember_me_spec.js
@@ -5,13 +5,13 @@ import OAuthRememberMe from '~/pages/sessions/new/oauth_remember_me';
describe('OAuthRememberMe', () => {
const findFormAction = (selector) => {
- return $(`#oauth-container .js-oauth-login${selector}`).parent('form').attr('action');
+ return $(`.js-oauth-login ${selector}`).parent('form').attr('action');
};
beforeEach(() => {
setHTMLFixture(htmlOauthRememberMe);
- new OAuthRememberMe({ container: $('#oauth-container') }).bindEvents();
+ new OAuthRememberMe({ container: $('.js-oauth-login') }).bindEvents();
});
afterEach(() => {
@@ -19,7 +19,7 @@ describe('OAuthRememberMe', () => {
});
it('adds and removes the "remember_me" query parameter from all OAuth login buttons', () => {
- $('#oauth-container #remember_me_omniauth').click();
+ $('.js-oauth-login #remember_me_omniauth').click();
expect(findFormAction('.twitter')).toBe('http://example.com/?remember_me=1');
expect(findFormAction('.github')).toBe('http://example.com/?remember_me=1');
@@ -27,7 +27,7 @@ describe('OAuthRememberMe', () => {
'http://example.com/?redirect_fragment=L1&remember_me=1',
);
- $('#oauth-container #remember_me_omniauth').click();
+ $('.js-oauth-login #remember_me_omniauth').click();
expect(findFormAction('.twitter')).toBe('http://example.com/');
expect(findFormAction('.github')).toBe('http://example.com/');
diff --git a/spec/frontend/pages/sessions/new/preserve_url_fragment_spec.js b/spec/frontend/pages/sessions/new/preserve_url_fragment_spec.js
index 6ff2bb42d8d..7607381a981 100644
--- a/spec/frontend/pages/sessions/new/preserve_url_fragment_spec.js
+++ b/spec/frontend/pages/sessions/new/preserve_url_fragment_spec.js
@@ -5,7 +5,7 @@ import preserveUrlFragment from '~/pages/sessions/new/preserve_url_fragment';
describe('preserve_url_fragment', () => {
const findFormAction = (selector) => {
- return $(`.omniauth-container ${selector}`).parent('form').attr('action');
+ return $(`.js-oauth-login ${selector}`).parent('form').attr('action');
};
beforeEach(() => {
@@ -44,9 +44,7 @@ describe('preserve_url_fragment', () => {
});
it('when "remember-me" is present', () => {
- $('.js-oauth-login')
- .parent('form')
- .attr('action', (i, href) => `${href}?remember_me=1`);
+ $('.js-oauth-login form').attr('action', (i, href) => `${href}?remember_me=1`);
preserveUrlFragment('#L65');
diff --git a/spec/helpers/application_settings_helper_spec.rb b/spec/helpers/application_settings_helper_spec.rb
index 5dc75a60a6e..b378437c407 100644
--- a/spec/helpers/application_settings_helper_spec.rb
+++ b/spec/helpers/application_settings_helper_spec.rb
@@ -65,6 +65,7 @@ RSpec.describe ApplicationSettingsHelper do
project_download_export_limit project_export_limit project_import_limit
raw_blob_request_limit group_export_limit group_download_export_limit
group_import_limit users_get_by_id_limit search_rate_limit search_rate_limit_unauthenticated
+ members_delete_limit
])
end
diff --git a/spec/helpers/markup_helper_spec.rb b/spec/helpers/markup_helper_spec.rb
index 22d1113ee8c..831f41cde0a 100644
--- a/spec/helpers/markup_helper_spec.rb
+++ b/spec/helpers/markup_helper_spec.rb
@@ -461,7 +461,7 @@ RSpec.describe MarkupHelper, feature_category: :team_planning do
it 'displays the first line of a code block' do
object = create_object("```\nCode block\nwith two lines\n```")
- expected = %r{<pre.+><code><span class="line">Code block\.\.\.</span></code></pre>}
+ expected = %r{<pre.+><code><span class="line" lang="plaintext">Code block\.\.\.</span></code></pre>}
expect(helper.first_line_in_markdown(object, attribute, 100, is_todo: true, project: project)).to match(expected)
end
@@ -476,8 +476,8 @@ RSpec.describe MarkupHelper, feature_category: :team_planning do
it 'preserves code color scheme' do
object = create_object("```ruby\ndef test\n 'hello world'\nend\n```")
- expected = "\n<pre class=\"code highlight js-syntax-highlight language-ruby\">" \
- "<code><span class=\"line\"><span class=\"k\">def</span> <span class=\"nf\">test</span>...</span>" \
+ expected = "\n<pre class=\"code highlight js-syntax-highlight language-ruby\" lang=\"ruby\">" \
+ "<code><span class=\"line\" lang=\"ruby\"><span class=\"k\">def</span> <span class=\"nf\">test</span>...</span>" \
"</code></pre>\n"
expect(helper.first_line_in_markdown(object, attribute, 150, is_todo: true, project: project)).to eq(expected)
diff --git a/spec/helpers/time_zone_helper_spec.rb b/spec/helpers/time_zone_helper_spec.rb
index e8d96ee0700..95acb2ee9d9 100644
--- a/spec/helpers/time_zone_helper_spec.rb
+++ b/spec/helpers/time_zone_helper_spec.rb
@@ -93,6 +93,29 @@ RSpec.describe TimeZoneHelper, :aggregate_failures do
end
end
+ describe '#timezone_data_with_unique_identifiers' do
+ subject { helper.timezone_data_with_unique_identifiers }
+
+ before do
+ allow(helper).to receive(:timezone_data).and_return([
+ { identifier: 'Europe/London', name: 'London' },
+ { identifier: 'Europe/London', name: 'Edinburgh' },
+ { identifier: 'Europe/Berlin', name: 'Berlin' },
+ { identifier: 'Europe/London', name: 'Hogwarts' }
+
+ ])
+ end
+
+ let(:expected) do
+ [
+ { identifier: 'Europe/London', name: 'Edinburgh, Hogwarts, London' },
+ { identifier: 'Europe/Berlin', name: 'Berlin' }
+ ]
+ end
+
+ it { is_expected.to eq(expected) }
+ end
+
describe '#local_time' do
let_it_be(:timezone) { 'America/Los_Angeles' }
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb
index 9b2c14314df..b4003469ebb 100644
--- a/spec/models/application_setting_spec.rb
+++ b/spec/models/application_setting_spec.rb
@@ -28,6 +28,7 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do
it { expect(setting.decompress_archive_file_timeout).to eq(210) }
it { expect(setting.bulk_import_concurrent_pipeline_batch_limit).to eq(25) }
it { expect(setting.allow_project_creation_for_guest_and_below).to eq(true) }
+ it { expect(setting.members_delete_limit).to eq(60) }
end
describe 'validations' do
@@ -58,6 +59,8 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do
}
end
+ it { expect(described_class).to validate_jsonb_schema(['application_setting_rate_limits']) }
+
it { is_expected.to allow_value(nil).for(:home_page_url) }
it { is_expected.to allow_value(http).for(:home_page_url) }
it { is_expected.to allow_value(https).for(:home_page_url) }
@@ -225,6 +228,8 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do
max_import_size
max_pages_custom_domains_per_project
max_terraform_state_size_bytes
+ members_delete_limit
+ notes_create_limit
package_registry_cleanup_policies_worker_capacity
packages_cleanup_package_file_worker_capacity
pipeline_limit_per_project_user_sha
@@ -237,7 +242,6 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do
sidekiq_job_limiter_limit_bytes
terminal_max_session_time
users_get_by_id_limit
- notes_create_limit
]
end
diff --git a/spec/requests/api/members_spec.rb b/spec/requests/api/members_spec.rb
index feb24a4e73f..7fc58140fb6 100644
--- a/spec/requests/api/members_spec.rb
+++ b/spec/requests/api/members_spec.rb
@@ -717,7 +717,7 @@ RSpec.describe API::Members, feature_category: :groups_and_projects do
end.to change { source.members.count }.by(-1)
end
- it_behaves_like 'rate limited endpoint', rate_limit_key: :member_delete do
+ it_behaves_like 'rate limited endpoint', rate_limit_key: :members_delete do
let(:current_user) { maintainer }
let(:another_member) { create(:user) }
diff --git a/spec/support/helpers/login_helpers.rb b/spec/support/helpers/login_helpers.rb
index 91f0218732e..83849df73dc 100644
--- a/spec/support/helpers/login_helpers.rb
+++ b/spec/support/helpers/login_helpers.rb
@@ -110,7 +110,7 @@ module LoginHelpers
def login_via(provider, user, uid, remember_me: false, additional_info: {})
mock_auth_hash(provider, uid, user.email, additional_info: additional_info)
visit new_user_session_path
- expect(page).to have_css('.omniauth-container')
+ expect(page).to have_css('.js-oauth-login')
check 'remember_me_omniauth' if remember_me
diff --git a/spec/views/admin/application_settings/network.html.haml_spec.rb b/spec/views/admin/application_settings/network.html.haml_spec.rb
index 989977bac3e..193ee8a32d5 100644
--- a/spec/views/admin/application_settings/network.html.haml_spec.rb
+++ b/spec/views/admin/application_settings/network.html.haml_spec.rb
@@ -18,4 +18,12 @@ RSpec.describe 'admin/application_settings/network.html.haml', feature_category:
expect(rendered).to have_field('application_setting_projects_api_rate_limit_unauthenticated')
end
end
+
+ context 'for Members API rate limit' do
+ it 'renders the `members_delete_limit` field' do
+ render
+
+ expect(rendered).to have_field('application_setting_members_delete_limit')
+ end
+ end
end
diff --git a/spec/views/admin/sessions/new.html.haml_spec.rb b/spec/views/admin/sessions/new.html.haml_spec.rb
index 81275fa8750..73d6298c27e 100644
--- a/spec/views/admin/sessions/new.html.haml_spec.rb
+++ b/spec/views/admin/sessions/new.html.haml_spec.rb
@@ -45,7 +45,7 @@ RSpec.describe 'admin/sessions/new.html.haml' do
expect(rendered).not_to have_content _('No authentication methods configured.')
expect(rendered).to have_css('.omniauth-divider')
expect(rendered).to have_content(_('or sign in with'))
- expect(rendered).to have_css('.omniauth-container')
+ expect(rendered).to have_css('.js-oauth-login')
end
end