Merge branch 'dz-dashboard-groups-search' into 'master'
Add filter and sorting to dashboard groups page See merge request !9619
This commit is contained in:
commit
bb062ebdb6
|
@ -35,6 +35,8 @@
|
|||
/* global Labels */
|
||||
/* global Shortcuts */
|
||||
|
||||
import GroupsList from './groups_list';
|
||||
|
||||
const ShortcutsBlob = require('./shortcuts_blob');
|
||||
const UserCallout = require('./user_callout');
|
||||
|
||||
|
@ -96,6 +98,10 @@ const UserCallout = require('./user_callout');
|
|||
case 'dashboard:todos:index':
|
||||
new gl.Todos();
|
||||
break;
|
||||
case 'dashboard:groups:index':
|
||||
case 'explore:groups:index':
|
||||
new GroupsList();
|
||||
break;
|
||||
case 'projects:milestones:new':
|
||||
case 'projects:milestones:edit':
|
||||
case 'projects:milestones:update':
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
* 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);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,5 +1,17 @@
|
|||
class Dashboard::GroupsController < Dashboard::ApplicationController
|
||||
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
|
||||
|
|
|
@ -1,8 +1,17 @@
|
|||
class Explore::GroupsController < Explore::ApplicationController
|
||||
def index
|
||||
@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.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
|
||||
|
|
|
@ -9,12 +9,20 @@ module ExploreHelper
|
|||
}
|
||||
|
||||
options = exist_opts.merge(options)
|
||||
path = request.path
|
||||
path << "?#{options.to_param}"
|
||||
path
|
||||
request_path_with_options(options)
|
||||
end
|
||||
|
||||
def filter_groups_path(options = {})
|
||||
request_path_with_options(options)
|
||||
end
|
||||
|
||||
def explore_controller?
|
||||
controller.class.name.split("::").first == "Explore"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def request_path_with_options(options = {})
|
||||
request.path + "?#{options.to_param}"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,7 +6,10 @@
|
|||
= nav_link(page: explore_groups_path) do
|
||||
= link_to explore_groups_path, title: 'Explore groups' do
|
||||
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
|
||||
New Group
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
.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 @@
|
|||
- if @group_members.empty?
|
||||
= render 'empty_state'
|
||||
- else
|
||||
%ul.content-list
|
||||
- @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'
|
||||
= render 'groups'
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
.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 @@
|
|||
- else
|
||||
= 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
|
||||
.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 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
|
||||
|
||||
- if @groups.present?
|
||||
= render 'groups'
|
||||
- else
|
||||
.nothing-here-block No public groups
|
||||
|
||||
= paginate @groups, theme: "gitlab"
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
.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
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
title: Add filter and sorting to dashboard groups page
|
||||
merge_request: 9619
|
||||
author:
|
|
@ -28,6 +28,7 @@ var config = {
|
|||
environments_folder: './environments/folder/environments_folder_bundle.js',
|
||||
filtered_search: './filtered_search/filtered_search_bundle.js',
|
||||
graphs: './graphs/graphs_bundle.js',
|
||||
groups_list: './groups_list.js',
|
||||
issuable: './issuable/issuable_bundle.js',
|
||||
merge_conflicts: './merge_conflicts/merge_conflicts_bundle.js',
|
||||
merge_request_widget: './merge_request_widget/ci_bundle.js',
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
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
|
|
@ -0,0 +1,46 @@
|
|||
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
|
Loading…
Reference in New Issue