Commit 5f229074 authored by Ezekiel Kigbo's avatar Ezekiel Kigbo

Update project list specs

Add tests to ensure search only executes with a button click or enter,
sort by Name, Last updated, Created date and Stars and tests for
Visibility filter
parent aebf22f6
......@@ -1448,10 +1448,6 @@ pre.light-well {
}
.project-filters {
.row-content-block {
border-top: 0;
}
.btn svg {
color: $gl-gray-700;
}
......@@ -1470,53 +1466,39 @@ pre.light-well {
}
}
.filtered-search-wrapper {
flex-wrap: nowrap;
flex-direction: row;
}
.filtered-search-dropdown {
width: auto;
flex-direction: row;
align-items: center;
}
.filtered-search,
.filtered-search-nav,
.filtered-search-dropdown {
display: flex;
min-width: auto;
margin: 0;
}
.filtered-search-dropdown-label {
padding: 0 0 0 16px;
font-weight: bold;
min-width: 68px;
@include media-breakpoint-down(xs) {
min-width: 60px;
}
}
.filtered-search {
margin: 0 0 0 16px;
min-width: 30%;
width: 100%;
flex: 1 1 0;
.project-filter-form .project-filter-form-field {
padding-right: 8px;
}
}
.filtered-search,
.filtered-search-dropdown {
.btn-group {
width: 100%;
@include media-breakpoint-down(lg) {
min-width: 15%;
.project-filter-form-field {
min-width: 150px;
}
}
.qa-reverse-sort {
max-width: 38px;
@include media-breakpoint-down(md) {
min-width: 30%;
}
}
.qa-reverse-sort {
max-width: 38px;
}
.filtered-search-box {
border-radius: 3px 0 0 3px;
}
......@@ -1525,41 +1507,11 @@ pre.light-well {
margin-left: 8px;
}
@include media-breakpoint-down(lg) {
.filtered-search {
min-width: 15%;
.project-filter-form-field {
min-width: 150px;
}
}
.extended-filtered-search-box {
margin: 0;
min-width: 45%;
}
}
@include media-breakpoint-down(md) {
.filtered-search:not(.extended-filtered-search-box) {
margin: 0 0 8px 16px;
min-width: 30%;
}
.extended-filtered-search-box {
margin: 0 0 8px;
min-width: 55%;
}
.filtered-search-nav {
margin: 0 0 8px;
}
.filtered-search-wrapper {
flex-wrap: wrap;
}
.filtered-search-dropdown {
width: 50%;
}
......@@ -1579,43 +1531,11 @@ pre.light-well {
width: 100%;
}
.filtered-search-wrapper {
display: flex;
flex-flow: column nowrap;
}
.filtered-search,
.filtered-search-nav,
.filtered-search-dropdown {
flex: 1 1 0;
width: 100%;
}
.filtered-search:not(.extended-filtered-search-box),
.filtered-search {
margin-left: 0;
}
.filtered-search-box {
margin: 0;
}
.filtered-search-nav .nav-block {
width: 100%;
}
.filtered-search-dropdown {
margin: 0 0 8px;
&:last-of-type {
margin: 0;
}
}
.filtered-search-dropdown-label {
padding: 0;
min-width: 60px;
}
}
}
......@@ -3,7 +3,7 @@
- inactive_class = 'btn p-2'
- active_class = 'btn p-2 active'
- is_explore_trending = local_assigns.fetch(:is_explore_trending, false)
.nav-block
.nav-block{ class: Feature.enabled?(:project_list_filter_bar) ? "w-100" : "" }
- if !Feature.enabled?(:project_list_filter_bar)
%ul.nav-links.mobile-separator.nav.nav-tabs
= nav_link(html_options: { class: ("active" unless params[:personal].present?) }) do
......@@ -11,8 +11,7 @@
= nav_link(html_options: { class: ("active" if params[:personal].present?) }) do
= link_to s_('DashboardProjects|Personal'), filter_projects_path(personal: true)
- else
-# %ul.btn-group.button-filter-group.d-flex.m-0.p-0
%div.btn-group.button-filter-group.d-flex.m-0.p-0
.btn-group.button-filter-group.d-flex.m-0.p-0
- if is_explore
= link_to s_('DashboardProjects|Trending'), trending_explore_projects_path, class: is_explore_trending ? active_class : inactive_class
= link_to s_('DashboardProjects|All'), explore_projects_path, class: is_explore_trending ? inactive_class : active_class
......
......@@ -2,28 +2,28 @@
- is_explore = local_assigns.fetch(:is_explore, false)
- is_explore_trending = local_assigns.fetch(:is_explore_trending, false)
- without_tabs = local_assigns.fetch(:without_tabs, false)
.filtered-search-block.row-content-block
.filtered-search-wrapper.d-flex
.filtered-search-block.row-content-block.bt-0
.filtered-search-wrapper.d-flex.flex-nowrap.flex-column.flex-sm-wrap.flex-sm-row.flex-xl-nowrap
- unless without_tabs
.filtered-search-nav
.filtered-search-nav.d-flex.mb-2.mb-lg-0
= render 'dashboard/projects/nav', is_explore: is_explore, is_explore_trending: is_explore_trending
.filtered-search{ class: without_tabs ? "extended-filtered-search-box" : "" }
.btn-group{ role: "group" }
.btn-group{ role: "group" }
.filtered-search-box
.filtered-search.d-flex.w-100.mb-2.mb-lg-0{ class: without_tabs ? "extended-filtered-search-box ml-0 mb-2 mb-lg-0" : "ml-0 ml-sm-3" }
.btn-group.w-100{ role: "group" }
.btn-group.w-100{ role: "group" }
.filtered-search-box.m-0
.filtered-search-box-input-container.pl-2
= render 'shared/projects/search_form', admin_view: false, search_form_placeholder: _("Search projects...")
-# TODO: since we are no longer triggering search when we type
-# we might be able to safely remove app/assets/javascripts/projects_list.js
-# we might be able to remove app/assets/javascripts/projects_list.js
%button.btn.btn-secondary{ type: 'submit', form: 'project-filter-form' }
= sprite_icon('search', size: 16, css_class: 'search-icon ')
.filtered-search-dropdown
.filtered-search-dropdown-label
.filtered-search-dropdown.d-flex.flex-row.align-items-center.mb-2.m-sm-0#filtered-search-visibility-dropdown
.filtered-search-dropdown-label.p-0.pl-sm-3.font-weight-bold
%span
= _("Visibility")
= render 'explore/projects/filter', has_label: true
.filtered-search-dropdown
.filtered-search-dropdown-label
.filtered-search-dropdown.d-flex.flex-row.align-items-center.m-sm-0#filtered-search-sorting-dropdown
.filtered-search-dropdown-label.p-0.pl-sm-3.font-weight-bold
%span
= _("Sort by")
= render 'shared/projects/sort_dropdown'
......
- form_field_classes = local_assigns[:admin_view] ? 'input-short' : ''
- form_field_classes = local_assigns[:admin_view] || !Feature.enabled?(:project_list_filter_bar) ? 'input-short js-projects-list-filter' : ''
- placeholder = local_assigns[:search_form_placeholder] ? search_form_placeholder : 'Filter by name...'
= form_tag filter_projects_path, method: :get, class: 'project-filter-form', id: 'project-filter-form' do |f|
......
- @sort ||= sort_value_latest_activity
.btn-group{ role: "group" }
.btn-group.dropdown.js-project-filter-dropdown-wrap{ role: "group" }
.btn-group.w-100{ role: "group" }
.btn-group.w-100.dropdown.js-project-filter-dropdown-wrap{ role: "group" }
- toggle_text = projects_sort_option_titles[@sort]
%button.dropdown-menu-toggle{ id: 'sort-projects-dropdown', type: 'button', data: { toggle: 'dropdown', display: 'static' }, class: 'btn btn-default' }
= toggle_text
......
---
title: Add filtering to project dashboard
merge_request: 25231
author:
type: added
......@@ -112,6 +112,14 @@ describe 'Dashboard Projects' do
expect(first('.project-row')).to have_content(project_with_most_stars.title)
end
it 'shows tabs to filter by all projects or personal' do
visit dashboard_projects_path
segmented_button = page.find('.filtered-search-nav .button-filter-group')
expect(segmented_button).to have_content 'All'
expect(segmented_button).to have_content 'Personal'
end
end
context 'when on Starred projects tab', :js do
......@@ -134,6 +142,11 @@ describe 'Dashboard Projects' do
expect(find('.nav-links li:nth-child(1) .badge-pill')).to have_content(1)
expect(find('.nav-links li:nth-child(2) .badge-pill')).to have_content(1)
end
it 'does not show tabs to filter by all projects or personal' do
visit(starred_dashboard_projects_path)
expect(page).not_to have_content '.filtered-search-nav'
end
end
describe 'with a pipeline', :clean_gitlab_redis_shared_state do
......
......@@ -14,6 +14,7 @@ describe 'Dashboard > User filters projects' do
describe 'filtering personal projects' do
before do
stub_feature_flags(project_list_filter_bar: false)
project2.add_developer(user)
visit dashboard_projects_path
......@@ -30,6 +31,7 @@ describe 'Dashboard > User filters projects' do
describe 'filtering starred projects', :js do
before do
stub_feature_flags(project_list_filter_bar: false)
user.toggle_star(project)
visit dashboard_projects_path
......@@ -42,4 +44,228 @@ describe 'Dashboard > User filters projects' do
expect(page).not_to have_content('You don\'t have starred projects yet')
end
end
describe 'without search bar', :js do
before do
stub_feature_flags(project_list_filter_bar: false)
project2.add_developer(user)
visit dashboard_projects_path
end
it 'will autocomplete searches', :js do
expect(page).to have_content 'Victorialand'
expect(page).to have_content 'Treasure'
fill_in 'project-filter-form-field', with: 'Lord beerus\n'
expect(page).not_to have_content 'Victorialand'
expect(page).not_to have_content 'Treasure'
end
end
describe 'with search bar', :js do
before do
stub_feature_flags(project_list_filter_bar: true)
project2.add_developer(user)
visit dashboard_projects_path
end
# TODO: move these helpers somewhere more useful
def click_sort_direction
page.find('.filtered-search-block #filtered-search-sorting-dropdown .reverse-sort-btn').click
end
def select_dropdown_option(selector, label)
dropdown = page.find(selector)
dropdown.click
dropdown.find('.dropdown-menu a', text: label, match: :first).click
end
def expect_to_see_projects(sorted_projects)
click_sort_direction
list = page.all('.projects-list .project-name').map(&:text)
expect(list).to match(sorted_projects)
end
describe 'Search' do
it 'will execute when i click the search button' do
expect(page).to have_content 'Victorialand'
expect(page).to have_content 'Treasure'
fill_in 'project-filter-form-field', with: 'Lord vegeta\n'
find('.filtered-search .btn').click
expect(page).not_to have_content 'Victorialand'
expect(page).not_to have_content 'Treasure'
end
it 'will execute when i press enter' do
expect(page).to have_content 'Victorialand'
expect(page).to have_content 'Treasure'
fill_in 'project-filter-form-field', with: 'Lord frieza\n'
find('#project-filter-form-field').native.send_keys :enter
expect(page).not_to have_content 'Victorialand'
expect(page).not_to have_content 'Treasure'
end
end
describe 'Filter' do
before do
priv = create(:project, :private, name: 'Private project', namespace: user.namespace)
int = create(:project, :internal, name: 'Internal project', namespace: user.namespace)
priv.add_maintainer(user)
int.add_maintainer(user)
end
it 'can filter for only private projects' do
select_dropdown_option '#filtered-search-visibility-dropdown', 'Private'
expect(current_url).to match(/visibility_level=0/)
list = page.all('.projects-list .project-name').map(&:text)
expect(list).to match(["Private project", "Treasure", "Victorialand"])
end
it 'can filter for only internal projects' do
select_dropdown_option '#filtered-search-visibility-dropdown', 'Internal'
expect(current_url).to match(/visibility_level=10/)
list = page.all('.projects-list .project-name').map(&:text)
expect(list).to match(['Internal project'])
end
it 'can filter for any project' do
select_dropdown_option '#filtered-search-visibility-dropdown', 'Any'
list = page.all('.projects-list .project-name').map(&:text)
expect(list).to match(["Internal project", "Private project", "Treasure", "Victorialand"])
end
end
describe 'Sorting' do
before do
[
{ name: 'Red ribbon army', created_at: 2.days.ago },
{ name: 'Cell saga', created_at: Time.now },
{ name: 'Frieza saga', created_at: 10.days.ago }
].each do |item|
proj = create(:project, name: item[:name], namespace: user.namespace, created_at: item[:created_at])
proj.add_developer(user)
end
user.toggle_star(project)
user.toggle_star(project2)
user2.toggle_star(project2)
end
it 'will include sorting direction' do
sorting_dropdown = page.find('.filtered-search-block #filtered-search-sorting-dropdown')
expect(sorting_dropdown).to have_css '.reverse-sort-btn'
end
it 'will have all sorting options', :js do
sorting_dropdown = page.find('.filtered-search-block #filtered-search-sorting-dropdown')
sorting_option_labels = ['Last updated', 'Created date', 'Name', 'Stars']
sorting_dropdown.click
sorting_option_labels.each do |label|
expect(sorting_dropdown).to have_content(label)
end
end
it 'will default to Last updated', :js do
page.find('.filtered-search-block #filtered-search-sorting-dropdown').click
active_sorting_option = page.first('.filtered-search-block #filtered-search-sorting-dropdown .is-active')
expect(active_sorting_option).to have_content 'Last updated'
end
context 'Sorting by name' do
it 'will sort the project list' do
select_dropdown_option '#filtered-search-sorting-dropdown', 'Name'
desc = ['Victorialand', 'Treasure', 'Red ribbon army', 'Frieza saga', 'Cell saga']
asc = ['Cell saga', 'Frieza saga', 'Red ribbon army', 'Treasure', 'Victorialand']
expect_to_see_projects(desc)
expect_to_see_projects(asc)
end
it 'will update the url query' do
select_dropdown_option '#filtered-search-sorting-dropdown', 'Name'
[/sort=name_desc/, /sort=name_asc/].each do |query_param|
click_sort_direction
expect(current_url).to match(query_param)
end
end
end
context 'Sorting by Last updated' do
it 'will sort the project list' do
select_dropdown_option '#filtered-search-sorting-dropdown', 'Last updated'
desc = ["Frieza saga", "Red ribbon army", "Victorialand", "Treasure", "Cell saga"]
asc = ["Cell saga", "Treasure", "Victorialand", "Red ribbon army", "Frieza saga"]
expect_to_see_projects(desc)
expect_to_see_projects(asc)
end
it 'will update the url query' do
select_dropdown_option '#filtered-search-sorting-dropdown', 'Last updated'
[/sort=latest_activity_asc/, /sort=latest_activity_desc/].each do |query_param|
click_sort_direction
expect(current_url).to match(query_param)
end
end
end
context 'Sorting by Created date' do
it 'will sort the project list' do
select_dropdown_option '#filtered-search-sorting-dropdown', 'Created date'
desc = ["Frieza saga", "Red ribbon army", "Victorialand", "Treasure", "Cell saga"]
asc = ["Cell saga", "Treasure", "Victorialand", "Red ribbon army", "Frieza saga"]
expect_to_see_projects(desc)
expect_to_see_projects(asc)
end
it 'will update the url query' do
select_dropdown_option '#filtered-search-sorting-dropdown', 'Created date'
[/sort=created_asc/, /sort=created_desc/].each do |query_param|
click_sort_direction
expect(current_url).to match(query_param)
end
end
end
context 'Sorting by Stars' do
it 'will sort the project list' do
select_dropdown_option '#filtered-search-sorting-dropdown', 'Stars'
desc = ["Red ribbon army", "Cell saga", "Frieza saga", "Victorialand", "Treasure"]
asc = ["Treasure", "Victorialand", "Red ribbon army", "Cell saga", "Frieza saga"]
expect_to_see_projects(desc)
expect_to_see_projects(asc)
end
it 'will update the url query' do
select_dropdown_option '#filtered-search-sorting-dropdown', 'Stars'
[/sort=stars_asc/, /sort=stars_desc/].each do |query_param|
click_sort_direction
expect(current_url).to match(query_param)
end
end
end
end
end
end
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