Commit f39dbf3d authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Allow creating nested group via UI

Signed-off-by: default avatarDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
parent da359c46
...@@ -13,9 +13,11 @@ class GroupsController < Groups::ApplicationController ...@@ -13,9 +13,11 @@ class GroupsController < Groups::ApplicationController
before_action :authorize_create_group!, only: [:new, :create] before_action :authorize_create_group!, only: [:new, :create]
# Load group projects # Load group projects
before_action :group_projects, only: [:show, :projects, :activity, :issues, :merge_requests] before_action :group_projects, only: [:projects, :activity, :issues, :merge_requests]
before_action :event_filter, only: [:activity] before_action :event_filter, only: [:activity]
before_action :user_actions, only: [:show, :subgroups]
layout :determine_layout layout :determine_layout
def index def index
...@@ -37,13 +39,6 @@ class GroupsController < Groups::ApplicationController ...@@ -37,13 +39,6 @@ class GroupsController < Groups::ApplicationController
end end
def show def show
if current_user
@last_push = current_user.recent_push
@notification_setting = current_user.notification_settings_for(group)
end
@nested_groups = group.children
setup_projects setup_projects
respond_to do |format| respond_to do |format|
...@@ -62,6 +57,11 @@ class GroupsController < Groups::ApplicationController ...@@ -62,6 +57,11 @@ class GroupsController < Groups::ApplicationController
end end
end end
def subgroups
@nested_groups = group.children
@nested_groups = @nested_groups.search(params[:filter_groups]) if params[:filter_groups].present?
end
def activity def activity
respond_to do |format| respond_to do |format|
format.html format.html
...@@ -99,13 +99,16 @@ class GroupsController < Groups::ApplicationController ...@@ -99,13 +99,16 @@ class GroupsController < Groups::ApplicationController
protected protected
def setup_projects def setup_projects
options = {}
options[:only_owned] = true if params[:shared] == '0'
options[:only_shared] = true if params[:shared] == '1'
@projects = GroupProjectsFinder.new(group, options).execute(current_user)
@projects = @projects.includes(:namespace) @projects = @projects.includes(:namespace)
@projects = @projects.sorted_by_activity @projects = @projects.sorted_by_activity
@projects = filter_projects(@projects) @projects = filter_projects(@projects)
@projects = @projects.sort(@sort = params[:sort]) @projects = @projects.sort(@sort = params[:sort])
@projects = @projects.page(params[:page]) if params[:filter_projects].blank? @projects = @projects.page(params[:page]) if params[:filter_projects].blank?
@shared_projects = GroupProjectsFinder.new(group, only_shared: true).execute(current_user)
end end
def authorize_create_group! def authorize_create_group!
...@@ -138,7 +141,8 @@ class GroupsController < Groups::ApplicationController ...@@ -138,7 +141,8 @@ class GroupsController < Groups::ApplicationController
:public, :public,
:request_access_enabled, :request_access_enabled,
:share_with_group_lock, :share_with_group_lock,
:visibility_level :visibility_level,
:parent_id
] ]
end end
...@@ -147,4 +151,11 @@ class GroupsController < Groups::ApplicationController ...@@ -147,4 +151,11 @@ class GroupsController < Groups::ApplicationController
@events = event_filter.apply_filter(@events).with_associations @events = event_filter.apply_filter(@events).with_associations
@events = @events.limit(20).offset(params[:offset] || 0) @events = @events.limit(20).offset(params[:offset] || 0)
end end
def user_actions
if current_user
@last_push = current_user.recent_push
@notification_setting = current_user.notification_settings_for(group)
end
end
end end
.group-home-panel.text-center
%div{ class: container_class }
.avatar-container.s70.group-avatar
= image_tag group_icon(@group), class: "avatar s70 avatar-tile"
%h1.group-title
@#{@group.path}
%span.visibility-icon.has-tooltip{ data: { container: 'body' }, title: visibility_icon_description(@group) }
= visibility_level_icon(@group.visibility_level, fw: false)
- if @group.description.present?
.group-home-desc
= markdown_field(@group, :description)
- if current_user
.group-buttons
= render 'shared/members/access_request_buttons', source: @group
= render 'shared/notifications/button', notification_setting: @notification_setting
%ul.nav-links
= nav_link(page: group_path(@group)) do
= link_to group_path(@group) do
Projects
= nav_link(page: subgroups_group_path(@group)) do
= link_to subgroups_group_path(@group) do
Subgroups
...@@ -4,38 +4,12 @@ ...@@ -4,38 +4,12 @@
- if current_user - if current_user
= auto_discovery_link_tag(:atom, group_url(@group, format: :atom, private_token: current_user.private_token), title: "#{@group.name} activity") = auto_discovery_link_tag(:atom, group_url(@group, format: :atom, private_token: current_user.private_token), title: "#{@group.name} activity")
.group-home-panel.text-center = render 'groups/home_panel'
%div{ class: container_class }
.avatar-container.s70.group-avatar
= image_tag group_icon(@group), class: "avatar s70 avatar-tile"
%h1.group-title
@#{@group.path}
%span.visibility-icon.has-tooltip{ data: { container: 'body' }, title: visibility_icon_description(@group) }
= visibility_level_icon(@group.visibility_level, fw: false)
- if @group.description.present?
.group-home-desc
= markdown_field(@group, :description)
- if current_user
.group-buttons
= render 'shared/members/access_request_buttons', source: @group
= render 'shared/notifications/button', notification_setting: @notification_setting
.groups-header{ class: container_class } .groups-header{ class: container_class }
.top-area .top-area
%ul.nav-links = render 'groups/show_nav'
%li.active
= link_to "#projects", 'data-toggle' => 'tab' do
All Projects
- if @shared_projects.present?
%li
= link_to "#shared", 'data-toggle' => 'tab' do
Shared Projects
- if @nested_groups.present?
%li
= link_to "#groups", 'data-toggle' => 'tab' do
Subgroups
.nav-controls .nav-controls
= form_tag request.path, method: :get, class: 'project-filter-form', id: 'project-filter-form' do |f| = form_tag request.path, method: :get, class: 'project-filter-form', id: 'project-filter-form' do |f|
= search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control', spellcheck: false = search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control', spellcheck: false
...@@ -44,15 +18,4 @@ ...@@ -44,15 +18,4 @@
= link_to new_project_path(namespace_id: @group.id), class: 'btn btn-new pull-right' do = link_to new_project_path(namespace_id: @group.id), class: 'btn btn-new pull-right' do
New Project New Project
.tab-content = render "projects", projects: @projects
.tab-pane.active#projects
= render "projects", projects: @projects
- if @shared_projects.present?
.tab-pane#shared
= render "shared_projects", projects: @shared_projects
- if @nested_groups.present?
.tab-pane#groups
%ul.content-list
= render partial: 'shared/groups/group', collection: @nested_groups
- @no_container = true
= render 'groups/home_panel'
.groups-header{ class: container_class }
.top-area
= render 'groups/show_nav'
.nav-controls
= form_tag request.path, method: :get do |f|
= search_field_tag :filter_groups, params[:filter_groups], placeholder: 'Filter by name', class: 'form-control', spellcheck: false
- if can? current_user, :admin_group, @group
= link_to new_group_path(parent_id: @group.id), class: 'btn btn-new pull-right' do
New Subgroup
- if @nested_groups.present?
%ul.content-list
= render partial: 'shared/groups/group', collection: @nested_groups, locals: { full_name: false }
- else
.nothing-here-block
There are no subgroups to show.
- parent = Group.find_by(id: params[:parent_id] || @group.parent_id)
- if @group.persisted? - if @group.persisted?
.form-group .form-group
= f.label :name, class: 'control-label' do = f.label :name, class: 'control-label' do
...@@ -11,11 +12,15 @@ ...@@ -11,11 +12,15 @@
.col-sm-10 .col-sm-10
.input-group.gl-field-error-anchor .input-group.gl-field-error-anchor
.input-group-addon .input-group-addon
= root_url %span>= root_url
- if parent
%strong= parent.full_path + '/'
= f.text_field :path, placeholder: 'open-source', class: 'form-control', = f.text_field :path, placeholder: 'open-source', class: 'form-control',
autofocus: local_assigns[:autofocus] || false, required: true, autofocus: local_assigns[:autofocus] || false, required: true,
pattern: Gitlab::Regex::NAMESPACE_REGEX_STR_SIMPLE, pattern: Gitlab::Regex::NAMESPACE_REGEX_STR_SIMPLE,
title: 'Please choose a group name with no special characters.' title: 'Please choose a group name with no special characters.'
- if parent
= f.hidden_field :parent_id, value: parent.id
- if @group.persisted? - if @group.persisted?
.alert.alert-warning.prepend-top-10 .alert.alert-warning.prepend-top-10
......
- group_member = local_assigns[:group_member] - group_member = local_assigns[:group_member]
- full_name = true unless local_assigns[:full_name] == false
- css_class = '' unless local_assigns[:css_class] - css_class = '' unless local_assigns[:css_class]
- css_class += " no-description" if group.description.blank? - css_class += " no-description" if group.description.blank?
...@@ -28,7 +29,10 @@ ...@@ -28,7 +29,10 @@
= image_tag group_icon(group), class: "avatar s40 hidden-xs" = image_tag group_icon(group), class: "avatar s40 hidden-xs"
.title .title
= link_to group, class: 'group-name' do = link_to group, class: 'group-name' do
= group.full_name - if full_name
= group.full_name
- else
= group.name
- if group_member - if group_member
as as
......
- @sort ||= sort_value_recently_updated - @sort ||= sort_value_recently_updated
- personal = params[:personal] - personal = params[:personal]
- archived = params[:archived] - archived = params[:archived]
- shared = params[:shared]
- namespace_id = params[:namespace_id] - namespace_id = params[:namespace_id]
.dropdown.inline .dropdown.inline
- toggle_text = projects_sort_options_hash[@sort] - toggle_text = projects_sort_options_hash[@sort]
...@@ -28,3 +29,14 @@ ...@@ -28,3 +29,14 @@
%li %li
= link_to filter_projects_path(namespace_id: namespace_id, sort: @sort, personal: true), class: ("is-active" if personal.present?) do = link_to filter_projects_path(namespace_id: namespace_id, sort: @sort, personal: true), class: ("is-active" if personal.present?) do
Owned by me Owned by me
- if @group && @group.shared_projects.present?
%li.divider
%li
= link_to filter_projects_path(namespace_id: namespace_id, sort: @sort, shared: nil), class: ("is-active" unless shared.present?) do
All projects
%li
= link_to filter_projects_path(namespace_id: namespace_id, sort: @sort, shared: 0), class: ("is-active" if shared == '0') do
Hide shared projects
%li
= link_to filter_projects_path(namespace_id: namespace_id, sort: @sort, shared: 1), class: ("is-active" if shared == '1') do
Hide group projects
---
title: Allow creating nested groups via UI
merge_request: 8786
author:
...@@ -25,5 +25,6 @@ scope(path: 'groups/*id', ...@@ -25,5 +25,6 @@ scope(path: 'groups/*id',
get :merge_requests, as: :merge_requests_group get :merge_requests, as: :merge_requests_group
get :projects, as: :projects_group get :projects, as: :projects_group
get :activity, as: :activity_group get :activity, as: :activity_group
get :subgroups, as: :subgroups_group
get '/', action: :show, as: :group_canonical get '/', action: :show, as: :group_canonical
end end
...@@ -45,6 +45,23 @@ feature 'Group', feature: true do ...@@ -45,6 +45,23 @@ feature 'Group', feature: true do
end end
end end
describe 'create a nested group' do
let(:group) { create(:group, path: 'foo') }
before do
visit subgroups_group_path(group)
click_link 'New Subgroup'
end
it 'creates a nested group' do
fill_in 'Group path', with: 'bar'
click_button 'Create group'
expect(current_path).to eq(group_path('foo/bar'))
expect(page).to have_content("Group 'bar' was successfully created.")
end
end
describe 'group edit' do describe 'group edit' do
let(:group) { create(:group) } let(:group) { create(:group) }
let(:path) { edit_group_path(group) } let(:path) { edit_group_path(group) }
...@@ -117,7 +134,7 @@ feature 'Group', feature: true do ...@@ -117,7 +134,7 @@ feature 'Group', feature: true do
visit path visit path
click_link 'Subgroups' click_link 'Subgroups'
expect(page).to have_content(nested_group.full_name) expect(page).to have_content(nested_group.name)
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