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 @@ ...@@ -56,6 +56,7 @@
.gl-bg-green-100 { @include gl-bg-green-100;} .gl-bg-green-100 { @include gl-bg-green-100;}
.gl-text-blue-500 { @include gl-text-blue-500; } .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-gray-900 { @include gl-text-gray-900; }
.gl-text-red-700 { @include gl-text-red-700; } .gl-text-red-700 { @include gl-text-red-700; }
.gl-text-orange-700 { @include gl-text-orange-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 @@ ...@@ -2,9 +2,11 @@
- approvers_over_presentable_limit = merge_request.approved_by_users.size - presentable_approvers_limit - approvers_over_presentable_limit = merge_request.approved_by_users.size - presentable_approvers_limit
- project = merge_request.project - 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 - 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") = link_to_member(project, approver, name: true, title: "Approved by :name")
- if approvers_over_presentable_limit.positive? - 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}" = "+ #{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-info-container
.issuable-main-info .issuable-main-info
.merge-request-title.title .title
%span.merge-request-title-text.js-onboarding-mr-item = link_to merge_request.title, merge_request_path(merge_request)
= link_to merge_request.title, merge_request_path(merge_request) %span.gl-text-gray-700
= issuable_reference(merge_request)
.issuable-info
%span.issuable-reference
= issuable_reference(merge_request)
.issuable-meta .issuable-meta
%ul.controls.d-flex.align-items-end %ul.controls
- if merge_request.approved_by_users.any? - if merge_request.approved_by_users.any?
%li.d-flex = render 'approvers', project: merge_request.project, merge_request: merge_request
= render 'approvers', merge_request: merge_request - else
%span %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') } = _('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? - if @merge_requests.present?
.card.card-small.card-without-border .compliance-dashboard
%ul.content-list.mr-list.issuable-list %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 = render partial: 'merge_request', collection: @merge_requests
= paginate @merge_requests = paginate_without_count @merge_requests
- else - else
= render 'empty_state' = render 'empty_state'
...@@ -3,34 +3,95 @@ ...@@ -3,34 +3,95 @@
require 'spec_helper' require 'spec_helper'
describe 'groups/security/compliance_dashboards/show.html.haml' do describe 'groups/security/compliance_dashboards/show.html.haml' do
set(:user) { create(:user) } let(:user) { create(:user) }
let(:group) { create(:group) } let(:group) { create(:group) }
let(:project) { create(:project, namespace: group) }
before do before do
group.add_owner(user) group.add_owner(user)
stub_licensed_features(group_level_compliance_dashboard: true)
assign(:group, group)
allow(view).to receive(:current_user) { user }
end end
it 'shows empty state if there are no merge requests' do context 'when there are no merge requests' do
render 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 end
context 'when there are merge requests' do 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 before do
mr.metrics.update!(merged_at: 1.day.ago) merge_request.metrics.update!(merged_at: 10.minutes.ago)
assign(:merge_requests, Kaminari.paginate_array([mr]).page(1)) assign(:merge_requests, Kaminari.paginate_array([merge_request]).page(0))
end end
it 'shows merge requests' do it 'renders merge requests' do
render 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 end
end end
...@@ -528,6 +528,9 @@ msgstr "" ...@@ -528,6 +528,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more" msgid "+ %{numberOfHiddenAssignees} more"
msgstr "" msgstr ""
msgid "+%{approvers} more approvers"
msgstr ""
msgid "+%{extraOptionCount} more" msgid "+%{extraOptionCount} more"
msgstr "" msgstr ""
...@@ -9809,6 +9812,9 @@ msgstr "" ...@@ -9809,6 +9812,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths" msgid "Helps reduce request volume for protected paths"
msgstr "" msgstr ""
msgid "Here you will find recent merge request activity"
msgstr ""
msgid "Hi %{username}!" msgid "Hi %{username}!"
msgstr "" msgstr ""
...@@ -12421,6 +12427,9 @@ msgstr "" ...@@ -12421,6 +12427,9 @@ msgstr ""
msgid "No application_settings found" msgid "No application_settings found"
msgstr "" msgstr ""
msgid "No approvers"
msgstr ""
msgid "No authentication methods configured." msgid "No authentication methods configured."
msgstr "" 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