Merge branch '43246-checkfilter' into 'master'
Resolve "Show a message when loading the issues / merge requests dashboard without filters" Closes #43246 See merge request gitlab-org/gitlab-ce!17961
This commit is contained in:
commit
e5d32c2c0c
|
@ -233,21 +233,21 @@ export default class SearchAutocomplete {
|
||||||
const issueItems = [
|
const issueItems = [
|
||||||
{
|
{
|
||||||
text: 'Issues assigned to me',
|
text: 'Issues assigned to me',
|
||||||
url: `${issuesPath}/?assignee_username=${userName}`,
|
url: `${issuesPath}/?assignee_id=${userId}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: "Issues I've created",
|
text: "Issues I've created",
|
||||||
url: `${issuesPath}/?author_username=${userName}`,
|
url: `${issuesPath}/?author_id=${userId}`,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
const mergeRequestItems = [
|
const mergeRequestItems = [
|
||||||
{
|
{
|
||||||
text: 'Merge requests assigned to me',
|
text: 'Merge requests assigned to me',
|
||||||
url: `${mrPath}/?assignee_username=${userName}`,
|
url: `${mrPath}/?assignee_id=${userId}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: "Merge requests I've created",
|
text: "Merge requests I've created",
|
||||||
url: `${mrPath}/?author_username=${userName}`,
|
url: `${mrPath}/?author_id=${userId}`,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
$image-widths: 80 250 306 394 430;
|
$image-widths: 80 130 250 306 394 430;
|
||||||
@each $width in $image-widths {
|
@each $width in $image-widths {
|
||||||
&.svg-#{$width} {
|
&.svg-#{$width} {
|
||||||
img,
|
img,
|
||||||
|
|
|
@ -2,9 +2,17 @@ class DashboardController < Dashboard::ApplicationController
|
||||||
include IssuesAction
|
include IssuesAction
|
||||||
include MergeRequestsAction
|
include MergeRequestsAction
|
||||||
|
|
||||||
|
FILTER_PARAMS = [
|
||||||
|
:author_id,
|
||||||
|
:assignee_id,
|
||||||
|
:milestone_title,
|
||||||
|
:label_name
|
||||||
|
].freeze
|
||||||
|
|
||||||
before_action :event_filter, only: :activity
|
before_action :event_filter, only: :activity
|
||||||
before_action :projects, only: [:issues, :merge_requests]
|
before_action :projects, only: [:issues, :merge_requests]
|
||||||
before_action :set_show_full_reference, only: [:issues, :merge_requests]
|
before_action :set_show_full_reference, only: [:issues, :merge_requests]
|
||||||
|
before_action :check_filters_presence!, only: [:issues, :merge_requests]
|
||||||
|
|
||||||
respond_to :html
|
respond_to :html
|
||||||
|
|
||||||
|
@ -39,4 +47,15 @@ class DashboardController < Dashboard::ApplicationController
|
||||||
def set_show_full_reference
|
def set_show_full_reference
|
||||||
@show_full_reference = true
|
@show_full_reference = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def check_filters_presence!
|
||||||
|
@no_filters_set = FILTER_PARAMS.none? { |k| params.key?(k) }
|
||||||
|
|
||||||
|
return unless @no_filters_set
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
format.html
|
||||||
|
format.atom { head :bad_request }
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -228,9 +228,7 @@ module ApplicationHelper
|
||||||
scope: params[:scope],
|
scope: params[:scope],
|
||||||
milestone_title: params[:milestone_title],
|
milestone_title: params[:milestone_title],
|
||||||
assignee_id: params[:assignee_id],
|
assignee_id: params[:assignee_id],
|
||||||
assignee_username: params[:assignee_username],
|
|
||||||
author_id: params[:author_id],
|
author_id: params[:author_id],
|
||||||
author_username: params[:author_username],
|
|
||||||
search: params[:search],
|
search: params[:search],
|
||||||
label_name: params[:label_name]
|
label_name: params[:label_name]
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,16 +159,18 @@ module IssuablesHelper
|
||||||
label_names.join(', ')
|
label_names.join(', ')
|
||||||
end
|
end
|
||||||
|
|
||||||
def issuables_state_counter_text(issuable_type, state)
|
def issuables_state_counter_text(issuable_type, state, display_count)
|
||||||
titles = {
|
titles = {
|
||||||
opened: "Open"
|
opened: "Open"
|
||||||
}
|
}
|
||||||
|
|
||||||
state_title = titles[state] || state.to_s.humanize
|
state_title = titles[state] || state.to_s.humanize
|
||||||
count = issuables_count_for_state(issuable_type, state)
|
|
||||||
|
|
||||||
html = content_tag(:span, state_title)
|
html = content_tag(:span, state_title)
|
||||||
html << " " << content_tag(:span, number_with_delimiter(count), class: 'badge')
|
|
||||||
|
if display_count
|
||||||
|
count = issuables_count_for_state(issuable_type, state)
|
||||||
|
html << " " << content_tag(:span, number_with_delimiter(count), class: 'badge')
|
||||||
|
end
|
||||||
|
|
||||||
html.html_safe
|
html.html_safe
|
||||||
end
|
end
|
||||||
|
@ -191,24 +193,10 @@ module IssuablesHelper
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def issuable_filter_params
|
|
||||||
[
|
|
||||||
:search,
|
|
||||||
:author_id,
|
|
||||||
:assignee_id,
|
|
||||||
:milestone_title,
|
|
||||||
:label_name
|
|
||||||
]
|
|
||||||
end
|
|
||||||
|
|
||||||
def issuable_reference(issuable)
|
def issuable_reference(issuable)
|
||||||
@show_full_reference ? issuable.to_reference(full: true) : issuable.to_reference(@group || @project)
|
@show_full_reference ? issuable.to_reference(full: true) : issuable.to_reference(@group || @project)
|
||||||
end
|
end
|
||||||
|
|
||||||
def issuable_filter_present?
|
|
||||||
issuable_filter_params.any? { |k| params.key?(k) }
|
|
||||||
end
|
|
||||||
|
|
||||||
def issuable_initial_data(issuable)
|
def issuable_initial_data(issuable)
|
||||||
data = {
|
data = {
|
||||||
endpoint: issuable_path(issuable),
|
endpoint: issuable_path(issuable),
|
||||||
|
|
|
@ -1,15 +1,19 @@
|
||||||
- @hide_top_links = true
|
- @hide_top_links = true
|
||||||
- page_title "Issues"
|
- page_title _("Issues")
|
||||||
- header_title "Issues", issues_dashboard_path(assignee_id: current_user.id)
|
- @breadcrumb_link = issues_dashboard_path(assignee_id: current_user.id)
|
||||||
= content_for :meta_tags do
|
= content_for :meta_tags do
|
||||||
= auto_discovery_link_tag(:atom, params.merge(rss_url_options), title: "#{current_user.name} issues")
|
= auto_discovery_link_tag(:atom, params.merge(rss_url_options), title: "#{current_user.name} issues")
|
||||||
|
|
||||||
.top-area
|
.top-area
|
||||||
= render 'shared/issuable/nav', type: :issues
|
= render 'shared/issuable/nav', type: :issues, display_count: !@no_filters_set
|
||||||
.nav-controls
|
.nav-controls
|
||||||
= link_to params.merge(rss_url_options), class: 'btn has-tooltip', data: { container: 'body' }, title: 'Subscribe' do
|
= link_to params.merge(rss_url_options), class: 'btn has-tooltip', data: { container: 'body' }, title: 'Subscribe' do
|
||||||
= icon('rss')
|
= icon('rss')
|
||||||
= render 'shared/new_project_item_select', path: 'issues/new', label: "New issue", with_feature_enabled: 'issues', type: :issues
|
= render 'shared/new_project_item_select', path: 'issues/new', label: "New issue", with_feature_enabled: 'issues', type: :issues
|
||||||
|
|
||||||
= render 'shared/issuable/filter', type: :issues
|
= render 'shared/issuable/filter', type: :issues
|
||||||
= render 'shared/issues'
|
|
||||||
|
- if current_user && @no_filters_set
|
||||||
|
= render 'shared/dashboard/no_filter_selected'
|
||||||
|
- else
|
||||||
|
= render 'shared/issues'
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
- @hide_top_links = true
|
- @hide_top_links = true
|
||||||
- page_title "Merge Requests"
|
- page_title _("Merge Requests")
|
||||||
- header_title "Merge Requests", merge_requests_dashboard_path(assignee_id: current_user.id)
|
- @breadcrumb_link = merge_requests_dashboard_path(assignee_id: current_user.id)
|
||||||
|
|
||||||
.top-area
|
.top-area
|
||||||
= render 'shared/issuable/nav', type: :merge_requests
|
= render 'shared/issuable/nav', type: :merge_requests, display_count: !@no_filters_set
|
||||||
.nav-controls
|
.nav-controls
|
||||||
= render 'shared/new_project_item_select', path: 'merge_requests/new', label: "New merge request", with_feature_enabled: 'merge_requests', type: :merge_requests
|
= render 'shared/new_project_item_select', path: 'merge_requests/new', label: "New merge request", with_feature_enabled: 'merge_requests', type: :merge_requests
|
||||||
|
|
||||||
= render 'shared/issuable/filter', type: :merge_requests
|
= render 'shared/issuable/filter', type: :merge_requests
|
||||||
= render 'shared/merge_requests'
|
|
||||||
|
- if current_user && @no_filters_set
|
||||||
|
= render 'shared/dashboard/no_filter_selected'
|
||||||
|
- else
|
||||||
|
= render 'shared/merge_requests'
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
.row.empty-state.text-center
|
||||||
|
.col-xs-12
|
||||||
|
.svg-130.prepend-top-default
|
||||||
|
= image_tag 'illustrations/issue-dashboard_results-without-filter.svg'
|
||||||
|
.col-xs-12
|
||||||
|
.text-content
|
||||||
|
%h4
|
||||||
|
= _("Please select at least one filter to see results")
|
|
@ -24,12 +24,9 @@
|
||||||
.filter-item.inline.labels-filter
|
.filter-item.inline.labels-filter
|
||||||
= render "shared/issuable/label_dropdown", selected: selected_labels, use_id: false, selected_toggle: params[:label_name], data_options: { field_name: "label_name[]" }
|
= render "shared/issuable/label_dropdown", selected: selected_labels, use_id: false, selected_toggle: params[:label_name], data_options: { field_name: "label_name[]" }
|
||||||
|
|
||||||
- if issuable_filter_present?
|
- unless @no_filters_set
|
||||||
.filter-item.inline.reset-filters
|
.pull-right
|
||||||
%a{ href: page_filter_path(without: issuable_filter_params) } Reset filters
|
= render 'shared/sort_dropdown'
|
||||||
|
|
||||||
.pull-right
|
|
||||||
= render 'shared/sort_dropdown'
|
|
||||||
|
|
||||||
- has_labels = @labels && @labels.any?
|
- has_labels = @labels && @labels.any?
|
||||||
.row-content-block.second-block.filtered-labels{ class: ("hidden" unless has_labels) }
|
.row-content-block.second-block.filtered-labels{ class: ("hidden" unless has_labels) }
|
||||||
|
|
|
@ -1,22 +1,23 @@
|
||||||
- type = local_assigns.fetch(:type, :issues)
|
- type = local_assigns.fetch(:type, :issues)
|
||||||
- page_context_word = type.to_s.humanize(capitalize: false)
|
- page_context_word = type.to_s.humanize(capitalize: false)
|
||||||
|
- display_count = local_assigns.fetch(:display_count, :true)
|
||||||
|
|
||||||
%ul.nav-links.issues-state-filters.mobile-separator
|
%ul.nav-links.issues-state-filters.mobile-separator
|
||||||
%li{ class: active_when(params[:state] == 'opened') }>
|
%li{ class: active_when(params[:state] == 'opened') }>
|
||||||
= link_to page_filter_path(state: 'opened', label: true), id: 'state-opened', title: "Filter by #{page_context_word} that are currently opened.", data: { state: 'opened' } do
|
= link_to page_filter_path(state: 'opened', label: true), id: 'state-opened', title: "Filter by #{page_context_word} that are currently opened.", data: { state: 'opened' } do
|
||||||
#{issuables_state_counter_text(type, :opened)}
|
#{issuables_state_counter_text(type, :opened, display_count)}
|
||||||
|
|
||||||
- if type == :merge_requests
|
- if type == :merge_requests
|
||||||
%li{ class: active_when(params[:state] == 'merged') }>
|
%li{ class: active_when(params[:state] == 'merged') }>
|
||||||
= link_to page_filter_path(state: 'merged', label: true), id: 'state-merged', title: 'Filter by merge requests that are currently merged.', data: { state: 'merged' } do
|
= link_to page_filter_path(state: 'merged', label: true), id: 'state-merged', title: 'Filter by merge requests that are currently merged.', data: { state: 'merged' } do
|
||||||
#{issuables_state_counter_text(type, :merged)}
|
#{issuables_state_counter_text(type, :merged, display_count)}
|
||||||
|
|
||||||
%li{ class: active_when(params[:state] == 'closed') }>
|
%li{ class: active_when(params[:state] == 'closed') }>
|
||||||
= link_to page_filter_path(state: 'closed', label: true), id: 'state-closed', title: 'Filter by merge requests that are currently closed and unmerged.', data: { state: 'closed' } do
|
= link_to page_filter_path(state: 'closed', label: true), id: 'state-closed', title: 'Filter by merge requests that are currently closed and unmerged.', data: { state: 'closed' } do
|
||||||
#{issuables_state_counter_text(type, :closed)}
|
#{issuables_state_counter_text(type, :closed, display_count)}
|
||||||
- else
|
- else
|
||||||
%li{ class: active_when(params[:state] == 'closed') }>
|
%li{ class: active_when(params[:state] == 'closed') }>
|
||||||
= link_to page_filter_path(state: 'closed', label: true), id: 'state-closed', title: 'Filter by issues that are currently closed.', data: { state: 'closed' } do
|
= link_to page_filter_path(state: 'closed', label: true), id: 'state-closed', title: 'Filter by issues that are currently closed.', data: { state: 'closed' } do
|
||||||
#{issuables_state_counter_text(type, :closed)}
|
#{issuables_state_counter_text(type, :closed, display_count)}
|
||||||
|
|
||||||
= render 'shared/issuable/nav_links/all', page_context_word: page_context_word, counter: issuables_state_counter_text(type, :all)
|
= render 'shared/issuable/nav_links/all', page_context_word: page_context_word, counter: issuables_state_counter_text(type, :all, display_count)
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
title: Require at least one filter when listing issues or merge requests on dashboard
|
||||||
|
page
|
||||||
|
merge_request:
|
||||||
|
author:
|
||||||
|
type: performance
|
|
@ -11,9 +11,11 @@ describe DashboardController do
|
||||||
|
|
||||||
describe 'GET issues' do
|
describe 'GET issues' do
|
||||||
it_behaves_like 'issuables list meta-data', :issue, :issues
|
it_behaves_like 'issuables list meta-data', :issue, :issues
|
||||||
|
it_behaves_like 'issuables requiring filter', :issues
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'GET merge requests' do
|
describe 'GET merge requests' do
|
||||||
it_behaves_like 'issuables list meta-data', :merge_request, :merge_requests
|
it_behaves_like 'issuables list meta-data', :merge_request, :merge_requests
|
||||||
|
it_behaves_like 'issuables requiring filter', :merge_requests
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,17 +13,26 @@ describe "Dashboard Issues Feed" do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "atom feed" do
|
describe "atom feed" do
|
||||||
it "renders atom feed via personal access token" do
|
it "returns 400 if no filter is used" do
|
||||||
personal_access_token = create(:personal_access_token, user: user)
|
personal_access_token = create(:personal_access_token, user: user)
|
||||||
|
|
||||||
visit issues_dashboard_path(:atom, private_token: personal_access_token.token)
|
visit issues_dashboard_path(:atom, private_token: personal_access_token.token)
|
||||||
|
|
||||||
|
expect(response_headers['Content-Type']).to have_content('application/atom+xml')
|
||||||
|
expect(page.status_code).to eq(400)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "renders atom feed via personal access token" do
|
||||||
|
personal_access_token = create(:personal_access_token, user: user)
|
||||||
|
|
||||||
|
visit issues_dashboard_path(:atom, private_token: personal_access_token.token, assignee_id: user.id)
|
||||||
|
|
||||||
expect(response_headers['Content-Type']).to have_content('application/atom+xml')
|
expect(response_headers['Content-Type']).to have_content('application/atom+xml')
|
||||||
expect(body).to have_selector('title', text: "#{user.name} issues")
|
expect(body).to have_selector('title', text: "#{user.name} issues")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "renders atom feed via RSS token" do
|
it "renders atom feed via RSS token" do
|
||||||
visit issues_dashboard_path(:atom, rss_token: user.rss_token)
|
visit issues_dashboard_path(:atom, rss_token: user.rss_token, assignee_id: user.id)
|
||||||
|
|
||||||
expect(response_headers['Content-Type']).to have_content('application/atom+xml')
|
expect(response_headers['Content-Type']).to have_content('application/atom+xml')
|
||||||
expect(body).to have_selector('title', text: "#{user.name} issues")
|
expect(body).to have_selector('title', text: "#{user.name} issues")
|
||||||
|
@ -44,7 +53,7 @@ describe "Dashboard Issues Feed" do
|
||||||
let!(:issue2) { create(:issue, author: user, assignees: [assignee], project: project2, description: 'test desc') }
|
let!(:issue2) { create(:issue, author: user, assignees: [assignee], project: project2, description: 'test desc') }
|
||||||
|
|
||||||
it "renders issue fields" do
|
it "renders issue fields" do
|
||||||
visit issues_dashboard_path(:atom, rss_token: user.rss_token)
|
visit issues_dashboard_path(:atom, rss_token: user.rss_token, assignee_id: assignee.id)
|
||||||
|
|
||||||
entry = find(:xpath, "//feed/entry[contains(summary/text(),'#{issue2.title}')]")
|
entry = find(:xpath, "//feed/entry[contains(summary/text(),'#{issue2.title}')]")
|
||||||
|
|
||||||
|
@ -67,7 +76,7 @@ describe "Dashboard Issues Feed" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "renders issue label and milestone info" do
|
it "renders issue label and milestone info" do
|
||||||
visit issues_dashboard_path(:atom, rss_token: user.rss_token)
|
visit issues_dashboard_path(:atom, rss_token: user.rss_token, assignee_id: assignee.id)
|
||||||
|
|
||||||
entry = find(:xpath, "//feed/entry[contains(summary/text(),'#{issue1.title}')]")
|
entry = find(:xpath, "//feed/entry[contains(summary/text(),'#{issue1.title}')]")
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,12 @@ feature 'Dashboard Issues filtering', :js do
|
||||||
visit_issues
|
visit_issues
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'without any filter' do
|
||||||
|
it 'shows error message' do
|
||||||
|
expect(page).to have_content 'Please select at least one filter to see results'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'filtering by milestone' do
|
context 'filtering by milestone' do
|
||||||
it 'shows all issues with no milestone' do
|
it 'shows all issues with no milestone' do
|
||||||
show_milestone_dropdown
|
show_milestone_dropdown
|
||||||
|
@ -27,15 +33,6 @@ feature 'Dashboard Issues filtering', :js do
|
||||||
expect(page).to have_selector('.issue', count: 1)
|
expect(page).to have_selector('.issue', count: 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'shows all issues with any milestone' do
|
|
||||||
show_milestone_dropdown
|
|
||||||
|
|
||||||
click_link 'Any Milestone'
|
|
||||||
|
|
||||||
expect(page).to have_issuable_counts(open: 2, closed: 0, all: 2)
|
|
||||||
expect(page).to have_selector('.issue', count: 2)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'shows all issues with the selected milestone' do
|
it 'shows all issues with the selected milestone' do
|
||||||
show_milestone_dropdown
|
show_milestone_dropdown
|
||||||
|
|
||||||
|
@ -68,13 +65,6 @@ feature 'Dashboard Issues filtering', :js do
|
||||||
let(:label) { create(:label, project: project) }
|
let(:label) { create(:label, project: project) }
|
||||||
let!(:label_link) { create(:label_link, label: label, target: issue) }
|
let!(:label_link) { create(:label_link, label: label, target: issue) }
|
||||||
|
|
||||||
it 'shows all issues without filter' do
|
|
||||||
page.within 'ul.content-list' do
|
|
||||||
expect(page).to have_content issue.title
|
|
||||||
expect(page).to have_content issue2.title
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'shows all issues with the selected label' do
|
it 'shows all issues with the selected label' do
|
||||||
page.within '.labels-filter' do
|
page.within '.labels-filter' do
|
||||||
find('.dropdown').click
|
find('.dropdown').click
|
||||||
|
@ -89,9 +79,13 @@ feature 'Dashboard Issues filtering', :js do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'sorting' do
|
context 'sorting' do
|
||||||
it 'shows sorted issues' do
|
before do
|
||||||
|
visit_issues(assignee_id: user.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'remembers last sorting value' do
|
||||||
sort_by('Created date')
|
sort_by('Created date')
|
||||||
visit_issues
|
visit_issues(assignee_id: user.id)
|
||||||
|
|
||||||
expect(find('.issues-filters')).to have_content('Created date')
|
expect(find('.issues-filters')).to have_content('Created date')
|
||||||
end
|
end
|
||||||
|
|
|
@ -51,15 +51,6 @@ RSpec.describe 'Dashboard Issues' do
|
||||||
expect(page).not_to have_content(other_issue.title)
|
expect(page).not_to have_content(other_issue.title)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'shows all issues' do
|
|
||||||
click_link('Reset filters')
|
|
||||||
|
|
||||||
expect(page).to have_content(authored_issue.title)
|
|
||||||
expect(page).to have_content(authored_issue_on_public_project.title)
|
|
||||||
expect(page).to have_content(assigned_issue.title)
|
|
||||||
expect(page).to have_content(other_issue.title)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'state filter tabs work' do
|
it 'state filter tabs work' do
|
||||||
find('#state-closed').click
|
find('#state-closed').click
|
||||||
expect(page).to have_current_path(issues_dashboard_url(assignee_id: current_user.id, state: 'closed'), url: true)
|
expect(page).to have_current_path(issues_dashboard_url(assignee_id: current_user.id, state: 'closed'), url: true)
|
||||||
|
|
|
@ -103,15 +103,11 @@ feature 'Dashboard Merge Requests' do
|
||||||
expect(page).not_to have_content(other_merge_request.title)
|
expect(page).not_to have_content(other_merge_request.title)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'shows all merge requests', :js do
|
it 'shows error message without filter', :js do
|
||||||
filter_item_select('Any Assignee', '.js-assignee-search')
|
filter_item_select('Any Assignee', '.js-assignee-search')
|
||||||
filter_item_select('Any Author', '.js-author-search')
|
filter_item_select('Any Author', '.js-author-search')
|
||||||
|
|
||||||
expect(page).to have_content(authored_merge_request.title)
|
expect(page).to have_content('Please select at least one filter to see results')
|
||||||
expect(page).to have_content(authored_merge_request_from_fork.title)
|
|
||||||
expect(page).to have_content(assigned_merge_request.title)
|
|
||||||
expect(page).to have_content(assigned_merge_request_from_fork.title)
|
|
||||||
expect(page).to have_content(other_merge_request.title)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'shows sorted merge requests' do
|
it 'shows sorted merge requests' do
|
||||||
|
|
|
@ -9,49 +9,25 @@ describe 'User uses header search field' do
|
||||||
before do
|
before do
|
||||||
project.add_reporter(user)
|
project.add_reporter(user)
|
||||||
sign_in(user)
|
sign_in(user)
|
||||||
|
|
||||||
visit(project_path(project))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'starts searching by pressing the enter key', :js do
|
context 'when user is in a global scope', :js do
|
||||||
fill_in('search', with: 'gitlab')
|
|
||||||
find('#search').native.send_keys(:enter)
|
|
||||||
|
|
||||||
page.within('.breadcrumbs-sub-title') do
|
|
||||||
expect(page).to have_content('Search')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'contains location badge' do
|
|
||||||
expect(page).to have_selector('.has-location-badge')
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when clicking the search field', :js do
|
|
||||||
before do
|
before do
|
||||||
|
visit(root_path)
|
||||||
page.find('#search').click
|
page.find('#search').click
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'shows category search dropdown' do
|
|
||||||
expect(page).to have_selector('.dropdown-header', text: /#{project.name}/i)
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when clicking issues' do
|
context 'when clicking issues' do
|
||||||
let!(:issue) { create(:issue, project: project, author: user, assignees: [user]) }
|
|
||||||
|
|
||||||
it 'shows assigned issues' do
|
it 'shows assigned issues' do
|
||||||
find('.dropdown-menu').click_link('Issues assigned to me')
|
find('.search-input-container .dropdown-menu').click_link('Issues assigned to me')
|
||||||
|
|
||||||
expect(page).to have_selector('.filtered-search')
|
expect(find('.js-assignee-search')).to have_content(user.name)
|
||||||
expect_tokens([assignee_token(user.name)])
|
|
||||||
expect_filtered_search_input_empty
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'shows created issues' do
|
it 'shows created issues' do
|
||||||
find('.dropdown-menu').click_link("Issues I've created")
|
find('.search-input-container .dropdown-menu').click_link("Issues I've created")
|
||||||
|
|
||||||
expect(page).to have_selector('.filtered-search')
|
expect(find('.js-author-search')).to have_content(user.name)
|
||||||
expect_tokens([author_token(user.name)])
|
|
||||||
expect_filtered_search_input_empty
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -59,32 +35,97 @@ describe 'User uses header search field' do
|
||||||
let!(:merge_request) { create(:merge_request, source_project: project, author: user, assignee: user) }
|
let!(:merge_request) { create(:merge_request, source_project: project, author: user, assignee: user) }
|
||||||
|
|
||||||
it 'shows assigned merge requests' do
|
it 'shows assigned merge requests' do
|
||||||
find('.dropdown-menu').click_link('Merge requests assigned to me')
|
find('.search-input-container .dropdown-menu').click_link('Merge requests assigned to me')
|
||||||
|
|
||||||
expect(page).to have_selector('.merge-requests-holder')
|
expect(find('.js-assignee-search')).to have_content(user.name)
|
||||||
expect_tokens([assignee_token(user.name)])
|
|
||||||
expect_filtered_search_input_empty
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'shows created merge requests' do
|
it 'shows created merge requests' do
|
||||||
find('.dropdown-menu').click_link("Merge requests I've created")
|
find('.search-input-container .dropdown-menu').click_link("Merge requests I've created")
|
||||||
|
|
||||||
expect(page).to have_selector('.merge-requests-holder')
|
expect(find('.js-author-search')).to have_content(user.name)
|
||||||
expect_tokens([author_token(user.name)])
|
|
||||||
expect_filtered_search_input_empty
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when entering text into the search field', :js do
|
context 'when user is in a project scope' do
|
||||||
before do
|
before do
|
||||||
page.within('.search-input-wrap') do
|
visit(project_path(project))
|
||||||
fill_in('search', with: project.name[0..3])
|
end
|
||||||
|
|
||||||
|
it 'starts searching by pressing the enter key', :js do
|
||||||
|
fill_in('search', with: 'gitlab')
|
||||||
|
find('#search').native.send_keys(:enter)
|
||||||
|
|
||||||
|
page.within('.breadcrumbs-sub-title') do
|
||||||
|
expect(page).to have_content('Search')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not display the category search dropdown' do
|
it 'contains location badge' do
|
||||||
expect(page).not_to have_selector('.dropdown-header', text: /#{project.name}/i)
|
expect(page).to have_selector('.has-location-badge')
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when clicking the search field', :js do
|
||||||
|
before do
|
||||||
|
page.find('#search').click
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'shows category search dropdown' do
|
||||||
|
expect(page).to have_selector('.dropdown-header', text: /#{project.name}/i)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when clicking issues' do
|
||||||
|
let!(:issue) { create(:issue, project: project, author: user, assignees: [user]) }
|
||||||
|
|
||||||
|
it 'shows assigned issues' do
|
||||||
|
find('.dropdown-menu').click_link('Issues assigned to me')
|
||||||
|
|
||||||
|
expect(page).to have_selector('.filtered-search')
|
||||||
|
expect_tokens([assignee_token(user.name)])
|
||||||
|
expect_filtered_search_input_empty
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'shows created issues' do
|
||||||
|
find('.dropdown-menu').click_link("Issues I've created")
|
||||||
|
|
||||||
|
expect(page).to have_selector('.filtered-search')
|
||||||
|
expect_tokens([author_token(user.name)])
|
||||||
|
expect_filtered_search_input_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when clicking merge requests' do
|
||||||
|
let!(:merge_request) { create(:merge_request, source_project: project, author: user, assignee: user) }
|
||||||
|
|
||||||
|
it 'shows assigned merge requests' do
|
||||||
|
find('.dropdown-menu').click_link('Merge requests assigned to me')
|
||||||
|
|
||||||
|
expect(page).to have_selector('.merge-requests-holder')
|
||||||
|
expect_tokens([assignee_token(user.name)])
|
||||||
|
expect_filtered_search_input_empty
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'shows created merge requests' do
|
||||||
|
find('.dropdown-menu').click_link("Merge requests I've created")
|
||||||
|
|
||||||
|
expect(page).to have_selector('.merge-requests-holder')
|
||||||
|
expect_tokens([author_token(user.name)])
|
||||||
|
expect_filtered_search_input_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when entering text into the search field', :js do
|
||||||
|
before do
|
||||||
|
page.within('.search-input-wrap') do
|
||||||
|
fill_in('search', with: project.name[0..3])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not display the category search dropdown' do
|
||||||
|
expect(page).not_to have_selector('.dropdown-header', text: /#{project.name}/i)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -40,22 +40,22 @@ describe IssuablesHelper do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns "Open" when state is :opened' do
|
it 'returns "Open" when state is :opened' do
|
||||||
expect(helper.issuables_state_counter_text(:issues, :opened))
|
expect(helper.issuables_state_counter_text(:issues, :opened, true))
|
||||||
.to eq('<span>Open</span> <span class="badge">42</span>')
|
.to eq('<span>Open</span> <span class="badge">42</span>')
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns "Closed" when state is :closed' do
|
it 'returns "Closed" when state is :closed' do
|
||||||
expect(helper.issuables_state_counter_text(:issues, :closed))
|
expect(helper.issuables_state_counter_text(:issues, :closed, true))
|
||||||
.to eq('<span>Closed</span> <span class="badge">42</span>')
|
.to eq('<span>Closed</span> <span class="badge">42</span>')
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns "Merged" when state is :merged' do
|
it 'returns "Merged" when state is :merged' do
|
||||||
expect(helper.issuables_state_counter_text(:merge_requests, :merged))
|
expect(helper.issuables_state_counter_text(:merge_requests, :merged, true))
|
||||||
.to eq('<span>Merged</span> <span class="badge">42</span>')
|
.to eq('<span>Merged</span> <span class="badge">42</span>')
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns "All" when state is :all' do
|
it 'returns "All" when state is :all' do
|
||||||
expect(helper.issuables_state_counter_text(:merge_requests, :all))
|
expect(helper.issuables_state_counter_text(:merge_requests, :all, true))
|
||||||
.to eq('<span>All</span> <span class="badge">42</span>')
|
.to eq('<span>All</span> <span class="badge">42</span>')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -101,27 +101,6 @@ describe IssuablesHelper do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#issuable_filter_present?' do
|
|
||||||
it 'returns true when any key is present' do
|
|
||||||
allow(helper).to receive(:params).and_return(
|
|
||||||
ActionController::Parameters.new(milestone_title: 'Velit consectetur asperiores natus delectus.',
|
|
||||||
project_id: 'gitlabhq',
|
|
||||||
scope: 'all')
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(helper.issuable_filter_present?).to be_truthy
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns false when no key is present' do
|
|
||||||
allow(helper).to receive(:params).and_return(
|
|
||||||
ActionController::Parameters.new(project_id: 'gitlabhq',
|
|
||||||
scope: 'all')
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(helper.issuable_filter_present?).to be_falsey
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#updated_at_by' do
|
describe '#updated_at_by' do
|
||||||
let(:user) { create(:user) }
|
let(:user) { create(:user) }
|
||||||
let(:unedited_issuable) { create(:issue) }
|
let(:unedited_issuable) { create(:issue) }
|
||||||
|
|
|
@ -6,8 +6,21 @@ import SearchAutocomplete from '~/search_autocomplete';
|
||||||
import '~/lib/utils/common_utils';
|
import '~/lib/utils/common_utils';
|
||||||
import * as urlUtils from '~/lib/utils/url_utility';
|
import * as urlUtils from '~/lib/utils/url_utility';
|
||||||
|
|
||||||
(function() {
|
describe('Search autocomplete dropdown', () => {
|
||||||
var assertLinks, dashboardIssuesPath, dashboardMRsPath, groupIssuesPath, groupMRsPath, groupName, mockDashboardOptions, mockGroupOptions, mockProjectOptions, projectIssuesPath, projectMRsPath, projectName, userId, widget;
|
var assertLinks,
|
||||||
|
dashboardIssuesPath,
|
||||||
|
dashboardMRsPath,
|
||||||
|
groupIssuesPath,
|
||||||
|
groupMRsPath,
|
||||||
|
groupName,
|
||||||
|
mockDashboardOptions,
|
||||||
|
mockGroupOptions,
|
||||||
|
mockProjectOptions,
|
||||||
|
projectIssuesPath,
|
||||||
|
projectMRsPath,
|
||||||
|
projectName,
|
||||||
|
userId,
|
||||||
|
widget;
|
||||||
var userName = 'root';
|
var userName = 'root';
|
||||||
|
|
||||||
widget = null;
|
widget = null;
|
||||||
|
@ -66,133 +79,126 @@ import * as urlUtils from '~/lib/utils/url_utility';
|
||||||
// Mock `gl` object in window for dashboard specific page. App code will need it.
|
// Mock `gl` object in window for dashboard specific page. App code will need it.
|
||||||
mockDashboardOptions = function() {
|
mockDashboardOptions = function() {
|
||||||
window.gl || (window.gl = {});
|
window.gl || (window.gl = {});
|
||||||
return window.gl.dashboardOptions = {
|
return (window.gl.dashboardOptions = {
|
||||||
issuesPath: dashboardIssuesPath,
|
issuesPath: dashboardIssuesPath,
|
||||||
mrPath: dashboardMRsPath
|
mrPath: dashboardMRsPath,
|
||||||
};
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Mock `gl` object in window for project specific page. App code will need it.
|
// Mock `gl` object in window for project specific page. App code will need it.
|
||||||
mockProjectOptions = function() {
|
mockProjectOptions = function() {
|
||||||
window.gl || (window.gl = {});
|
window.gl || (window.gl = {});
|
||||||
return window.gl.projectOptions = {
|
return (window.gl.projectOptions = {
|
||||||
'gitlab-ce': {
|
'gitlab-ce': {
|
||||||
issuesPath: projectIssuesPath,
|
issuesPath: projectIssuesPath,
|
||||||
mrPath: projectMRsPath,
|
mrPath: projectMRsPath,
|
||||||
projectName: projectName
|
projectName: projectName,
|
||||||
}
|
},
|
||||||
};
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
mockGroupOptions = function() {
|
mockGroupOptions = function() {
|
||||||
window.gl || (window.gl = {});
|
window.gl || (window.gl = {});
|
||||||
return window.gl.groupOptions = {
|
return (window.gl.groupOptions = {
|
||||||
'gitlab-org': {
|
'gitlab-org': {
|
||||||
issuesPath: groupIssuesPath,
|
issuesPath: groupIssuesPath,
|
||||||
mrPath: groupMRsPath,
|
mrPath: groupMRsPath,
|
||||||
projectName: groupName
|
projectName: groupName,
|
||||||
}
|
},
|
||||||
};
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
assertLinks = function(list, issuesPath, mrsPath) {
|
assertLinks = function(list, issuesPath, mrsPath) {
|
||||||
var a1, a2, a3, a4, issuesAssignedToMeLink, issuesIHaveCreatedLink, mrsAssignedToMeLink, mrsIHaveCreatedLink;
|
|
||||||
if (issuesPath) {
|
if (issuesPath) {
|
||||||
issuesAssignedToMeLink = issuesPath + "/?assignee_username=" + userName;
|
const issuesAssignedToMeLink = `a[href="${issuesPath}/?assignee_id=${userId}"]`;
|
||||||
issuesIHaveCreatedLink = issuesPath + "/?author_username=" + userName;
|
const issuesIHaveCreatedLink = `a[href="${issuesPath}/?author_id=${userId}"]`;
|
||||||
a1 = "a[href='" + issuesAssignedToMeLink + "']";
|
expect(list.find(issuesAssignedToMeLink).length).toBe(1);
|
||||||
a2 = "a[href='" + issuesIHaveCreatedLink + "']";
|
expect(list.find(issuesAssignedToMeLink).text()).toBe('Issues assigned to me');
|
||||||
expect(list.find(a1).length).toBe(1);
|
expect(list.find(issuesIHaveCreatedLink).length).toBe(1);
|
||||||
expect(list.find(a1).text()).toBe('Issues assigned to me');
|
expect(list.find(issuesIHaveCreatedLink).text()).toBe("Issues I've created");
|
||||||
expect(list.find(a2).length).toBe(1);
|
|
||||||
expect(list.find(a2).text()).toBe("Issues I've created");
|
|
||||||
}
|
}
|
||||||
mrsAssignedToMeLink = mrsPath + "/?assignee_username=" + userName;
|
const mrsAssignedToMeLink = `a[href="${mrsPath}/?assignee_id=${userId}"]`;
|
||||||
mrsIHaveCreatedLink = mrsPath + "/?author_username=" + userName;
|
const mrsIHaveCreatedLink = `a[href="${mrsPath}/?author_id=${userId}"]`;
|
||||||
a3 = "a[href='" + mrsAssignedToMeLink + "']";
|
expect(list.find(mrsAssignedToMeLink).length).toBe(1);
|
||||||
a4 = "a[href='" + mrsIHaveCreatedLink + "']";
|
expect(list.find(mrsAssignedToMeLink).text()).toBe('Merge requests assigned to me');
|
||||||
expect(list.find(a3).length).toBe(1);
|
expect(list.find(mrsIHaveCreatedLink).length).toBe(1);
|
||||||
expect(list.find(a3).text()).toBe('Merge requests assigned to me');
|
expect(list.find(mrsIHaveCreatedLink).text()).toBe("Merge requests I've created");
|
||||||
expect(list.find(a4).length).toBe(1);
|
|
||||||
return expect(list.find(a4).text()).toBe("Merge requests I've created");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('Search autocomplete dropdown', function() {
|
preloadFixtures('static/search_autocomplete.html.raw');
|
||||||
preloadFixtures('static/search_autocomplete.html.raw');
|
beforeEach(function() {
|
||||||
beforeEach(function() {
|
loadFixtures('static/search_autocomplete.html.raw');
|
||||||
loadFixtures('static/search_autocomplete.html.raw');
|
|
||||||
|
|
||||||
// Prevent turbolinks from triggering within gl_dropdown
|
// Prevent turbolinks from triggering within gl_dropdown
|
||||||
spyOn(urlUtils, 'visitUrl').and.returnValue(true);
|
spyOn(urlUtils, 'visitUrl').and.returnValue(true);
|
||||||
|
|
||||||
window.gon = {};
|
window.gon = {};
|
||||||
window.gon.current_user_id = userId;
|
window.gon.current_user_id = userId;
|
||||||
window.gon.current_username = userName;
|
window.gon.current_username = userName;
|
||||||
|
|
||||||
return widget = new SearchAutocomplete();
|
return (widget = new SearchAutocomplete());
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(function() {
|
|
||||||
// Undo what we did to the shared <body>
|
|
||||||
removeBodyAttributes();
|
|
||||||
window.gon = {};
|
|
||||||
});
|
|
||||||
it('should show Dashboard specific dropdown menu', function() {
|
|
||||||
var list;
|
|
||||||
addBodyAttributes();
|
|
||||||
mockDashboardOptions();
|
|
||||||
widget.searchInput.triggerHandler('focus');
|
|
||||||
list = widget.wrap.find('.dropdown-menu').find('ul');
|
|
||||||
return assertLinks(list, dashboardIssuesPath, dashboardMRsPath);
|
|
||||||
});
|
|
||||||
it('should show Group specific dropdown menu', function() {
|
|
||||||
var list;
|
|
||||||
addBodyAttributes('group');
|
|
||||||
mockGroupOptions();
|
|
||||||
widget.searchInput.triggerHandler('focus');
|
|
||||||
list = widget.wrap.find('.dropdown-menu').find('ul');
|
|
||||||
return assertLinks(list, groupIssuesPath, groupMRsPath);
|
|
||||||
});
|
|
||||||
it('should show Project specific dropdown menu', function() {
|
|
||||||
var list;
|
|
||||||
addBodyAttributes('project');
|
|
||||||
mockProjectOptions();
|
|
||||||
widget.searchInput.triggerHandler('focus');
|
|
||||||
list = widget.wrap.find('.dropdown-menu').find('ul');
|
|
||||||
return assertLinks(list, projectIssuesPath, projectMRsPath);
|
|
||||||
});
|
|
||||||
it('should show only Project mergeRequest dropdown menu items when project issues are disabled', function() {
|
|
||||||
addBodyAttributes('project');
|
|
||||||
disableProjectIssues();
|
|
||||||
mockProjectOptions();
|
|
||||||
widget.searchInput.triggerHandler('focus');
|
|
||||||
const list = widget.wrap.find('.dropdown-menu').find('ul');
|
|
||||||
assertLinks(list, null, projectMRsPath);
|
|
||||||
});
|
|
||||||
it('should not show category related menu if there is text in the input', function() {
|
|
||||||
var link, list;
|
|
||||||
addBodyAttributes('project');
|
|
||||||
mockProjectOptions();
|
|
||||||
widget.searchInput.val('help');
|
|
||||||
widget.searchInput.triggerHandler('focus');
|
|
||||||
list = widget.wrap.find('.dropdown-menu').find('ul');
|
|
||||||
link = "a[href='" + projectIssuesPath + "/?assignee_id=" + userId + "']";
|
|
||||||
return expect(list.find(link).length).toBe(0);
|
|
||||||
});
|
|
||||||
return it('should not submit the search form when selecting an autocomplete row with the keyboard', function() {
|
|
||||||
var ENTER = 13;
|
|
||||||
var DOWN = 40;
|
|
||||||
addBodyAttributes();
|
|
||||||
mockDashboardOptions(true);
|
|
||||||
var submitSpy = spyOnEvent('form', 'submit');
|
|
||||||
widget.searchInput.triggerHandler('focus');
|
|
||||||
widget.wrap.trigger($.Event('keydown', { which: DOWN }));
|
|
||||||
var enterKeyEvent = $.Event('keydown', { which: ENTER });
|
|
||||||
widget.searchInput.trigger(enterKeyEvent);
|
|
||||||
// This does not currently catch failing behavior. For security reasons,
|
|
||||||
// browsers will not trigger default behavior (form submit, in this
|
|
||||||
// example) on JavaScript-created keypresses.
|
|
||||||
expect(submitSpy).not.toHaveBeenTriggered();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}).call(window);
|
|
||||||
|
afterEach(function() {
|
||||||
|
// Undo what we did to the shared <body>
|
||||||
|
removeBodyAttributes();
|
||||||
|
window.gon = {};
|
||||||
|
});
|
||||||
|
it('should show Dashboard specific dropdown menu', function() {
|
||||||
|
var list;
|
||||||
|
addBodyAttributes();
|
||||||
|
mockDashboardOptions();
|
||||||
|
widget.searchInput.triggerHandler('focus');
|
||||||
|
list = widget.wrap.find('.dropdown-menu').find('ul');
|
||||||
|
return assertLinks(list, dashboardIssuesPath, dashboardMRsPath);
|
||||||
|
});
|
||||||
|
it('should show Group specific dropdown menu', function() {
|
||||||
|
var list;
|
||||||
|
addBodyAttributes('group');
|
||||||
|
mockGroupOptions();
|
||||||
|
widget.searchInput.triggerHandler('focus');
|
||||||
|
list = widget.wrap.find('.dropdown-menu').find('ul');
|
||||||
|
return assertLinks(list, groupIssuesPath, groupMRsPath);
|
||||||
|
});
|
||||||
|
it('should show Project specific dropdown menu', function() {
|
||||||
|
var list;
|
||||||
|
addBodyAttributes('project');
|
||||||
|
mockProjectOptions();
|
||||||
|
widget.searchInput.triggerHandler('focus');
|
||||||
|
list = widget.wrap.find('.dropdown-menu').find('ul');
|
||||||
|
return assertLinks(list, projectIssuesPath, projectMRsPath);
|
||||||
|
});
|
||||||
|
it('should show only Project mergeRequest dropdown menu items when project issues are disabled', function() {
|
||||||
|
addBodyAttributes('project');
|
||||||
|
disableProjectIssues();
|
||||||
|
mockProjectOptions();
|
||||||
|
widget.searchInput.triggerHandler('focus');
|
||||||
|
const list = widget.wrap.find('.dropdown-menu').find('ul');
|
||||||
|
assertLinks(list, null, projectMRsPath);
|
||||||
|
});
|
||||||
|
it('should not show category related menu if there is text in the input', function() {
|
||||||
|
var link, list;
|
||||||
|
addBodyAttributes('project');
|
||||||
|
mockProjectOptions();
|
||||||
|
widget.searchInput.val('help');
|
||||||
|
widget.searchInput.triggerHandler('focus');
|
||||||
|
list = widget.wrap.find('.dropdown-menu').find('ul');
|
||||||
|
link = "a[href='" + projectIssuesPath + '/?assignee_id=' + userId + "']";
|
||||||
|
return expect(list.find(link).length).toBe(0);
|
||||||
|
});
|
||||||
|
it('should not submit the search form when selecting an autocomplete row with the keyboard', function() {
|
||||||
|
var ENTER = 13;
|
||||||
|
var DOWN = 40;
|
||||||
|
addBodyAttributes();
|
||||||
|
mockDashboardOptions(true);
|
||||||
|
var submitSpy = spyOnEvent('form', 'submit');
|
||||||
|
widget.searchInput.triggerHandler('focus');
|
||||||
|
widget.wrap.trigger($.Event('keydown', { which: DOWN }));
|
||||||
|
var enterKeyEvent = $.Event('keydown', { which: ENTER });
|
||||||
|
widget.searchInput.trigger(enterKeyEvent);
|
||||||
|
// This does not currently catch failing behavior. For security reasons,
|
||||||
|
// browsers will not trigger default behavior (form submit, in this
|
||||||
|
// example) on JavaScript-created keypresses.
|
||||||
|
expect(submitSpy).not.toHaveBeenTriggered();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
@ -5,9 +5,9 @@ shared_examples 'issuables list meta-data' do |issuable_type, action = nil|
|
||||||
%w[fix improve/awesome].each do |source_branch|
|
%w[fix improve/awesome].each do |source_branch|
|
||||||
issuable =
|
issuable =
|
||||||
if issuable_type == :issue
|
if issuable_type == :issue
|
||||||
create(issuable_type, project: project)
|
create(issuable_type, project: project, author: project.creator)
|
||||||
else
|
else
|
||||||
create(issuable_type, source_project: project, source_branch: source_branch)
|
create(issuable_type, source_project: project, source_branch: source_branch, author: project.creator)
|
||||||
end
|
end
|
||||||
|
|
||||||
@issuable_ids << issuable.id
|
@issuable_ids << issuable.id
|
||||||
|
@ -16,7 +16,7 @@ shared_examples 'issuables list meta-data' do |issuable_type, action = nil|
|
||||||
|
|
||||||
it "creates indexed meta-data object for issuable notes and votes count" do
|
it "creates indexed meta-data object for issuable notes and votes count" do
|
||||||
if action
|
if action
|
||||||
get action
|
get action, author_id: project.creator.id
|
||||||
else
|
else
|
||||||
get :index, namespace_id: project.namespace, project_id: project
|
get :index, namespace_id: project.namespace, project_id: project
|
||||||
end
|
end
|
||||||
|
@ -35,7 +35,7 @@ shared_examples 'issuables list meta-data' do |issuable_type, action = nil|
|
||||||
it "doesn't execute any queries with false conditions" do
|
it "doesn't execute any queries with false conditions" do
|
||||||
get_action =
|
get_action =
|
||||||
if action
|
if action
|
||||||
proc { get action }
|
proc { get action, author_id: project.creator.id }
|
||||||
else
|
else
|
||||||
proc { get :index, namespace_id: project2.namespace, project_id: project2 }
|
proc { get :index, namespace_id: project2.namespace, project_id: project2 }
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
shared_examples 'issuables requiring filter' do |action|
|
||||||
|
it "doesn't load any issuables if no filter is set" do
|
||||||
|
expect_any_instance_of(described_class).not_to receive(:issuables_collection)
|
||||||
|
|
||||||
|
get action
|
||||||
|
|
||||||
|
expect(response).to render_template(action)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "loads issuables if at least one filter is set" do
|
||||||
|
expect_any_instance_of(described_class).to receive(:issuables_collection).and_call_original
|
||||||
|
|
||||||
|
get action, author_id: user.id
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue