Commit db1ee8e8 authored by Natalia Tepluhina's avatar Natalia Tepluhina

Merge branch '36524-group-level-compliance-dashboard-mvc-fe' into 'master'

Group-level compliance dashboard MVC frontend

Closes #36524

See merge request gitlab-org/gitlab!21549
parents ca07f8b1 329ee6ea
......@@ -56,6 +56,7 @@
.gl-bg-green-100 { @include gl-bg-green-100;}
.gl-text-blue-500 { @include gl-text-blue-500; }
.gl-text-gray-700 { @include gl-text-gray-700; }
.gl-text-gray-900 { @include gl-text-gray-900; }
.gl-text-red-700 { @include gl-text-red-700; }
.gl-text-orange-700 { @include gl-text-orange-700; }
......
.compliance-dashboard {
.content-list {
border-top: 1px solid $border-color;
border-bottom: 1px solid $border-color;
}
.author-link {
align-items: center;
margin-right: 10px;
&:last-child {
margin-right: 0;
}
}
}
......@@ -2,9 +2,11 @@
- approvers_over_presentable_limit = merge_request.approved_by_users.size - presentable_approvers_limit
- project = merge_request.project
= _('Approved by: ')
%li.issuable-status
%span.gl-text-gray-700
= _('Approved by: ')
- merge_request.approved_by_users.take(presentable_approvers_limit).each do |approver| # rubocop: disable CodeReuse/ActiveRecord
= link_to_member(project, approver, name: true, title: "Approved by :name")
- if approvers_over_presentable_limit.positive?
%span{ class: 'avatar-counter has-tooltip', data: { container: 'body', placement: 'bottom', 'line-type' => 'old', 'original-title' => "+#{approvers_over_presentable_limit} more approvers", qa_selector: 'avatar_counter' } }
%span{ class: 'avatar-counter has-tooltip', data: { container: 'body', placement: 'bottom', 'line-type' => 'old', qa_selector: 'avatar_counter' }, title: _("+%{approvers} more approvers") % { approvers: approvers_over_presentable_limit } }
= "+ #{approvers_over_presentable_limit}"
%li{ id: dom_id(merge_request), data: { id: merge_request.id } }
%li.merge-request{ id: dom_id(merge_request), data: { id: merge_request.id } }
.issuable-info-container
.issuable-main-info
.merge-request-title.title
%span.merge-request-title-text.js-onboarding-mr-item
= link_to merge_request.title, merge_request_path(merge_request)
.issuable-info
%span.issuable-reference
= issuable_reference(merge_request)
.title
= link_to merge_request.title, merge_request_path(merge_request)
%span.gl-text-gray-700
= issuable_reference(merge_request)
.issuable-meta
%ul.controls.d-flex.align-items-end
%ul.controls
- if merge_request.approved_by_users.any?
%li.d-flex
= render 'approvers', merge_request: merge_request
%span
= render 'approvers', project: merge_request.project, merge_request: merge_request
- else
%li.issuable-status
%span.gl-text-gray-700
= _('No approvers')
%span.gl-text-gray-700
= _('merged %{time_ago}').html_safe % { time_ago: time_ago_with_tooltip(merge_request.merged_at, placement: 'bottom', html_class: 'merge_request_updated_ago') }
- if @merge_requests.present?
.card.card-small.card-without-border
%ul.content-list.mr-list.issuable-list
.compliance-dashboard
%header.my-3
%h4= _("Compliance Dashboard")
%p= _("Here you will find recent merge request activity")
%ul.content-list.issuable-list.issues-list
= render partial: 'merge_request', collection: @merge_requests
= paginate @merge_requests
= paginate_without_count @merge_requests
- else
= render 'empty_state'
......@@ -3,34 +3,95 @@
require 'spec_helper'
describe 'groups/security/compliance_dashboards/show.html.haml' do
set(:user) { create(:user) }
let(:user) { create(:user) }
let(:group) { create(:group) }
let(:project) { create(:project, namespace: group) }
before do
group.add_owner(user)
assign(:group, group)
allow(view).to receive(:current_user) { user }
stub_licensed_features(group_level_compliance_dashboard: true)
end
it 'shows empty state if there are no merge requests' do
render
context 'when there are no merge requests' do
it 'renders empty state' do
render
expect(rendered).to have_css("div.empty-state")
expect(rendered).to have_css('div', class: 'empty-state merge-requests')
expect(rendered).not_to have_css('div', class: 'compliance-dashboard')
end
end
context 'when there are merge requests' do
let(:mr) { create(:merge_request, :merged) }
let(:merge_request) { create(:merge_request, source_project: project, state: :merged) }
before do
mr.metrics.update!(merged_at: 1.day.ago)
assign(:merge_requests, Kaminari.paginate_array([mr]).page(1))
merge_request.metrics.update!(merged_at: 10.minutes.ago)
assign(:merge_requests, Kaminari.paginate_array([merge_request]).page(0))
end
it 'shows merge requests' do
it 'renders merge requests' do
render
expect(rendered).to have_css(".merge-request-title.title")
expect(rendered).to have_link(merge_request.title)
expect(rendered).not_to have_css('div', class: 'empty-state merge-requests')
end
it 'renders merge requests with time merged tooltip' do
render
expect(rendered).to have_css('time', class: 'js-timeago')
end
context 'with no approvers' do
it 'renders the message "No approvers"' do
render
expect(rendered).to have_css("li span", text: 'No approvers')
end
end
context 'with a single approvers' do
let(:approver_1) { create(:user) }
let!(:approval_rule) { create :approval_merge_request_rule, merge_request: merge_request, users: [approver_1] }
let!(:approval) { create :approval, merge_request: merge_request, user: approver_1 }
before do
project.add_developer(approver_1)
end
it 'renders a single approver avatar link' do
render
expect(rendered).to have_css('a', class: 'author-link', count: 1)
expect(rendered).to have_link(approver_1.name)
end
end
context 'with more than two approvers' do
let(:approver_1) { create(:user) }
let(:approver_2) { create(:user) }
let(:approver_3) { create(:user) }
let!(:approval_1) { create :approval, merge_request: merge_request, user: approver_1 }
let!(:approval_2) { create :approval, merge_request: merge_request, user: approver_2 }
let!(:approval_3) { create :approval, merge_request: merge_request, user: approver_3 }
before do
project.add_developer(approver_1)
project.add_developer(approver_2)
project.add_developer(approver_3)
end
it 'renders the two latest approvers\'s avatar links' do
render
expect(rendered).to have_css('a', class: 'author-link', count: 2)
end
it 'renders a tooltip for additional approvers' do
render
expect(rendered).to have_css('span', class: 'avatar-counter', text: '+ 1')
end
end
end
end
......@@ -528,6 +528,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
msgid "+%{approvers} more approvers"
msgstr ""
msgid "+%{extraOptionCount} more"
msgstr ""
......@@ -9809,6 +9812,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths"
msgstr ""
msgid "Here you will find recent merge request activity"
msgstr ""
msgid "Hi %{username}!"
msgstr ""
......@@ -12421,6 +12427,9 @@ msgstr ""
msgid "No application_settings found"
msgstr ""
msgid "No approvers"
msgstr ""
msgid "No authentication methods configured."
msgstr ""
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment