diff --git a/app/assets/javascripts/pipelines/stores/test_reports/actions.js b/app/assets/javascripts/pipelines/stores/test_reports/actions.js index f39222fe4df..34f5130a3e7 100644 --- a/app/assets/javascripts/pipelines/stores/test_reports/actions.js +++ b/app/assets/javascripts/pipelines/stores/test_reports/actions.js @@ -45,7 +45,10 @@ export const fetchTestSuite = ({ state, commit, dispatch }, index) => { const { name = '', build_ids = [] } = state.testReports?.test_suites?.[index] || {}; // Replacing `/:suite_name.json` with the name of the suite. Including the extra characters // to ensure that we replace exactly the template part of the URL string - const endpoint = state.suiteEndpoint?.replace('/:suite_name.json', `/${name}.json`); + const endpoint = state.suiteEndpoint?.replace( + '/:suite_name.json', + `/${encodeURIComponent(name)}.json`, + ); return axios .get(endpoint, { params: { build_ids } }) diff --git a/app/assets/stylesheets/components/dashboard_skeleton.scss b/app/assets/stylesheets/components/dashboard_skeleton.scss index 64091201221..a35222bca95 100644 --- a/app/assets/stylesheets/components/dashboard_skeleton.scss +++ b/app/assets/stylesheets/components/dashboard_skeleton.scss @@ -33,7 +33,7 @@ height: $gl-padding-32; &-arrow { - color: $gray-300; + color: $gray-200; } &-downstream { diff --git a/app/assets/stylesheets/framework/stacked_progress_bar.scss b/app/assets/stylesheets/framework/stacked_progress_bar.scss index 2d16fdf4ee7..03ef886baef 100644 --- a/app/assets/stylesheets/framework/stacked_progress_bar.scss +++ b/app/assets/stylesheets/framework/stacked_progress_bar.scss @@ -40,7 +40,7 @@ color: $gl-gray-dark; &:hover { - background-color: $gray-300; + background-color: $gray-200; } } diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss index b5b86b807a6..b002ced9393 100644 --- a/app/assets/stylesheets/framework/typography.scss +++ b/app/assets/stylesheets/framework/typography.scss @@ -187,7 +187,7 @@ tr { th { - border-bottom: solid 2px $gray-300; + border-bottom: solid 2px $gray-200; } } diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index 265dceb3c61..f7c0617a135 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -165,7 +165,7 @@ $gray-10: #fafafa !default; $gray-50: #f0f0f0 !default; $gray-100: #dbdbdb !default; $gray-200: #bfbfbf !default; -$gray-300: #ccc !default; +$gray-300: #999 !default; $gray-400: #bababa !default; $gray-500: #a7a7a7 !default; $gray-600: #919191 !default; diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss index 57ad9abef4b..6fc2cccc8fd 100644 --- a/app/assets/stylesheets/pages/pipelines.scss +++ b/app/assets/stylesheets/pages/pipelines.scss @@ -809,7 +809,7 @@ &.ci-status-icon-created, &.ci-status-icon-skipped { - @include mini-pipeline-graph-color($white, $gray-100, $gray-300, $gray-500, $gray-600, $gray-700); + @include mini-pipeline-graph-color($white, $gray-100, $gray-200, $gray-500, $gray-600, $gray-700); } } diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml index 7c6c21bc509..271ab12037e 100644 --- a/app/views/admin/dashboard/index.html.haml +++ b/app/views/admin/dashboard/index.html.haml @@ -1,15 +1,15 @@ - breadcrumb_title _("Dashboard") - page_title _("Dashboard") -- if show_license_breakdown? - = render_if_exists 'admin/licenses/breakdown', license: @license - - if @notices - @notices.each do |notice| .js-vue-alert{ 'v-cloak': true, data: { variant: notice[:type], dismissible: true.to_s } } = notice[:message].html_safe +- if show_license_breakdown? + = render_if_exists 'admin/licenses/breakdown', license: @license + .admin-dashboard.gl-mt-3 .row .col-sm-4 diff --git a/doc/api/README.md b/doc/api/README.md index b07f14b5a7a..f5b89a2a27a 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -218,6 +218,7 @@ Only available to [administrators](../user/permissions.md). All API requests support performing an API call as if you were another user, provided you are authenticated as an administrator with an OAuth or Personal Access Token that has the `sudo` scope. +The API requests are executed with the permissions of the impersonated user. You need to pass the `sudo` parameter either via query string or a header with an ID/username of the user you want to perform the operation as. If passed as a header, the diff --git a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb index ad87ee173f5..b2d57e902cb 100644 --- a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb +++ b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb @@ -15,7 +15,7 @@ module QA disable_optional_jobs(project) end - describe 'Auto DevOps support', :orchestrated, :kubernetes do + describe 'Auto DevOps support', :orchestrated, :kubernetes, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/230927', type: :stale } do context 'when rbac is enabled' do let(:cluster) { Service::KubernetesCluster.new.create! } diff --git a/qa/qa/specs/features/browser_ui/8_monitor/all_monitor_core_features_spec.rb b/qa/qa/specs/features/browser_ui/8_monitor/all_monitor_core_features_spec.rb index de80b47e8b1..1eef6c06cd8 100644 --- a/qa/qa/specs/features/browser_ui/8_monitor/all_monitor_core_features_spec.rb +++ b/qa/qa/specs/features/browser_ui/8_monitor/all_monitor_core_features_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module QA - RSpec.describe 'Monitor' do + RSpec.describe 'Monitor', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/230927', type: :stale } do describe 'with Prometheus in a Gitlab-managed cluster', :orchestrated, :kubernetes, :requires_admin do before :all do @cluster = Service::KubernetesCluster.new(provider_class: Service::ClusterProvider::K3s).create! diff --git a/spec/frontend/diffs/components/diff_stats_spec.js b/spec/frontend/diffs/components/diff_stats_spec.js index 5956b478019..2bf1dd2f961 100644 --- a/spec/frontend/diffs/components/diff_stats_spec.js +++ b/spec/frontend/diffs/components/diff_stats_spec.js @@ -2,39 +2,46 @@ import { shallowMount } from '@vue/test-utils'; import DiffStats from '~/diffs/components/diff_stats.vue'; import Icon from '~/vue_shared/components/icon.vue'; +const TEST_ADDED_LINES = 100; +const TEST_REMOVED_LINES = 200; +const DIFF_FILES_LENGTH = 300; + describe('diff_stats', () => { - it('does not render a group if diffFileLengths is empty', () => { - const wrapper = shallowMount(DiffStats, { + let wrapper; + + const createComponent = (props = {}) => { + wrapper = shallowMount(DiffStats, { propsData: { - addedLines: 1, - removedLines: 2, + addedLines: TEST_ADDED_LINES, + removedLines: TEST_REMOVED_LINES, + ...props, }, }); - const groups = wrapper.findAll('.diff-stats-group'); + }; - expect(groups.length).toBe(2); - }); + describe('diff stats group', () => { + const findDiffStatsGroup = () => wrapper.findAll('.diff-stats-group'); - it('does not render a group if diffFileLengths is not a number', () => { - const wrapper = shallowMount(DiffStats, { - propsData: { - addedLines: 1, - removedLines: 2, + it('is not rendered if diffFileLengths is empty', () => { + createComponent(); + + expect(findDiffStatsGroup().length).toBe(2); + }); + + it('is not rendered if diffFileLengths is not a number', () => { + createComponent({ diffFilesLength: Number.NaN, - }, - }); - const groups = wrapper.findAll('.diff-stats-group'); + }); - expect(groups.length).toBe(2); + expect(findDiffStatsGroup().length).toBe(2); + }); }); - it('shows amount of files changed, lines added and lines removed when passed all props', () => { - const wrapper = shallowMount(DiffStats, { - propsData: { - addedLines: 100, - removedLines: 200, - diffFilesLength: 300, - }, + describe('amount displayed', () => { + beforeEach(() => { + createComponent({ + diffFilesLength: DIFF_FILES_LENGTH, + }); }); const findFileLine = name => wrapper.find(name); @@ -43,12 +50,17 @@ describe('diff_stats', () => { .findAll(Icon) .filter(c => c.attributes('name') === name) .at(0).element.parentNode; - const additions = findFileLine('.js-file-addition-line'); - const deletions = findFileLine('.js-file-deletion-line'); - const filesChanged = findIcon('doc-code'); - expect(additions.text()).toBe('100'); - expect(deletions.text()).toBe('200'); - expect(filesChanged.textContent).toContain('300'); + it('shows the amount of lines added', () => { + expect(findFileLine('.js-file-addition-line').text()).toBe(TEST_ADDED_LINES.toString()); + }); + + it('shows the amount of lines removed', () => { + expect(findFileLine('.js-file-deletion-line').text()).toBe(TEST_REMOVED_LINES.toString()); + }); + + it('shows the amount of files changed', () => { + expect(findIcon('doc-code').textContent).toContain(DIFF_FILES_LENGTH); + }); }); }); diff --git a/spec/frontend/pipelines/test_reports/stores/actions_spec.js b/spec/frontend/pipelines/test_reports/stores/actions_spec.js index 41175959de5..4346447c684 100644 --- a/spec/frontend/pipelines/test_reports/stores/actions_spec.js +++ b/spec/frontend/pipelines/test_reports/stores/actions_spec.js @@ -159,6 +159,35 @@ describe('Actions TestReports Store', () => { testAction(actions.fetchTestSuite, index, { ...state, testReports }, [], [], done); }); }); + + describe('when the suite name has a `/` in it', () => { + it('sets test suite, shows tests, and encodes the suite name', done => { + const index = 0; + const suite = testReports.test_suites[0]; + const { name } = suite; + const slashName = `${name}/8`; + testReports.test_suites[0].name = slashName; + const buildIds = [1]; + testReports.test_suites[0].hasFullSuite = false; + testReports.test_suites[0].build_ids = buildIds; + const endpoint = suiteEndpoint.replace(':suite_name', encodeURIComponent(slashName)); + mock + .onGet(endpoint, { params: { build_ids: buildIds } }) + .replyOnce(200, testReports.test_suites[0], {}); + + testAction( + actions.fetchTestSuite, + index, + { ...state, testReports }, + [{ type: types.SET_SUITE, payload: { suite, index } }], + [{ type: 'toggleLoading' }, { type: 'toggleLoading' }], + () => { + expect(mock.history.get.map(x => x.url)).toEqual([endpoint]); + done(); + }, + ); + }); + }); }); describe('fetch full report', () => { diff --git a/spec/views/admin/dashboard/index.html.haml_spec.rb b/spec/views/admin/dashboard/index.html.haml_spec.rb index 569a20e8f08..70fb77944cc 100644 --- a/spec/views/admin/dashboard/index.html.haml_spec.rb +++ b/spec/views/admin/dashboard/index.html.haml_spec.rb @@ -32,4 +32,13 @@ RSpec.describe 'admin/dashboard/index.html.haml' do expect(rendered).to have_content "#{Gitlab::VERSION} (#{Gitlab.revision})" end + + it 'does not include license breakdown' do + render + + expect(rendered).not_to have_content "Users in License" + expect(rendered).not_to have_content "Active Users" + expect(rendered).not_to have_content "Maximum Users" + expect(rendered).not_to have_content "Users over License" + end end