diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-03-22 21:15:07 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-03-22 21:15:07 +0000 |
commit | e53eae82b097308623e77a69f8cc3138cca3cf68 (patch) | |
tree | d8a99e1a3ca49739a8e7f2cad4b2f4c622c6c8c4 | |
parent | de0e57e387034634a861555b878923cd077a039f (diff) | |
download | gitlab-ce-e53eae82b097308623e77a69f8cc3138cca3cf68.tar.gz |
Add latest changes from gitlab-org/gitlab@master
-rw-r--r-- | .gitlab/ci/frontend.gitlab-ci.yml | 6 | ||||
-rw-r--r-- | GITALY_SERVER_VERSION | 2 | ||||
-rw-r--r-- | app/assets/javascripts/environments/components/new_environment_item.vue | 2 | ||||
-rw-r--r-- | app/assets/javascripts/jobs/components/job/sidebar/artifacts_block.vue | 6 | ||||
-rw-r--r-- | app/assets/stylesheets/components/related_items_list.scss | 4 | ||||
-rw-r--r-- | app/graphql/graphql_triggers.rb | 2 | ||||
-rw-r--r-- | app/views/users/show.html.haml | 301 | ||||
-rw-r--r-- | doc/administration/clusters/kas.md | 27 | ||||
-rw-r--r-- | doc/development/documentation/styleguide/word_list.md | 2 | ||||
-rw-r--r-- | doc/update/plan_your_upgrade.md | 2 | ||||
-rw-r--r-- | qa/qa/page/project/job/show.rb | 4 | ||||
-rw-r--r-- | scripts/gitlab_component_helpers.sh | 73 | ||||
-rw-r--r-- | spec/features/users/show_spec.rb | 8 | ||||
-rw-r--r-- | spec/frontend/environments/new_environment_item_spec.js | 1 | ||||
-rw-r--r-- | spec/graphql/graphql_triggers_spec.rb | 14 | ||||
-rw-r--r-- | spec/lib/banzai/filter/external_link_filter_spec.rb | 32 |
16 files changed, 279 insertions, 207 deletions
diff --git a/.gitlab/ci/frontend.gitlab-ci.yml b/.gitlab/ci/frontend.gitlab-ci.yml index 0039e117d57..88dbd1649b0 100644 --- a/.gitlab/ci/frontend.gitlab-ci.yml +++ b/.gitlab/ci/frontend.gitlab-ci.yml @@ -104,9 +104,9 @@ retrieve-frontend-fixtures: - .frontend:rules:default-frontend-jobs stage: prepare script: - - export FIXTURES_SHA="${CI_MERGE_REQUEST_TARGET_BRANCH_SHA:-${CI_MERGE_REQUEST_DIFF_BASE_SHA:-$CI_COMMIT_SHA}}" - source scripts/utils.sh - source scripts/gitlab_component_helpers.sh + - export_fixtures_sha_for_download - | if check_fixtures_download; then run_timed_command "download_and_extract_fixtures" @@ -129,9 +129,9 @@ retrieve-frontend-fixtures: CRYSTALBALL: "false" WEBPACK_VENDOR_DLL: "true" script: - - export FIXTURES_SHA="${CI_MERGE_REQUEST_TARGET_BRANCH_SHA:-${CI_MERGE_REQUEST_DIFF_BASE_SHA:-$CI_COMMIT_SHA}}" - source scripts/utils.sh - source scripts/gitlab_component_helpers.sh + - export_fixtures_sha_for_download - | if check_fixtures_download; then exit 0 @@ -186,9 +186,9 @@ upload-frontend-fixtures: stage: fixtures needs: ["rspec-all frontend_fixture"] script: - - export FIXTURES_SHA="${CI_MERGE_REQUEST_SOURCE_BRANCH_SHA:-$CI_COMMIT_SHA}" - source scripts/utils.sh - source scripts/gitlab_component_helpers.sh + - export_fixtures_sha_for_upload - 'fixtures_archive_doesnt_exist || { echoinfo "INFO: Exiting early as package exists."; exit 0; }' - run_timed_command "create_fixtures_package" - run_timed_command "upload_fixtures_package" diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index 168cb96d4c5..53d503b7d85 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -8421e7ceb0d9cb7164eb48f02b6e91a0f6d92e05 +98d26efad3a10c52e1ad20429cffb4e6605510d5 diff --git a/app/assets/javascripts/environments/components/new_environment_item.vue b/app/assets/javascripts/environments/components/new_environment_item.vue index 2ec6e12b8b3..a945e89393b 100644 --- a/app/assets/javascripts/environments/components/new_environment_item.vue +++ b/app/assets/javascripts/environments/components/new_environment_item.vue @@ -223,7 +223,7 @@ export default { :icon="icon" :aria-label="label" size="small" - category="tertiary" + category="secondary" @click="toggleCollapse" /> <gl-link diff --git a/app/assets/javascripts/jobs/components/job/sidebar/artifacts_block.vue b/app/assets/javascripts/jobs/components/job/sidebar/artifacts_block.vue index 2018942a7e8..14aaaa219e9 100644 --- a/app/assets/javascripts/jobs/components/job/sidebar/artifacts_block.vue +++ b/app/assets/javascripts/jobs/components/job/sidebar/artifacts_block.vue @@ -45,7 +45,9 @@ export default { data-testid="artifacts-remove-timeline" > <span v-if="isExpired">{{ s__('Job|The artifacts were removed') }}</span> - <span v-if="willExpire">{{ s__('Job|The artifacts will be removed') }}</span> + <span v-if="willExpire" data-qa-selector="artifacts_unlocked_message_content">{{ + s__('Job|The artifacts will be removed') + }}</span> <timeago-tooltip v-if="artifact.expire_at" :time="artifact.expire_at" /> <gl-link :href="helpUrl" @@ -57,7 +59,7 @@ export default { </gl-link> </p> <p v-else-if="isLocked" class="build-detail-row"> - <span data-testid="job-locked-message">{{ + <span data-testid="job-locked-message" data-qa-selector="artifacts_locked_message_content">{{ s__( 'Job|These artifacts are the latest. They will not be deleted (even if expired) until newer artifacts are available.', ) diff --git a/app/assets/stylesheets/components/related_items_list.scss b/app/assets/stylesheets/components/related_items_list.scss index 4d07e4259a0..04a7590d531 100644 --- a/app/assets/stylesheets/components/related_items_list.scss +++ b/app/assets/stylesheets/components/related_items_list.scss @@ -55,6 +55,10 @@ $item-remove-button-space: 42px; .item-weight .board-card-info-icon { min-width: $gl-padding; cursor: help; + + &:focus { + @include gl-focus; + } } .confidential-icon { diff --git a/app/graphql/graphql_triggers.rb b/app/graphql/graphql_triggers.rb index 89656f1e018..d18f57740c3 100644 --- a/app/graphql/graphql_triggers.rb +++ b/app/graphql/graphql_triggers.rb @@ -48,6 +48,8 @@ module GraphqlTriggers end def self.merge_request_merge_status_updated(merge_request) + return unless Feature.enabled?(:realtime_mr_status_change, merge_request.project) + GitlabSchema.subscriptions.trigger( 'mergeRequestMergeStatusUpdated', { issuable_id: merge_request.to_gid }, merge_request ) diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 08ebdb64b52..5732a2f88e9 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -1,6 +1,6 @@ - @hide_top_links = true -- @hide_breadcrumbs = true - @no_container = true +- breadcrumb_title user_display_name(@user) - page_title user_display_name(@user) - page_description @user.bio unless @user.blocked? || !@user.confirmed? - page_itemtype 'http://schema.org/Person' @@ -14,161 +14,162 @@ = auto_discovery_link_tag(:atom, user_url(@user, format: :atom), title: "#{@user.name} activity") .user-profile - .cover-block.user-cover-block{ class: [('border-bottom' if profile_tabs.empty?)] } - = render layout: 'users/cover_controls' do - - if @user == current_user - = render Pajamas::ButtonComponent.new(href: profile_path, - icon: 'pencil', - button_options: { class: 'gl-flex-grow-1 gl-mx-1 has-tooltip', title: s_('UserProfile|Edit profile'), 'aria-label': 'Edit profile', data: { toggle: 'tooltip', placement: 'bottom', container: 'body' }}) - - elsif current_user - #js-report-abuse{ data: { report_abuse_path: add_category_abuse_reports_path, reported_user_id: @user.id, reported_from_url: user_url(@user) } } - - verified_gpg_keys = @user.gpg_keys.select(&:verified?) - - if verified_gpg_keys.any? - = render Pajamas::ButtonComponent.new(href: user_gpg_keys_path, - icon: 'key', - button_options: { class: 'gl-flex-grow-1 gl-mx-1 has-tooltip', title: n_('View public GPG key', 'View public GPG keys', verified_gpg_keys.length), data: { toggle: 'tooltip', placement: 'bottom', container: 'body' }}) - - if can?(current_user, :read_user_profile, @user) - = render Pajamas::ButtonComponent.new(href: user_path(@user, rss_url_options), - icon: 'rss', - button_options: { class: 'gl-flex-grow-1 gl-mx-1 has-tooltip', title: s_('UserProfile|Subscribe'), data: { toggle: 'tooltip', placement: 'bottom', container: 'body' }}) - - if current_user && current_user.admin? - = render Pajamas::ButtonComponent.new(href: [:admin, @user], - icon: 'user', - button_options: { class: 'gl-flex-grow-1 gl-mx-1 has-tooltip', title: s_('UserProfile|View user in admin area'), data: {toggle: 'tooltip', placement: 'bottom', container: 'body'}}) - - if current_user && current_user.id != @user.id - - if current_user.following?(@user) - = form_tag user_unfollow_path(@user, :json), class: link_classes + 'gl-display-inline-block' do - = render Pajamas::ButtonComponent.new(type: :submit, button_options: { class: 'gl-w-full', data: { track_action: 'click_button', track_label: 'unfollow_from_profile' } }) do - = _('Unfollow') - - else - = form_tag user_follow_path(@user, :json), class: link_classes + 'gl-display-inline-block' do - = render Pajamas::ButtonComponent.new(variant: :confirm, type: :submit, button_options: { class: 'gl-w-full', data: { qa_selector: 'follow_user_link', track_action: 'click_button', track_label: 'follow_from_profile' } }) do - = _('Follow') + %div{ class: container_class } + .cover-block.user-cover-block{ class: [('border-bottom' if profile_tabs.empty? || show_super_sidebar?)] } + = render layout: 'users/cover_controls' do + - if @user == current_user + = render Pajamas::ButtonComponent.new(href: profile_path, + icon: 'pencil', + button_options: { class: 'gl-flex-grow-1 gl-mx-1 has-tooltip', title: s_('UserProfile|Edit profile'), 'aria-label': 'Edit profile', data: { toggle: 'tooltip', placement: 'bottom', container: 'body' }}) + - elsif current_user + #js-report-abuse{ data: { report_abuse_path: add_category_abuse_reports_path, reported_user_id: @user.id, reported_from_url: user_url(@user) } } + - verified_gpg_keys = @user.gpg_keys.select(&:verified?) + - if verified_gpg_keys.any? + = render Pajamas::ButtonComponent.new(href: user_gpg_keys_path, + icon: 'key', + button_options: { class: 'gl-flex-grow-1 gl-mx-1 has-tooltip', title: n_('View public GPG key', 'View public GPG keys', verified_gpg_keys.length), data: { toggle: 'tooltip', placement: 'bottom', container: 'body' }}) + - if can?(current_user, :read_user_profile, @user) + = render Pajamas::ButtonComponent.new(href: user_path(@user, rss_url_options), + icon: 'rss', + button_options: { class: 'gl-flex-grow-1 gl-mx-1 has-tooltip', title: s_('UserProfile|Subscribe'), data: { toggle: 'tooltip', placement: 'bottom', container: 'body' }}) + - if current_user && current_user.admin? + = render Pajamas::ButtonComponent.new(href: [:admin, @user], + icon: 'user', + button_options: { class: 'gl-flex-grow-1 gl-mx-1 has-tooltip', title: s_('UserProfile|View user in admin area'), data: {toggle: 'tooltip', placement: 'bottom', container: 'body'}}) + - if current_user && current_user.id != @user.id + - if current_user.following?(@user) + = form_tag user_unfollow_path(@user, :json), class: link_classes + 'gl-display-inline-block' do + = render Pajamas::ButtonComponent.new(type: :submit, button_options: { class: 'gl-w-full', data: { track_action: 'click_button', track_label: 'unfollow_from_profile' } }) do + = _('Unfollow') + - else + = form_tag user_follow_path(@user, :json), class: link_classes + 'gl-display-inline-block' do + = render Pajamas::ButtonComponent.new(variant: :confirm, type: :submit, button_options: { class: 'gl-w-full', data: { qa_selector: 'follow_user_link', track_action: 'click_button', track_label: 'follow_from_profile' } }) do + = _('Follow') - .profile-header{ class: [('with-no-profile-tabs' if profile_tabs.empty?)] } - .gl-display-inline-block.gl-mx-8.gl-vertical-align-top - .avatar-holder - = link_to avatar_icon_for_user(@user, 400, current_user: current_user), target: '_blank', rel: 'noopener noreferrer' do - = render Pajamas::AvatarComponent.new(@user, alt: "", size: 96, avatar_options: { itemprop: "image" }) - #js-user-achievements{ data: { root_url: root_url, user_id: @user.id } } - .gl-display-inline-block.gl-vertical-align-top.gl-text-left - - if @user.blocked? || !@user.confirmed? - .user-info - %h1.cover-title.gl-my-0 - = user_display_name(@user) - = render "users/profile_basic_info" - - else - .user-info - %h1.cover-title.gl-my-0{ itemprop: 'name' } - = @user.name - - if @user.pronouns.present? - %span.gl-font-base.gl-text-gray-500.gl-vertical-align-middle - = "(#{@user.pronouns})" - - if @user.status&.busy? - %span.gl-font-base.gl-text-gray-500.gl-vertical-align-middle= s_("UserProfile|(Busy)") + .profile-header{ class: [('with-no-profile-tabs' if profile_tabs.empty?)] } + .gl-display-inline-block.gl-mx-8.gl-vertical-align-top + .avatar-holder + = link_to avatar_icon_for_user(@user, 400, current_user: current_user), target: '_blank', rel: 'noopener noreferrer' do + = render Pajamas::AvatarComponent.new(@user, alt: "", size: 96, avatar_options: { itemprop: "image" }) + #js-user-achievements{ data: { root_url: root_url, user_id: @user.id } } + .gl-display-inline-block.gl-vertical-align-top.gl-text-left + - if @user.blocked? || !@user.confirmed? + .user-info + %h1.cover-title.gl-my-0 + = user_display_name(@user) + = render "users/profile_basic_info" + - else + .user-info + %h1.cover-title.gl-my-0{ itemprop: 'name' } + = @user.name + - if @user.pronouns.present? + %span.gl-font-base.gl-text-gray-500.gl-vertical-align-middle + = "(#{@user.pronouns})" + - if @user.status&.busy? + %span.gl-font-base.gl-text-gray-500.gl-vertical-align-middle= s_("UserProfile|(Busy)") - - if @user.pronunciation.present? - .gl-align-items-center - %p.gl-mb-4.gl-text-gray-500.gl-max-w-80.gl-mx-auto= s_("UserProfile|Pronounced as: %{pronunciation}") % { pronunciation: @user.pronunciation } + - if @user.pronunciation.present? + .gl-align-items-center + %p.gl-mb-4.gl-text-gray-500.gl-max-w-80.gl-mx-auto= s_("UserProfile|Pronounced as: %{pronunciation}") % { pronunciation: @user.pronunciation } - - if @user.status&.customized? - .cover-status.gl-display-inline-flex.gl-align-items-center.gl-mb-3 - = emoji_icon(@user.status.emoji, class: 'gl-mr-2') - = markdown_field(@user.status, :message) - = render "users/profile_basic_info" - - user_local_time = local_time(@user.timezone) - - if @user.location.present? || user_local_time.present? || work_information(@user).present? + - if @user.status&.customized? + .cover-status.gl-display-inline-flex.gl-align-items-center.gl-mb-3 + = emoji_icon(@user.status.emoji, class: 'gl-mr-2') + = markdown_field(@user.status, :message) + = render "users/profile_basic_info" + - user_local_time = local_time(@user.timezone) + - if @user.location.present? || user_local_time.present? || work_information(@user).present? + .gl-text-gray-900 + - if @user.location.present? + = render 'middle_dot_divider', stacking: true, itemprop: 'address', itemscope: true, itemtype: 'https://schema.org/PostalAddress' do + = sprite_icon('location', css_class: 'fgray') + %span{ itemprop: 'addressLocality' } + = @user.location + - if user_local_time.present? + = render 'middle_dot_divider', stacking: true, data: { testid: 'user-local-time' } do + = sprite_icon('clock', css_class: 'fgray') + %span + = user_local_time + - if work_information(@user).present? + = render 'middle_dot_divider', stacking: true do + = sprite_icon('work', css_class: 'fgray') + %span + = work_information(@user, with_schema_markup: true) .gl-text-gray-900 - - if @user.location.present? - = render 'middle_dot_divider', stacking: true, itemprop: 'address', itemscope: true, itemtype: 'https://schema.org/PostalAddress' do - = sprite_icon('location', css_class: 'fgray') - %span{ itemprop: 'addressLocality' } - = @user.location - - if user_local_time.present? - = render 'middle_dot_divider', stacking: true, data: { testid: 'user-local-time' } do - = sprite_icon('clock', css_class: 'fgray') - %span - = user_local_time - - if work_information(@user).present? + - if @user.skype.present? + = render 'middle_dot_divider' do + = link_to "skype:#{@user.skype}", class: 'gl-hover-text-decoration-none', title: "Skype" do + = sprite_icon('skype', css_class: 'skype-icon') + - if @user.linkedin.present? + = render 'middle_dot_divider' do + = link_to linkedin_url(@user), class: 'gl-hover-text-decoration-none', title: "LinkedIn", target: '_blank', rel: 'noopener noreferrer nofollow' do + = sprite_icon('linkedin', css_class: 'linkedin-icon') + - if @user.twitter.present? + = render 'middle_dot_divider', breakpoint: 'sm' do + = link_to twitter_url(@user), class: 'gl-hover-text-decoration-none', title: "Twitter", target: '_blank', rel: 'noopener noreferrer nofollow' do + = sprite_icon('twitter', css_class: 'twitter-icon') + - if @user.discord.present? + = render 'middle_dot_divider', breakpoint: 'sm' do + = link_to discord_url(@user), class: 'gl-hover-text-decoration-none', title: "Discord", target: '_blank', rel: 'noopener noreferrer nofollow' do + = sprite_icon('discord', css_class: 'discord-icon') + - if @user.website_url.present? + = render 'middle_dot_divider', stacking: true do + - if Feature.enabled?(:security_auto_fix) && @user.bot? + = sprite_icon('question', css_class: 'gl-text-blue-600') + = link_to @user.short_website_url, @user.full_website_url, target: '_blank', rel: 'me noopener noreferrer nofollow', itemprop: 'url' + - if display_public_email?(@user) = render 'middle_dot_divider', stacking: true do - = sprite_icon('work', css_class: 'fgray') - %span - = work_information(@user, with_schema_markup: true) - .gl-text-gray-900 - - if @user.skype.present? - = render 'middle_dot_divider' do - = link_to "skype:#{@user.skype}", class: 'gl-hover-text-decoration-none', title: "Skype" do - = sprite_icon('skype', css_class: 'skype-icon') - - if @user.linkedin.present? - = render 'middle_dot_divider' do - = link_to linkedin_url(@user), class: 'gl-hover-text-decoration-none', title: "LinkedIn", target: '_blank', rel: 'noopener noreferrer nofollow' do - = sprite_icon('linkedin', css_class: 'linkedin-icon') - - if @user.twitter.present? - = render 'middle_dot_divider', breakpoint: 'sm' do - = link_to twitter_url(@user), class: 'gl-hover-text-decoration-none', title: "Twitter", target: '_blank', rel: 'noopener noreferrer nofollow' do - = sprite_icon('twitter', css_class: 'twitter-icon') - - if @user.discord.present? - = render 'middle_dot_divider', breakpoint: 'sm' do - = link_to discord_url(@user), class: 'gl-hover-text-decoration-none', title: "Discord", target: '_blank', rel: 'noopener noreferrer nofollow' do - = sprite_icon('discord', css_class: 'discord-icon') - - if @user.website_url.present? - = render 'middle_dot_divider', stacking: true do - - if Feature.enabled?(:security_auto_fix) && @user.bot? - = sprite_icon('question', css_class: 'gl-text-blue-600') - = link_to @user.short_website_url, @user.full_website_url, target: '_blank', rel: 'me noopener noreferrer nofollow', itemprop: 'url' - - if display_public_email?(@user) - = render 'middle_dot_divider', stacking: true do - = link_to @user.public_email, "mailto:#{@user.public_email}", itemprop: 'email' - - if @user.bio.present? && @user.confirmed? && !@user.blocked? - %p.profile-user-bio.gl-mb-3 - = @user.bio + = link_to @user.public_email, "mailto:#{@user.public_email}", itemprop: 'email' + - if @user.bio.present? && @user.confirmed? && !@user.blocked? + %p.profile-user-bio.gl-mb-3 + = @user.bio - - if !profile_tabs.empty? && !Feature.enabled?(:profile_tabs_vue, current_user) - .scrolling-tabs-container{ class: [('gl-display-none' if show_super_sidebar?)] } - .fade-left= sprite_icon('chevron-lg-left', size: 12) - .fade-right= sprite_icon('chevron-lg-right', size: 12) - %ul.nav-links.user-profile-nav.scrolling-tabs.nav.nav-tabs - - if profile_tab?(:overview) - %li.js-overview-tab - = link_to user_path, data: { target: 'div#js-overview', action: 'overview', toggle: 'tab' } do - = s_('UserProfile|Overview') - - if profile_tab?(:activity) - %li.js-activity-tab - = link_to user_activity_path, data: { target: 'div#activity', action: 'activity', toggle: 'tab' } do - = s_('UserProfile|Activity') - - unless Feature.enabled?(:security_auto_fix) && @user.bot? - - if profile_tab?(:groups) - %li.js-groups-tab - = link_to user_groups_path, data: { target: 'div#groups', action: 'groups', toggle: 'tab', endpoint: user_groups_path(format: :json) } do - = s_('UserProfile|Groups') - - if profile_tab?(:contributed) - %li.js-contributed-tab - = link_to user_contributed_projects_path, data: { target: 'div#contributed', action: 'contributed', toggle: 'tab', endpoint: user_contributed_projects_path(format: :json) } do - = s_('UserProfile|Contributed projects') - - if profile_tab?(:projects) - %li.js-projects-tab - = link_to user_projects_path, data: { target: 'div#projects', action: 'projects', toggle: 'tab', endpoint: user_projects_path(format: :json) } do - = s_('UserProfile|Personal projects') - - if profile_tab?(:starred) - %li.js-starred-tab - = link_to user_starred_projects_path, data: { target: 'div#starred', action: 'starred', toggle: 'tab', endpoint: user_starred_projects_path(format: :json) } do - = s_('UserProfile|Starred projects') - - if profile_tab?(:snippets) - %li.js-snippets-tab - = link_to user_snippets_path, data: { target: 'div#snippets', action: 'snippets', toggle: 'tab', endpoint: user_snippets_path(format: :json) } do - = s_('UserProfile|Snippets') - - if profile_tab?(:followers) - %li.js-followers-tab - = link_to user_followers_path, data: { target: 'div#followers', action: 'followers', toggle: 'tab', endpoint: user_followers_path(format: :json) } do - = s_('UserProfile|Followers') - = gl_badge_tag @user.followers.count, size: :sm - - if profile_tab?(:following) - %li.js-following-tab - = link_to user_following_path, data: { target: 'div#following', action: 'following', toggle: 'tab', endpoint: user_following_path(format: :json), qa_selector: 'following_tab' } do - = s_('UserProfile|Following') - = gl_badge_tag @user.followees.count, size: :sm - - if !profile_tabs.empty? && Feature.enabled?(:profile_tabs_vue, current_user) - #js-profile-tabs{ data: user_profile_tabs_app_data(@user) } + - if !profile_tabs.empty? && !Feature.enabled?(:profile_tabs_vue, current_user) + .scrolling-tabs-container{ class: [('gl-display-none' if show_super_sidebar?)] } + .fade-left= sprite_icon('chevron-lg-left', size: 12) + .fade-right= sprite_icon('chevron-lg-right', size: 12) + %ul.nav-links.user-profile-nav.scrolling-tabs.nav.nav-tabs + - if profile_tab?(:overview) + %li.js-overview-tab + = link_to user_path, data: { target: 'div#js-overview', action: 'overview', toggle: 'tab' } do + = s_('UserProfile|Overview') + - if profile_tab?(:activity) + %li.js-activity-tab + = link_to user_activity_path, data: { target: 'div#activity', action: 'activity', toggle: 'tab' } do + = s_('UserProfile|Activity') + - unless Feature.enabled?(:security_auto_fix) && @user.bot? + - if profile_tab?(:groups) + %li.js-groups-tab + = link_to user_groups_path, data: { target: 'div#groups', action: 'groups', toggle: 'tab', endpoint: user_groups_path(format: :json) } do + = s_('UserProfile|Groups') + - if profile_tab?(:contributed) + %li.js-contributed-tab + = link_to user_contributed_projects_path, data: { target: 'div#contributed', action: 'contributed', toggle: 'tab', endpoint: user_contributed_projects_path(format: :json) } do + = s_('UserProfile|Contributed projects') + - if profile_tab?(:projects) + %li.js-projects-tab + = link_to user_projects_path, data: { target: 'div#projects', action: 'projects', toggle: 'tab', endpoint: user_projects_path(format: :json) } do + = s_('UserProfile|Personal projects') + - if profile_tab?(:starred) + %li.js-starred-tab + = link_to user_starred_projects_path, data: { target: 'div#starred', action: 'starred', toggle: 'tab', endpoint: user_starred_projects_path(format: :json) } do + = s_('UserProfile|Starred projects') + - if profile_tab?(:snippets) + %li.js-snippets-tab + = link_to user_snippets_path, data: { target: 'div#snippets', action: 'snippets', toggle: 'tab', endpoint: user_snippets_path(format: :json) } do + = s_('UserProfile|Snippets') + - if profile_tab?(:followers) + %li.js-followers-tab + = link_to user_followers_path, data: { target: 'div#followers', action: 'followers', toggle: 'tab', endpoint: user_followers_path(format: :json) } do + = s_('UserProfile|Followers') + = gl_badge_tag @user.followers.count, size: :sm + - if profile_tab?(:following) + %li.js-following-tab + = link_to user_following_path, data: { target: 'div#following', action: 'following', toggle: 'tab', endpoint: user_following_path(format: :json), qa_selector: 'following_tab' } do + = s_('UserProfile|Following') + = gl_badge_tag @user.followees.count, size: :sm + - if !profile_tabs.empty? && Feature.enabled?(:profile_tabs_vue, current_user) + #js-profile-tabs{ data: user_profile_tabs_app_data(@user) } %div{ class: container_class } - unless Feature.enabled?(:profile_tabs_vue, current_user) .tab-content diff --git a/doc/administration/clusters/kas.md b/doc/administration/clusters/kas.md index 9d2629e314a..6d6e8e5513c 100644 --- a/doc/administration/clusters/kas.md +++ b/doc/administration/clusters/kas.md @@ -43,6 +43,33 @@ To enable the agent server on a single node: For additional configuration options, see the **Enable GitLab KAS** section of the [`gitlab.rb.template`](https://gitlab.com/gitlab-org/omnibus-gitlab/-/blob/master/files/gitlab-config-template/gitlab.rb.template). +##### Configure KAS to listen on a UNIX socket + +If you use GitLab behind a proxy, KAS might not work correctly. You can resolve this issue on a single-node installation, you can configure KAS to listen on a UNIX socket. + +To configure KAS to listen on a UNIX socket: + +1. Create a directory for the KAS sockets: + + ```shell + sudo mkdir -p /var/opt/gitlab/gitlab-kas/sockets/ + ``` + +1. Edit `/etc/gitlab/gitlab.rb`: + + ```ruby + gitlab_kas['internal_api_listen_network'] = 'unix' + gitlab_kas['internal_api_listen_address'] = '/var/opt/gitlab/gitlab-kas/sockets/internal-api.socket' + gitlab_kas['private_api_listen_network'] = 'unix' + gitlab_kas['private_api_listen_address'] = '/var/opt/gitlab/gitlab-kas/sockets/private-api.socket' + gitlab_kas['env'] = { + 'SSL_CERT_DIR' => "/opt/gitlab/embedded/ssl/certs/", + 'OWN_PRIVATE_API_URL' => 'unix:///var/opt/gitlab/gitlab-kas/sockets/private-api.socket' + } + ``` + +1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure). + #### Enable on multiple nodes To enable the agent server on multiple nodes: diff --git a/doc/development/documentation/styleguide/word_list.md b/doc/development/documentation/styleguide/word_list.md index 2dd3bede19a..9ecddd08103 100644 --- a/doc/development/documentation/styleguide/word_list.md +++ b/doc/development/documentation/styleguide/word_list.md @@ -320,7 +320,7 @@ Use **compute credits** instead of these (or similar) terms: - **CI pipeline minutes** - **pipeline minutes quota** -As of March, 2022, this language is still being standardized in the documentation and UI. +This language is still being standardized in the documentation and UI beginning in March, 2023. For more information, see [issue 5218](https://gitlab.com/gitlab-com/Product/-/issues/5218). ## confirmation dialog diff --git a/doc/update/plan_your_upgrade.md b/doc/update/plan_your_upgrade.md index 0d0084cf530..fd5e1ac8c30 100644 --- a/doc/update/plan_your_upgrade.md +++ b/doc/update/plan_your_upgrade.md @@ -173,7 +173,7 @@ If you have Kubernetes clusters connected with GitLab, [upgrade your GitLab agen #### Elasticsearch Before updating GitLab, confirm advanced search migrations are complete by -[checking for pending advanced search migrations](background_migrations.md). +[checking for pending advanced search migrations](index.md#checking-for-pending-advanced-search-migrations). After updating GitLab, you may have to upgrade [Elasticsearch if the new version breaks compatibility](../integration/advanced_search/elasticsearch.md#version-requirements). diff --git a/qa/qa/page/project/job/show.rb b/qa/qa/page/project/job/show.rb index 444c67cfe4f..41a2986e300 100644 --- a/qa/qa/page/project/job/show.rb +++ b/qa/qa/page/project/job/show.rb @@ -69,11 +69,11 @@ module QA end def has_locked_artifact? - has_text?('will not be deleted') + has_element? :artifacts_locked_message_content end def has_unlocked_artifact? - has_text?('will be removed') + has_element? :artifacts_unlocked_message_content end private diff --git a/scripts/gitlab_component_helpers.sh b/scripts/gitlab_component_helpers.sh index 798135a5490..cf9b042b529 100644 --- a/scripts/gitlab_component_helpers.sh +++ b/scripts/gitlab_component_helpers.sh @@ -53,8 +53,6 @@ export GITLAB_ASSETS_PACKAGE_URL="${API_PACKAGES_BASE_URL}/assets/${NODE_ENV}-${ # Fixtures constants export FIXTURES_PATH="tmp/tests/frontend/**/*" -export FIXTURES_PACKAGE="fixtures-${FIXTURES_SHA:-}.tar.gz" -export FIXTURES_PACKAGE_URL="${API_PACKAGES_BASE_URL}/fixtures/${FIXTURES_SHA:-}/${FIXTURES_PACKAGE}" # Generic helper functions function archive_doesnt_exist() { @@ -62,12 +60,12 @@ function archive_doesnt_exist() { status=$(curl -I --silent --retry 3 --output /dev/null -w "%{http_code}" "${package_url}") - if [[ "${status}" != "200" ]]; then - echoinfo "The archive was not found. The server returned status ${status}." - return 0 - else + if [[ "${status}" = "200" ]]; then echoinfo "The archive was found. The server returned status ${status}." return 1 + else + echoinfo "The archive was not found. The server returned status ${status}." + return 0 fi } @@ -160,28 +158,6 @@ function upload_gitlab_assets_package() { } # Fixtures functions -function download_and_extract_fixtures() { - read_curl_package "${FIXTURES_PACKAGE_URL}" | extract_package -} - -function fixtures_archive_doesnt_exist() { - echoinfo "Checking if the package is available at ${FIXTURES_PACKAGE_URL} ..." - - archive_doesnt_exist "${FIXTURES_PACKAGE_URL}" -} - -function fixtures_directory_exists() { - local fixtures_directory="tmp/tests/frontend/" - - if [[ -d "${fixtures_directory}" ]]; then - echo "${fixtures_directory} directory exists" - return 0 - else - echo "${fixtures_directory} directory does not exist" - return 1 - fi -} - function check_fixtures_download() { if [[ "${REUSE_FRONTEND_FIXTURES_ENABLED:-}" != "true" ]]; then return 1 @@ -208,8 +184,41 @@ function create_fixtures_package() { create_package "${FIXTURES_PACKAGE}" "${FIXTURES_PATH}" } -function upload_fixtures_package() { - upload_package "${FIXTURES_PACKAGE}" "${FIXTURES_PACKAGE_URL}" +function download_and_extract_fixtures() { + read_curl_package "${FIXTURES_PACKAGE_URL}" | extract_package +} + +function export_fixtures_package_variables() { + export FIXTURES_PACKAGE="fixtures-${FIXTURES_SHA}.tar.gz" + export FIXTURES_PACKAGE_URL="${API_PACKAGES_BASE_URL}/fixtures/${FIXTURES_SHA}/${FIXTURES_PACKAGE}" +} + +function export_fixtures_sha_for_download() { + export FIXTURES_SHA="${CI_MERGE_REQUEST_TARGET_BRANCH_SHA:-${CI_MERGE_REQUEST_DIFF_BASE_SHA:-$CI_COMMIT_SHA}}" + export_fixtures_package_variables +} + +function export_fixtures_sha_for_upload() { + export FIXTURES_SHA="${CI_MERGE_REQUEST_SOURCE_BRANCH_SHA:-$CI_COMMIT_SHA}" + export_fixtures_package_variables +} + +function fixtures_archive_doesnt_exist() { + echoinfo "Checking if the package is available at ${FIXTURES_PACKAGE_URL} ..." + + archive_doesnt_exist "${FIXTURES_PACKAGE_URL}" +} + +function fixtures_directory_exists() { + local fixtures_directory="tmp/tests/frontend/" + + if [[ -d "${fixtures_directory}" ]]; then + echo "${fixtures_directory} directory exists" + return 0 + else + echo "${fixtures_directory} directory does not exist" + return 1 + fi } function only_js_files_changed { @@ -235,3 +244,7 @@ function only_js_files_changed { echoinfo "Only JS files were changed" return 0 } + +function upload_fixtures_package() { + upload_package "${FIXTURES_PACKAGE}" "${FIXTURES_PACKAGE_URL}" +} diff --git a/spec/features/users/show_spec.rb b/spec/features/users/show_spec.rb index 9aef3ed7cd6..fab87f6dc71 100644 --- a/spec/features/users/show_spec.rb +++ b/spec/features/users/show_spec.rb @@ -15,6 +15,14 @@ RSpec.describe 'User page', feature_category: :user_profile do expect(page).to have_content("User ID: #{user.id}") end + it 'shows name on breadcrumbs' do + subject + + page.within '.breadcrumbs' do + expect(page).to have_content(user.name) + end + end + context 'with public profile' do context 'with `profile_tabs_vue` feature flag disabled' do before do diff --git a/spec/frontend/environments/new_environment_item_spec.js b/spec/frontend/environments/new_environment_item_spec.js index c04ff896794..b2088ad410b 100644 --- a/spec/frontend/environments/new_environment_item_spec.js +++ b/spec/frontend/environments/new_environment_item_spec.js @@ -382,6 +382,7 @@ describe('~/environments/components/new_environment_item.vue', () => { const button = await expandCollapsedSection(); expect(button.attributes('aria-label')).toBe(__('Collapse')); + expect(button.props('category')).toBe('secondary'); expect(collapse.attributes('visible')).toBe('visible'); expect(icon.props('name')).toBe('chevron-lg-down'); expect(environmentName.classes('gl-font-weight-bold')).toBe(true); diff --git a/spec/graphql/graphql_triggers_spec.rb b/spec/graphql/graphql_triggers_spec.rb index 00b5aec366e..08b8f67c4bc 100644 --- a/spec/graphql/graphql_triggers_spec.rb +++ b/spec/graphql/graphql_triggers_spec.rb @@ -115,6 +115,20 @@ RSpec.describe GraphqlTriggers do GraphqlTriggers.merge_request_merge_status_updated(merge_request) end + + context 'when realtime_mr_status_change feature flag is disabled' do + before do + stub_feature_flags(realtime_mr_status_change: false) + end + + it 'does not trigger mergeRequestMergeStatusUpdated subscription' do + merge_request = build_stubbed(:merge_request) + + expect(GitlabSchema.subscriptions).not_to receive(:trigger) + + GraphqlTriggers.merge_request_merge_status_updated(merge_request) + end + end end describe '.merge_request_approval_state_updated' do diff --git a/spec/lib/banzai/filter/external_link_filter_spec.rb b/spec/lib/banzai/filter/external_link_filter_spec.rb index 3f72896939d..de259342998 100644 --- a/spec/lib/banzai/filter/external_link_filter_spec.rb +++ b/spec/lib/banzai/filter/external_link_filter_spec.rb @@ -2,25 +2,25 @@ require 'spec_helper' -RSpec.shared_examples 'an external link with rel attribute', feature_category: :team_planning do - it 'adds rel="nofollow" to external links' do - expect(doc.at_css('a')).to have_attribute('rel') - expect(doc.at_css('a')['rel']).to include 'nofollow' - end +RSpec.describe Banzai::Filter::ExternalLinkFilter, feature_category: :team_planning do + include FilterSpecHelper - it 'adds rel="noreferrer" to external links' do - expect(doc.at_css('a')).to have_attribute('rel') - expect(doc.at_css('a')['rel']).to include 'noreferrer' - end + shared_examples 'an external link with rel attribute' do + it 'adds rel="nofollow" to external links' do + expect(doc.at_css('a')).to have_attribute('rel') + expect(doc.at_css('a')['rel']).to include 'nofollow' + end - it 'adds rel="noopener" to external links' do - expect(doc.at_css('a')).to have_attribute('rel') - expect(doc.at_css('a')['rel']).to include 'noopener' - end -end + it 'adds rel="noreferrer" to external links' do + expect(doc.at_css('a')).to have_attribute('rel') + expect(doc.at_css('a')['rel']).to include 'noreferrer' + end -RSpec.describe Banzai::Filter::ExternalLinkFilter do - include FilterSpecHelper + it 'adds rel="noopener" to external links' do + expect(doc.at_css('a')).to have_attribute('rel') + expect(doc.at_css('a')['rel']).to include 'noopener' + end + end it 'ignores elements without an href attribute' do exp = act = %q(<a id="ignored">Ignore Me</a>) |