Merge branch 'dz-create-nested-groups-via-ui' into 'master'
Allow creating nested group via UI See merge request !8786
This commit is contained in:
commit
059d1ae4c8
11 changed files with 115 additions and 54 deletions
|
@ -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
|
||||||
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
|
||||||
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
|
||||||
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
|
||||||
: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
|
||||||
@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
|
||||||
|
|
17
app/views/groups/_home_panel.html.haml
Normal file
17
app/views/groups/_home_panel.html.haml
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
.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
|
7
app/views/groups/_show_nav.html.haml
Normal file
7
app/views/groups/_show_nav.html.haml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
%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 @@
|
||||||
- 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 @@
|
||||||
= 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
|
|
||||||
.tab-pane.active#projects
|
|
||||||
= render "projects", projects: @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
|
|
||||||
|
|
20
app/views/groups/subgroups.html.haml
Normal file
20
app/views/groups/subgroups.html.haml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
- @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.
|
|
@ -1,3 +1,4 @@
|
||||||
|
- 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 @@
|
||||||
.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
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
- 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 @@
|
||||||
= 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
|
||||||
|
- if full_name
|
||||||
= group.full_name
|
= group.full_name
|
||||||
|
- else
|
||||||
|
= group.name
|
||||||
|
|
||||||
- if group_member
|
- if group_member
|
||||||
as
|
as
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
- @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
|
.dropdown
|
||||||
- toggle_text = projects_sort_options_hash[@sort]
|
- toggle_text = projects_sort_options_hash[@sort]
|
||||||
|
@ -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
|
||||||
|
|
4
changelogs/unreleased/dz-create-nested-groups-via-ui.yml
Normal file
4
changelogs/unreleased/dz-create-nested-groups-via-ui.yml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
title: Allow creating nested groups via UI
|
||||||
|
merge_request: 8786
|
||||||
|
author:
|
|
@ -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
|
||||||
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
|
||||||
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
|
||||||
|
|
Loading…
Reference in a new issue