Commit bb062ebd authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'dz-dashboard-groups-search' into 'master'

Add filter and sorting to dashboard groups page

See merge request !9619
parents e9d75a4b f440bfd2
...@@ -35,6 +35,8 @@ ...@@ -35,6 +35,8 @@
/* global Labels */ /* global Labels */
/* global Shortcuts */ /* global Shortcuts */
import GroupsList from './groups_list';
const ShortcutsBlob = require('./shortcuts_blob'); const ShortcutsBlob = require('./shortcuts_blob');
const UserCallout = require('./user_callout'); const UserCallout = require('./user_callout');
...@@ -96,6 +98,10 @@ const UserCallout = require('./user_callout'); ...@@ -96,6 +98,10 @@ const UserCallout = require('./user_callout');
case 'dashboard:todos:index': case 'dashboard:todos:index':
new gl.Todos(); new gl.Todos();
break; break;
case 'dashboard:groups:index':
case 'explore:groups:index':
new GroupsList();
break;
case 'projects:milestones:new': case 'projects:milestones:new':
case 'projects:milestones:edit': case 'projects:milestones:edit':
case 'projects:milestones:update': case 'projects:milestones:update':
......
/**
* Based on project list search.
* Makes search request for groups when user types a value in the search input.
* Updates the html content of the page with the received one.
*/
export default class GroupsList {
constructor() {
this.groupsListFilterElement = document.querySelector('.js-groups-list-filter');
this.groupsListHolderElement = document.querySelector('.js-groups-list-holder');
this.initSearch();
}
initSearch() {
this.debounceFilter = _.debounce(this.filterResults.bind(this), 500);
this.groupsListFilterElement.removeEventListener('input', this.debounceFilter);
this.groupsListFilterElement.addEventListener('input', this.debounceFilter);
}
filterResults() {
const form = document.querySelector('form#group-filter-form');
const groupFilterUrl = `${form.getAttribute('action')}?${$(form).serialize()}`;
$(this.groupsListHolderElement).fadeTo(250, 0.5);
return $.ajax({
url: form.getAttribute('action'),
data: $(form).serialize(),
type: 'GET',
dataType: 'json',
context: this,
complete() {
$(this.groupsListHolderElement).fadeTo(250, 1);
},
success(data) {
this.groupsListHolderElement.innerHTML = data.html;
// Change url so if user reload a page - search results are saved
return window.history.replaceState({
page: groupFilterUrl,
}, document.title, groupFilterUrl);
},
});
}
}
class Dashboard::GroupsController < Dashboard::ApplicationController class Dashboard::GroupsController < Dashboard::ApplicationController
def index def index
@group_members = current_user.group_members.includes(source: :route).page(params[:page]) @group_members = current_user.group_members.includes(source: :route).joins(:group)
@group_members = @group_members.merge(Group.search(params[:filter_groups])) if params[:filter_groups].present?
@group_members = @group_members.merge(Group.sort(@sort = params[:sort]))
@group_members = @group_members.page(params[:page])
respond_to do |format|
format.html
format.json do
render json: {
html: view_to_html_string("dashboard/groups/_groups", locals: { group_members: @group_members })
}
end
end
end end
end end
class Explore::GroupsController < Explore::ApplicationController class Explore::GroupsController < Explore::ApplicationController
def index def index
@groups = GroupsFinder.new.execute(current_user) @groups = GroupsFinder.new.execute(current_user)
@groups = @groups.search(params[:search]) if params[:search].present? @groups = @groups.search(params[:filter_groups]) if params[:filter_groups].present?
@groups = @groups.sort(@sort = params[:sort]) @groups = @groups.sort(@sort = params[:sort])
@groups = @groups.page(params[:page]) @groups = @groups.page(params[:page])
respond_to do |format|
format.html
format.json do
render json: {
html: view_to_html_string("explore/groups/_groups", locals: { groups: @groups })
}
end
end
end end
end end
...@@ -9,12 +9,20 @@ module ExploreHelper ...@@ -9,12 +9,20 @@ module ExploreHelper
} }
options = exist_opts.merge(options) options = exist_opts.merge(options)
path = request.path request_path_with_options(options)
path << "?#{options.to_param}" end
path
def filter_groups_path(options = {})
request_path_with_options(options)
end end
def explore_controller? def explore_controller?
controller.class.name.split("::").first == "Explore" controller.class.name.split("::").first == "Explore"
end end
private
def request_path_with_options(options = {})
request.path + "?#{options.to_param}"
end
end end
...@@ -6,7 +6,10 @@ ...@@ -6,7 +6,10 @@
= nav_link(page: explore_groups_path) do = nav_link(page: explore_groups_path) do
= link_to explore_groups_path, title: 'Explore groups' do = link_to explore_groups_path, title: 'Explore groups' do
Explore Groups Explore Groups
- if current_user.can_create_group?
.nav-controls .nav-controls
= form_tag request.path, method: :get, class: 'group-filter-form', id: 'group-filter-form' do |f|
= search_field_tag :filter_groups, params[:filter_groups], placeholder: 'Filter by name...', class: 'group-filter-form-field form-control input-short js-groups-list-filter', spellcheck: false, id: 'group-filter-form-field', tabindex: "2"
= render 'shared/groups/dropdown'
- if current_user.can_create_group?
= link_to new_group_path, class: "btn btn-new" do = link_to new_group_path, class: "btn btn-new" do
New Group New Group
.js-groups-list-holder
%ul.content-list
- @group_members.each do |group_member|
= render 'shared/groups/group', group: group_member.group, group_member: group_member
= paginate @group_members, theme: 'gitlab'
...@@ -5,9 +5,4 @@ ...@@ -5,9 +5,4 @@
- if @group_members.empty? - if @group_members.empty?
= render 'empty_state' = render 'empty_state'
- else - else
%ul.content-list = render 'groups'
- @group_members.each do |group_member|
- group = group_member.group
= render 'shared/groups/group', group: group, group_member: group_member
= paginate @group_members, theme: 'gitlab'
.js-groups-list-holder
%ul.content-list
- @groups.each do |group|
= render 'shared/groups/group', group: group
= paginate @groups, theme: 'gitlab'
...@@ -6,40 +6,10 @@ ...@@ -6,40 +6,10 @@
- else - else
= render 'explore/head' = render 'explore/head'
.row-content-block.clearfix
.pull-left
= form_tag explore_groups_path, method: :get, class: 'form-inline form-tiny' do |f|
= hidden_field_tag :sort, @sort
.form-group
= search_field_tag :search, params[:search], placeholder: "Filter by name", class: "form-control search-text-input", id: "groups_search", spellcheck: false
.form-group
= button_tag 'Search', class: "btn btn-default"
.pull-right - if @groups.present?
.dropdown.inline = render 'groups'
%button.dropdown-toggle{ type: 'button', 'data-toggle' => 'dropdown' } - else
%span.light
- if @sort.present?
= sort_options_hash[@sort]
- else
= sort_title_recently_created
= icon('chevron-down')
%ul.dropdown-menu.dropdown-menu-align-right
%li
= link_to explore_groups_path(sort: sort_value_recently_created) do
= sort_title_recently_created
= link_to explore_groups_path(sort: sort_value_oldest_created) do
= sort_title_oldest_created
= link_to explore_groups_path(sort: sort_value_recently_updated) do
= sort_title_recently_updated
= link_to explore_groups_path(sort: sort_value_oldest_updated) do
= sort_title_oldest_updated
%ul.content-list
- @groups.each do |group|
= render 'shared/groups/group', group: group
- unless @groups.present?
.nothing-here-block No public groups .nothing-here-block No public groups
= paginate @groups, theme: "gitlab" = paginate @groups, theme: "gitlab"
.dropdown.inline
%button.dropdown-toggle{ type: 'button', 'data-toggle' => 'dropdown' }
%span.light
- if @sort.present?
= sort_options_hash[@sort]
- else
= sort_title_recently_created
= icon('chevron-down')
%ul.dropdown-menu.dropdown-menu-align-right
%li
= link_to filter_groups_path(sort: sort_value_recently_created) do
= sort_title_recently_created
= link_to filter_groups_path(sort: sort_value_oldest_created) do
= sort_title_oldest_created
= link_to filter_groups_path(sort: sort_value_recently_updated) do
= sort_title_recently_updated
= link_to filter_groups_path(sort: sort_value_oldest_updated) do
= sort_title_oldest_updated
---
title: Add filter and sorting to dashboard groups page
merge_request: 9619
author:
...@@ -28,6 +28,7 @@ var config = { ...@@ -28,6 +28,7 @@ var config = {
environments_folder: './environments/folder/environments_folder_bundle.js', environments_folder: './environments/folder/environments_folder_bundle.js',
filtered_search: './filtered_search/filtered_search_bundle.js', filtered_search: './filtered_search/filtered_search_bundle.js',
graphs: './graphs/graphs_bundle.js', graphs: './graphs/graphs_bundle.js',
groups_list: './groups_list.js',
issuable: './issuable/issuable_bundle.js', issuable: './issuable/issuable_bundle.js',
merge_conflicts: './merge_conflicts/merge_conflicts_bundle.js', merge_conflicts: './merge_conflicts/merge_conflicts_bundle.js',
merge_request_widget: './merge_request_widget/ci_bundle.js', merge_request_widget: './merge_request_widget/ci_bundle.js',
......
require 'spec_helper'
describe 'Dashboard Groups page', js: true, feature: true do
include WaitForAjax
let!(:user) { create :user }
let!(:group) { create(:group) }
let!(:nested_group) { create(:group, :nested) }
let!(:another_group) { create(:group) }
before do
group.add_owner(user)
nested_group.add_owner(user)
login_as(user)
visit dashboard_groups_path
end
it 'shows groups user is member of' do
expect(page).to have_content(group.full_name)
expect(page).to have_content(nested_group.full_name)
expect(page).not_to have_content(another_group.full_name)
end
it 'filters groups' do
fill_in 'filter_groups', with: group.name
wait_for_ajax
expect(page).to have_content(group.full_name)
expect(page).not_to have_content(nested_group.full_name)
expect(page).not_to have_content(another_group.full_name)
end
it 'resets search when user cleans the input' do
fill_in 'filter_groups', with: group.name
wait_for_ajax
fill_in 'filter_groups', with: ""
wait_for_ajax
expect(page).to have_content(group.full_name)
expect(page).to have_content(nested_group.full_name)
expect(page).not_to have_content(another_group.full_name)
expect(page.all('.js-groups-list-holder .content-list li').length).to eq 2
end
end
require 'spec_helper'
describe 'Explore Groups page', js: true, feature: true do
include WaitForAjax
let!(:user) { create :user }
let!(:group) { create(:group) }
let!(:public_group) { create(:group, :public) }
let!(:private_group) { create(:group, :private) }
before do
group.add_owner(user)
login_as(user)
visit explore_groups_path
end
it 'shows groups user is member of' do
expect(page).to have_content(group.full_name)
expect(page).to have_content(public_group.full_name)
expect(page).not_to have_content(private_group.full_name)
end
it 'filters groups' do
fill_in 'filter_groups', with: group.name
wait_for_ajax
expect(page).to have_content(group.full_name)
expect(page).not_to have_content(public_group.full_name)
expect(page).not_to have_content(private_group.full_name)
end
it 'resets search when user cleans the input' do
fill_in 'filter_groups', with: group.name
wait_for_ajax
fill_in 'filter_groups', with: ""
wait_for_ajax
expect(page).to have_content(group.full_name)
expect(page).to have_content(public_group.full_name)
expect(page).not_to have_content(private_group.full_name)
expect(page.all('.js-groups-list-holder .content-list li').length).to eq 2
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