Skip to content
Snippets Groups Projects
Commit 4807b12d authored by Phil Hughes's avatar Phil Hughes
Browse files

Merge branch 'ph/updatedMergeRequestHeader' into 'master'

Updated merge request header

See merge request !86019
parents 0f7187fd 20fbbe64
No related branches found
No related tags found
No related merge requests found
Pipeline #532109393 failed
Pipeline: GitLab

#532139914

    Showing
    with 177 additions and 55 deletions
    ......@@ -156,7 +156,7 @@ export default class ShortcutsIssuable extends Shortcuts {
    static copyBranchName() {
    // There are two buttons - one that is shown when the sidebar
    // is expanded, and one that is shown when it's collapsed.
    const allCopyBtns = Array.from(document.querySelectorAll('.js-sidebar-source-branch button'));
    const allCopyBtns = Array.from(document.querySelectorAll('.js-source-branch-copy'));
    // Select whichever button is currently visible so that
    // the "Copied" tooltip is shown when a click is simulated.
    ......
    ......@@ -44,7 +44,10 @@ export default {
    </script>
    <template>
    <div class="gl-display-inline-block">
    <div
    :class="{ 'gl-vertical-align-middle': getNoteableData.targetType === 'merge_request' }"
    class="gl-display-inline-block"
    >
    <confidentiality-badge
    v-if="isConfidential"
    data-testid="confidential"
    ......@@ -58,7 +61,7 @@ export default {
    v-gl-tooltip
    :data-testid="meta.dataTestId"
    :title="meta.tooltip || null"
    class="issuable-warning-icon inline"
    class="issuable-warning-icon gl-display-flex gl-justify-content-center gl-align-items-center"
    >
    <gl-icon :name="meta.iconName" class="icon" />
    </div>
    ......
    <script>
    import { GlIcon } from '@gitlab/ui';
    import Vue from 'vue';
    import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
    import { fetchPolicies } from '~/lib/graphql';
    import { __ } from '~/locale';
    ......@@ -11,9 +12,12 @@ export const statusBoxState = Vue.observable({
    const CLASSES = {
    opened: 'status-box-open',
    merge_request_opened: 'badge-success',
    locked: 'status-box-open',
    merge_request_locked: 'badge-success',
    closed: 'status-box-mr-closed',
    merged: 'status-box-mr-merged',
    merge_request_closed: 'badge-danger',
    merged: 'badge-info',
    };
    const STATUS = {
    ......@@ -27,6 +31,7 @@ export default {
    components: {
    GlIcon,
    },
    mixins: [glFeatureFlagMixin()],
    inject: {
    query: { default: null },
    projectPath: { default: null },
    ......@@ -52,8 +57,19 @@ export default {
    return statusBoxState;
    },
    computed: {
    isMergeRequest() {
    if (!this.glFeatures.updatedMrHeader) return false;
    return this.issuableType === 'merge_request';
    },
    statusBoxClass() {
    return CLASSES[`${this.issuableType}_${this.state}`] || CLASSES[this.state];
    return [
    CLASSES[`${this.issuableType}_${this.state}`] || CLASSES[this.state],
    {
    'badge badge-pill gl-badge': this.isMergeRequest,
    'issuable-status-box status-box': !this.isMergeRequest,
    },
    ];
    },
    statusHumanName() {
    return (STATUS[`${this.issuableType}_${this.state}`] || STATUS[this.state])[0];
    ......@@ -90,9 +106,13 @@ export default {
    </script>
    <template>
    <div :class="statusBoxClass" class="issuable-status-box status-box">
    <gl-icon :name="statusIconName" class="gl-display-block gl-sm-display-none!" />
    <span class="gl-display-none gl-sm-display-block">
    <div :class="statusBoxClass">
    <gl-icon
    v-if="!isMergeRequest"
    :name="statusIconName"
    class="gl-display-block gl-sm-display-none!"
    />
    <span :class="{ 'gl-display-none gl-sm-display-block': !isMergeRequest }">
    {{ statusHumanName }}
    </span>
    </div>
    ......
    ......@@ -148,7 +148,11 @@ MergeRequest.toggleDraftStatus = function (title, isReady) {
    } else {
    toast(__('Marked as draft. Can only be merged when marked as ready.'));
    }
    const titleEl = document.querySelector('.merge-request .detail-page-description .title');
    const titleEl = document.querySelector(
    `.merge-request .detail-page-${
    window.gon?.features?.updatedMrHeader ? 'header' : 'description'
    } .title`,
    );
    if (titleEl) {
    titleEl.textContent = title;
    ......
    ......@@ -36,6 +36,7 @@ export default function initMergeRequestShow() {
    return h(StatusBox, {
    props: {
    initialState: el.dataset.state,
    issuableType: 'merge_request',
    },
    });
    },
    ......
    ......@@ -716,6 +716,20 @@ export default {
    {{ __('Merge details') }}
    </strong>
    <ul class="gl-pl-4 gl-m-0">
    <li
    v-if="mr.divergedCommitsCount > 0 && glFeatures.updatedMrHeader"
    class="gl-line-height-normal"
    >
    <gl-sprintf
    :message="s__('mrWidget|The source branch is %{link} the target branch')"
    >
    <template #link>
    <gl-link :href="mr.targetBranchPath">{{
    n__('%d commit behind', '%d commits behind', mr.divergedCommitsCount)
    }}</gl-link>
    </template>
    </gl-sprintf>
    </li>
    <li class="gl-line-height-normal">
    <added-commit-message
    :state="mr.state"
    ......@@ -744,6 +758,18 @@ export default {
    :class="{ 'gl-mb-5': restructuredWidgetShowMergeButtons }"
    class="gl-w-full gl-order-n1 gl-text-gray-500"
    >
    <p class="gl-mb-3">
    <gl-sprintf
    v-if="mr.divergedCommitsCount > 0 && glFeatures.updatedMrHeader"
    :message="s__('mrWidget|The source branch is %{link} the target branch')"
    >
    <template #link>
    <gl-link :href="mr.targetBranchPath">{{
    n__('%d commit behind', '%d commits behind', mr.divergedCommitsCount)
    }}</gl-link>
    </template>
    </gl-sprintf>
    </p>
    <added-commit-message
    :is-squash-enabled="squashBeforeMerge"
    :is-fast-forward-enabled="!shouldShowMergeEdit"
    ......@@ -769,6 +795,22 @@ export default {
    >
    {{ __('The latest pipeline for this merge request did not complete successfully.') }}
    </div>
    <div
    v-if="
    mr.divergedCommitsCount > 0 &&
    glFeatures.updatedMrHeader &&
    !glFeatures.restructuredMrWidget
    "
    class="diverged-commits-count gl-mt-4"
    >
    <gl-sprintf :message="s__('mrWidget|The source branch is %{link} the target branch')">
    <template #link>
    <gl-link :href="mr.targetBranchPath">{{
    n__('%d commit behind', '%d commits behind', mr.divergedCommitsCount)
    }}</gl-link>
    </template>
    </gl-sprintf>
    </div>
    </div>
    </div>
    <template v-if="shouldShowMergeControls && !glFeatures.restructuredMrWidget">
    ......
    ......@@ -231,6 +231,9 @@ export default {
    isRestructuredMrWidgetEnabled() {
    return window.gon?.features?.restructuredMrWidget;
    },
    isUpdatedHeaderEnabled() {
    return window.gon?.features?.updatedMrHeader;
    },
    },
    watch: {
    'mr.machineValue': {
    ......@@ -524,11 +527,14 @@ export default {
    </script>
    <template>
    <div v-if="isLoaded" class="mr-state-widget gl-mt-3">
    <header class="gl-rounded-base gl-border-solid gl-border-1 gl-border-gray-100">
    <header
    v-if="shouldRenderCollaborationStatus || !isUpdatedHeaderEnabled"
    class="gl-rounded-base gl-border-solid gl-border-1 gl-border-gray-100"
    >
    <mr-widget-alert-message v-if="shouldRenderCollaborationStatus" type="info">
    {{ s__('mrWidget|Members who can merge are allowed to add commits.') }}
    </mr-widget-alert-message>
    <mr-widget-header :mr="mr" />
    <mr-widget-header v-if="!isUpdatedHeaderEnabled" :mr="mr" />
    </header>
    <mr-widget-suggest-pipeline
    v-if="shouldSuggestPipelines"
    ......
    ......@@ -666,12 +666,12 @@ $tabs-holder-z-index: 250;
    margin-top: $gl-padding;
    position: relative;
    &::before {
    &:not(:last-child)::before {
    content: '';
    border-left: 1px solid var(--gray-100, $gray-100);
    position: absolute;
    left: 28px;
    top: -17px;
    bottom: -17px;
    height: 16px;
    }
    }
    ......
    ......@@ -8,7 +8,8 @@
    a {
    color: $gl-text-color;
    &.link {
    &.link,
    &.gl-link {
    color: $blue-600;
    }
    }
    ......@@ -38,9 +39,18 @@
    align-self: center;
    flex: 0 0 auto;
    @include media-breakpoint-down(xs) {
    width: 100%;
    margin-top: 10px;
    &:not(.is-merge-request) {
    @include media-breakpoint-down(xs) {
    width: 100%;
    margin-top: 10px;
    }
    }
    &.is-merge-request {
    @include media-breakpoint-down(sm) {
    width: 100%;
    margin-top: 10px;
    }
    }
    }
    ......@@ -56,4 +66,8 @@
    .description {
    margin-top: 6px;
    }
    .author-link {
    color: $gl-text-color;
    }
    }
    ......@@ -44,6 +44,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
    push_frontend_feature_flag(:issue_assignees_widget, @project, default_enabled: :yaml)
    push_frontend_feature_flag(:realtime_labels, project, default_enabled: :yaml)
    push_frontend_feature_flag(:updated_diff_expansion_buttons, project, default_enabled: :yaml)
    push_frontend_feature_flag(:updated_mr_header, project, default_enabled: :yaml)
    end
    before_action do
    ......
    ......@@ -28,16 +28,18 @@ def issue_repositioning_disabled?
    end
    def status_box_class(item)
    updated_mr_header_enabled = Feature.enabled?(:updated_mr_header, @project, default_enabled: :yaml)
    if item.try(:expired?)
    'status-box-expired'
    elsif item.try(:merged?)
    'status-box-mr-merged'
    updated_mr_header_enabled ? 'badge-info' : 'status-box-mr-merged'
    elsif item.closed?
    'status-box-mr-closed'
    item.is_a?(MergeRequest) && updated_mr_header_enabled ? 'badge-danger' : 'status-box-mr-closed'
    elsif item.try(:upcoming?)
    'status-box-upcoming'
    else
    'status-box-open'
    item.is_a?(MergeRequest) && updated_mr_header_enabled ? 'badge-success' : 'status-box-open'
    end
    end
    ......
    ......@@ -231,6 +231,30 @@ def attention_requested_merge_requests_count
    def default_suggestion_commit_message
    @project.suggestion_commit_message.presence || Gitlab::Suggestions::CommitMessage::DEFAULT_SUGGESTION_COMMIT_MESSAGE
    end
    def merge_request_source_branch(merge_request)
    branch = if merge_request.for_fork?
    "#{merge_request.source_project_path}:#{merge_request.source_branch}"
    else
    merge_request.source_branch
    end
    branch_path = if merge_request.source_project
    project_tree_path(merge_request.source_project, merge_request.source_branch)
    else
    ''
    end
    link_to branch, branch_path, class: 'gl-link gl-font-monospace'
    end
    def merge_request_header(project, merge_request)
    link_to_author = link_to_member(project, merge_request.author, size: 24, extra_class: 'gl-font-weight-bold', avatar: false)
    copy_button = clipboard_button(text: merge_request.source_branch, title: _('Copy branch name'), class: 'btn btn-default btn-sm gl-button btn-default-tertiary btn-icon gl-display-none! gl-md-display-inline-block! js-source-branch-copy')
    target_branch = link_to merge_request.target_branch, project_tree_path(merge_request.target_project, merge_request.target_branch), class: 'gl-link gl-font-monospace'
    _('%{author} requested to merge %{span_start}%{source_branch} %{copy_button}%{span_end} into %{target_branch} %{created_at}').html_safe % { author: link_to_author.html_safe, source_branch: merge_request_source_branch(merge_request).html_safe, copy_button: copy_button.html_safe, target_branch: target_branch.html_safe, created_at: time_ago_with_tooltip(merge_request.created_at, html_class: 'gl-display-inline-block').html_safe, span_start: '<span class="gl-display-inline-block">'.html_safe, span_end: '</span>'.html_safe }
    end
    end
    MergeRequestsHelper.prepend_mod_with('MergeRequestsHelper')
    .detail-page-description.py-2
    %h2.title.mb-0{ data: { qa_selector: 'title_content' } }
    = markdown_field(@merge_request, :title)
    - if Feature.enabled?(:updated_mr_header, @project, default_enabled: :yaml)
    - state_human_name, _ = state_name_with_icon(@merge_request)
    .badge.badge-pill.gl-badge.js-mr-status-box{ class: status_box_class(@merge_request), data: { project_path: @merge_request.project.path_with_namespace, iid: @merge_request.iid, state: @merge_request.state } }= state_human_name
    = merge_request_header(@project, @merge_request)
    - else
    %h2.title.mb-0{ data: { qa_selector: 'title_content' } }
    = markdown_field(@merge_request, :title)
    ......@@ -3,6 +3,7 @@
    - can_reopen_merge_request = can?(current_user, :reopen_merge_request, @merge_request)
    - are_close_and_open_buttons_hidden = merge_request_button_hidden?(@merge_request, true) && merge_request_button_hidden?(@merge_request, false)
    - cache_key = [@project, @merge_request, can_update_merge_request, can_reopen_merge_request, are_close_and_open_buttons_hidden, current_user&.preferred_language]
    - moved_sidebar_enabled = Feature.enabled?(:updated_mr_header, @project, default_enabled: :yaml)
    = cache(cache_key, expires_in: 1.day) do
    - if @merge_request.closed_or_merged_without_fork?
    ......@@ -12,18 +13,24 @@
    .gl-alert-body
    = _('The source project of this merge request has been removed.')
    .detail-page-header.border-bottom-0.pt-0.pb-0
    .detail-page-header.border-bottom-0.pt-0.pb-0{ class: "#{'gl-display-block gl-md-display-flex!' if moved_sidebar_enabled}" }
    .detail-page-header-body
    = render "shared/issuable/status_box", issuable: @merge_request
    - unless moved_sidebar_enabled
    = render "shared/issuable/status_box", issuable: @merge_request
    .issuable-meta
    #js-issuable-header-warnings
    = issuable_meta(@merge_request, @project)
    - if moved_sidebar_enabled
    #js-issuable-header-warnings
    %h2.title.gl-my-0.gl-display-inline-block{ data: { qa_selector: 'title_content' } }
    = markdown_field(@merge_request, :title)
    - else
    #js-issuable-header-warnings
    = issuable_meta(@merge_request, @project)
    %a.gl-button.btn.btn-default.btn-icon.float-right.d-block.d-sm-none.gutter-toggle.issuable-gutter-toggle.js-sidebar-toggle{ href: "#" }
    = sprite_icon('chevron-double-lg-left')
    %div
    %button.gl-button.btn.btn-default.btn-icon.float-right.d-block.d-sm-none.gutter-toggle.issuable-gutter-toggle.js-sidebar-toggle{ type: 'button' }
    = sprite_icon('chevron-double-lg-left')
    .detail-page-header-actions.js-issuable-actions
    .detail-page-header-actions.js-issuable-actions{ class: "#{'gl-align-self-start is-merge-request' if moved_sidebar_enabled}" }
    - if @merge_request.source_project
    = render 'projects/merge_requests/code_dropdown'
    ......
    ......@@ -86,7 +86,7 @@
    - if issuable_type == 'merge_request'
    .sub-block.js-sidebar-source-branch
    .sidebar-collapsed-icon.js-dont-change-state
    = clipboard_button(text: source_branch, title: _('Copy branch name'), placement: "left", boundary: 'viewport')
    = clipboard_button(text: source_branch, title: _('Copy branch name'), placement: "left", boundary: 'viewport', class: 'btn-clipboard gl-button btn-default-tertiary btn-icon btn-sm js-source-branch-copy')
    .gl-display-flex.gl-align-items-center.gl-justify-content-space-between.gl-mb-2.hide-collapsed
    %span.gl-overflow-hidden.gl-text-overflow-ellipsis.gl-white-space-nowrap
    = _('Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}').html_safe % { source_branch_open: "<span class='gl-font-monospace' data-testid='ref-name' title='#{html_escape(source_branch)}'>".html_safe, source_branch_close: "</span>".html_safe, source_branch: html_escape(source_branch) }
    ......
    ---
    name: updated_mr_header
    introduced_by_url:
    rollout_issue_url:
    milestone: '14.10'
    type: development
    group: group::code review
    default_enabled: false
    ......@@ -316,11 +316,14 @@ export default {
    </script>
    <template>
    <div v-if="isLoaded" class="mr-state-widget gl-mt-3">
    <header class="gl-rounded-base gl-border-solid gl-border-1 gl-border-gray-100">
    <header
    v-if="shouldRenderCollaborationStatus || !isUpdatedHeaderEnabled"
    class="gl-rounded-base gl-border-solid gl-border-1 gl-border-gray-100"
    >
    <mr-widget-alert-message v-if="shouldRenderCollaborationStatus" type="info">
    {{ s__('mrWidget|Members who can merge are allowed to add commits.') }}
    </mr-widget-alert-message>
    <mr-widget-header :mr="mr" />
    <mr-widget-header v-if="!isUpdatedHeaderEnabled" :mr="mr" />
    </header>
    <mr-widget-suggest-pipeline
    v-if="shouldSuggestPipelines"
    ......
    # frozen_string_literal: true
    require 'spec_helper'
    RSpec.describe 'projects/merge_requests/show.html.haml' do
    include_context 'merge request show action'
    context 'when merge request is created by a GitLab team member' do
    before do
    allow(user).to receive(:gitlab_employee?).and_return(true)
    end
    it 'renders an employee badge next to their name' do
    render
    expect(rendered).to have_selector('[aria-label="GitLab Team Member"]')
    end
    end
    end
    ......@@ -474,6 +474,9 @@ msgstr ""
    msgid "%{authorsName}'s thread"
    msgstr ""
     
    msgid "%{author} requested to merge %{span_start}%{source_branch} %{copy_button}%{span_end} into %{target_branch} %{created_at}"
    msgstr ""
    msgid "%{board_target} not found"
    msgstr ""
     
    ......
    ......@@ -112,9 +112,7 @@
    click_button('Merge')
    page.within('.status-box') do
    expect(page).to have_content('Merged')
    end
    expect(page).to have_selector('.gl-badge', text: 'Merged')
    end
    end
    end
    0% Loading or .
    You are about to add 0 people to the discussion. Proceed with caution.
    Finish editing this message first!
    Please register or to comment