diff --git a/app/assets/stylesheets/content/_index.sass b/app/assets/stylesheets/content/_index.sass index 2d7b08d2ca..5f756741a0 100644 --- a/app/assets/stylesheets/content/_index.sass +++ b/app/assets/stylesheets/content/_index.sass @@ -73,4 +73,5 @@ @import content/version @import content/menus/_project_autocompletion +@import content/menus/_menu_blocks @import content/editor/index diff --git a/app/assets/stylesheets/content/menus/_menu_blocks.sass b/app/assets/stylesheets/content/menus/_menu_blocks.sass new file mode 100644 index 0000000000..09df8733d1 --- /dev/null +++ b/app/assets/stylesheets/content/menus/_menu_blocks.sass @@ -0,0 +1,24 @@ +.menu-blocks--container + display: grid + grid-template: repeat(auto-fit, 200px) / repeat(auto-fit, 200px) + grid-auto-rows: 200px + grid-column-gap: 30px + grid-row-gap: 30px + + .menu-block + border-radius: 3px + display: grid + grid-template: 110px 1fr / 1fr + grid-row-gap: 5px + justify-items: center + background: #cccccc30 + + &:hover + outline: 1px solid grey + text-decoration: none + + .menu-block--icon + font-size: 50px + align-self: end + &:before + padding-left: 10px diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb index f3aa89289e..9b92d89656 100644 --- a/app/controllers/admin_controller.rb +++ b/app/controllers/admin_controller.rb @@ -34,9 +34,11 @@ class AdminController < ApplicationController menu_item :plugins, only: [:plugins] menu_item :info, only: [:info] + menu_item :admin_overview, only: [:index] def index - redirect_to controller: 'users', action: 'index' + @menu_nodes = Redmine::MenuManager.items(:admin_menu).children + @menu_nodes.shift end def projects diff --git a/app/controllers/authentication_controller.rb b/app/controllers/authentication_controller.rb index 051a693312..b6c0697b40 100644 --- a/app/controllers/authentication_controller.rb +++ b/app/controllers/authentication_controller.rb @@ -30,6 +30,8 @@ class AuthenticationController < ApplicationController before_action :disable_api before_action :require_login + layout 'admin' + menu_item :authentication_settings accept_key_auth :index @@ -38,4 +40,27 @@ class AuthenticationController < ApplicationController format.html end end + + def edit + if params[:settings] + Settings::UpdateService + .new(user: current_user) + .call(settings: permitted_params.settings.to_h) + + flash[:notice] = l(:notice_successful_update) + redirect_to action: 'authentication_settings' + end + end + + def authentication_settings + render 'authentication_settings' + end + + def default_breadcrumb + t(:label_authentication) + end + + def show_local_breadcrumb + true + end end diff --git a/app/controllers/settings_controller.rb b/app/controllers/settings_controller.rb index 0830c73f4d..1ade188aea 100644 --- a/app/controllers/settings_controller.rb +++ b/app/controllers/settings_controller.rb @@ -29,10 +29,20 @@ class SettingsController < ApplicationController layout 'admin' - menu_item :settings before_action :require_admin + current_menu_item [:index, :edit] do + :settings + end + + current_menu_item :plugin do |controller| + plugin = Redmine::Plugin.find(controller.params[:id]) + plugin.settings[:menu_item] || :settings + rescue Redmine::PluginNotFound + :settings + end + def index edit render action: 'edit' @@ -41,17 +51,9 @@ class SettingsController < ApplicationController def edit @notifiables = Redmine::Notifiable.all if request.post? && params[:settings] - permitted_params.settings.to_h.each do |name, value| - if value.is_a?(Array) - # remove blank values in array settings - value.delete_if(&:blank?) - elsif value.is_a?(Hash) - value.delete_if { |_, v| v.blank? } - else - value = value.strip - end - Setting[name] = value - end + Settings::UpdateService + .new(user: current_user) + .call(settings: permitted_params.settings.to_h) flash[:notice] = l(:notice_successful_update) redirect_to action: 'edit', tab: params[:tab] diff --git a/app/controllers/users_settings_controller.rb b/app/controllers/users_settings_controller.rb new file mode 100644 index 0000000000..66ce0bb203 --- /dev/null +++ b/app/controllers/users_settings_controller.rb @@ -0,0 +1,57 @@ +#-- encoding: UTF-8 + +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2018 the OpenProject Foundation (OPF) +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2017 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See docs/COPYRIGHT.rdoc for more details. +#++ + +class UsersSettingsController < ::ApplicationController + layout 'admin' + menu_item :user_settings + + def index + render 'users/users_settings' + end + + def edit + if params[:settings] + Settings::UpdateService + .new(user: current_user) + .call(settings: permitted_params.settings.to_h) + + flash[:notice] = l(:notice_successful_update) + redirect_to action: 'index' + end + end + + def default_breadcrumb + t(:label_user_settings) + end + + def show_local_breadcrumb + true + end +end diff --git a/app/controllers/work_packages/settings_controller.rb b/app/controllers/work_packages/settings_controller.rb new file mode 100644 index 0000000000..ae5f746f8d --- /dev/null +++ b/app/controllers/work_packages/settings_controller.rb @@ -0,0 +1,57 @@ +#-- encoding: UTF-8 + +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2018 the OpenProject Foundation (OPF) +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2017 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See docs/COPYRIGHT.rdoc for more details. +#++ + +class WorkPackages::SettingsController < ::ApplicationController + layout 'admin' + menu_item :work_packages_setting + + def index + render 'work_packages/settings/work_package_tracking' + end + + def edit + if params[:settings] + Settings::UpdateService + .new(user: current_user) + .call(settings: permitted_params.settings.to_h) + + flash[:notice] = l(:notice_successful_update) + redirect_to action: 'index' + end + end + + def default_breadcrumb + t(:label_work_package_tracking) + end + + def show_local_breadcrumb + true + end +end diff --git a/app/helpers/settings_helper.rb b/app/helpers/settings_helper.rb index cb41ed6159..85ffe8d83c 100644 --- a/app/helpers/settings_helper.rb +++ b/app/helpers/settings_helper.rb @@ -36,10 +36,7 @@ module SettingsHelper [ { name: 'general', partial: 'settings/general', label: :label_general }, { name: 'display', partial: 'settings/display', label: :label_display }, - { name: 'authentication', partial: 'settings/authentication', label: :label_authentication }, - { name: 'users', partial: 'settings/users', label: :label_user_plural }, { name: 'projects', partial: 'settings/projects', label: :label_project_plural }, - { name: 'work_packages', partial: 'settings/work_packages', label: :label_work_package_tracking }, { name: 'notifications', partial: 'settings/notifications', label: Proc.new { User.human_attribute_name(:mail_notification) } }, { name: 'mail_handler', partial: 'settings/mail_handler', label: :label_incoming_emails }, { name: 'repositories', partial: 'settings/repositories', label: :label_repository_plural } diff --git a/app/services/settings/update_service.rb b/app/services/settings/update_service.rb new file mode 100644 index 0000000000..04c5ae3cf8 --- /dev/null +++ b/app/services/settings/update_service.rb @@ -0,0 +1,51 @@ +#-- encoding: UTF-8 + +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2019 the OpenProject Foundation (OPF) +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2017 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See doc/COPYRIGHT.rdoc for more details. +#++ + +class Settings::UpdateService < ::BaseServices::Update + attr_accessor :user + + def initialize(user) + self.user = user + end + + def call(settings:) + settings.each do |name, value| + if value.is_a?(Array) + # remove blank values in array settings + value.delete_if(&:blank?) + elsif value.is_a?(Hash) + value.delete_if { |_, v| v.blank? } + else + value = value.strip + end + Setting[name] = value + end + end +end diff --git a/app/views/admin/index.html.erb b/app/views/admin/index.html.erb new file mode 100644 index 0000000000..a68144e58d --- /dev/null +++ b/app/views/admin/index.html.erb @@ -0,0 +1,41 @@ +<%#-- copyright +OpenProject is a project management system. +Copyright (C) 2012-2018 the OpenProject Foundation (OPF) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License version 3. + +OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +Copyright (C) 2006-2017 Jean-Philippe Lang +Copyright (C) 2010-2013 the ChiliProject Team + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +See docs/COPYRIGHT.rdoc for more details. + +++#%> + +<% html_title(l(:label_administration), l(:label_overview)) -%> + +<%= toolbar title: t(:label_overview) %> + + diff --git a/app/views/admin/plugins.html.erb b/app/views/admin/plugins.html.erb index 0bf5f49044..5459da923c 100644 --- a/app/views/admin/plugins.html.erb +++ b/app/views/admin/plugins.html.erb @@ -36,7 +36,6 @@ See docs/COPYRIGHT.rdoc for more details. - <% @plugins.each do |plugin| %> @@ -53,7 +52,6 @@ See docs/COPYRIGHT.rdoc for more details. <%= h plugin.version %> <% end %> - <%= link_to(l(:button_configure), controller: '/settings', action: 'plugin', id: plugin.id) if plugin.configurable? %> <% end %> diff --git a/app/views/attribute_help_texts/_tab.html.erb b/app/views/attribute_help_texts/_tab.html.erb deleted file mode 100644 index ed9f9856a6..0000000000 --- a/app/views/attribute_help_texts/_tab.html.erb +++ /dev/null @@ -1,107 +0,0 @@ -<%#-- copyright -OpenProject is a project management system. -Copyright (C) 2012-2018 the OpenProject Foundation (OPF) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License version 3. - -OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: -Copyright (C) 2006-2017 Jean-Philippe Lang -Copyright (C) 2010-2013 the ChiliProject Team - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -See docs/COPYRIGHT.rdoc for more details. - -++#%> - -<% entries = @texts_by_type[tab[:name]] || [] %> -<% if entries.any? %> -
-
- - - - - - - - - - - - - - - - <% entries.each do |attribute_help_text| -%> - - - - - - <% end %> - -
-
-
- - <%= AttributeHelpText.human_attribute_name(:attribute_name) %> - -
-
-
-
-
- - <%= AttributeHelpText.human_attribute_name(:help_text) %> - -
-
-
-
-
- <%= link_to h(attribute_help_text.attribute_caption), - edit_attribute_help_text_path(attribute_help_text) %> - - - - - <%= link_to( - op_icon('icon icon-delete'), - (attribute_help_text_path(attribute_help_text)), - method: :delete, - data: { confirm: I18n.t(:text_are_you_sure) }, - title: t(:button_delete)) %> -
-
-
-<% else %> - <%= no_results_box %> -<% end %> - -
- <%= link_to new_attribute_help_text_path(name: tab[:name]), - { class: 'attribute-help-texts--create-button button -alt-highlight', - aria: {label: t(:'attribute_help_texts.add_new')}, - title: t(:'attribute_help_texts.add_new')} do %> - <%= op_icon('button--icon icon-add') %> - <%= t('activerecord.models.attribute_help_text') %> - <% end %> -
diff --git a/app/views/attribute_help_texts/index.html.erb b/app/views/attribute_help_texts/index.html.erb index 14e9f88ab7..5e03649688 100644 --- a/app/views/attribute_help_texts/index.html.erb +++ b/app/views/attribute_help_texts/index.html.erb @@ -34,9 +34,84 @@ See docs/COPYRIGHT.rdoc for more details. -<%= render_tabs [ - { name: 'WorkPackage', partial: 'attribute_help_texts/tab', label: :label_work_package }, - ] -%> - <% html_title(t(:label_administration), t(:'attribute_help_texts.label_plural')) -%> +<% name = 'WorkPackage' %> + +<% entries = @texts_by_type[name] || [] %> +<% if entries.any? %> +
+
+ + + + + + + + + + + + + + + + <% entries.each do |attribute_help_text| -%> + + + + + + <% end %> + +
+
+
+ + <%= AttributeHelpText.human_attribute_name(:attribute_name) %> + +
+
+
+
+
+ + <%= AttributeHelpText.human_attribute_name(:help_text) %> + +
+
+
+
+
+ <%= link_to h(attribute_help_text.attribute_caption), + edit_attribute_help_text_path(attribute_help_text) %> + + + + + <%= link_to( + op_icon('icon icon-delete'), + (attribute_help_text_path(attribute_help_text)), + method: :delete, + data: { confirm: I18n.t(:text_are_you_sure) }, + title: t(:button_delete)) %> +
+
+
+<% else %> + <%= no_results_box %> +<% end %> + +
+ <%= link_to new_attribute_help_text_path(name: name), + { class: 'attribute-help-texts--create-button button -alt-highlight', + aria: {label: t(:'attribute_help_texts.add_new')}, + title: t(:'attribute_help_texts.add_new')} do %> + <%= op_icon('button--icon icon-add') %> + <%= t('activerecord.models.attribute_help_text') %> + <% end %> +
diff --git a/app/views/settings/_authentication.html.erb b/app/views/authentication/authentication_settings.html.erb similarity index 97% rename from app/views/settings/_authentication.html.erb rename to app/views/authentication/authentication_settings.html.erb index 79745cd346..a257feef42 100644 --- a/app/views/settings/_authentication.html.erb +++ b/app/views/authentication/authentication_settings.html.erb @@ -26,9 +26,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. See docs/COPYRIGHT.rdoc for more details. ++#%> +<% html_title l(:label_administration), l(:label_authentication) -%> -<%= styled_form_tag({ action: 'edit', tab: 'authentication' }) do %> +<%= toolbar title: l(:label_authentication) %> +<%= styled_form_tag({ action: :edit }) do %>
<%= I18n.t(:general, scope: [:settings]) %> diff --git a/app/views/settings/_users.html.erb b/app/views/users/users_settings.html.erb similarity index 95% rename from app/views/settings/_users.html.erb rename to app/views/users/users_settings.html.erb index 7a01ad1736..675a8c65cb 100644 --- a/app/views/settings/_users.html.erb +++ b/app/views/users/users_settings.html.erb @@ -26,8 +26,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. See docs/COPYRIGHT.rdoc for more details. ++#%> +<% html_title l(:label_administration), l(:label_user_settings) -%> -<%= styled_form_tag({ action: 'edit', tab: 'users' }, class: 'admin-settings--form') do %> +<%= toolbar title: l(:label_user_settings) %> + +<%= styled_form_tag({ action: 'edit' }, class: 'admin-settings--form') do %>
<%= t(:'settings.user.default_preferences')%> diff --git a/app/views/settings/_enterprise_feature_hint.html.erb b/app/views/work_packages/settings/_enterprise_feature_hint.html.erb similarity index 100% rename from app/views/settings/_enterprise_feature_hint.html.erb rename to app/views/work_packages/settings/_enterprise_feature_hint.html.erb diff --git a/app/views/settings/_work_packages.html.erb b/app/views/work_packages/settings/work_package_tracking.html.erb similarity index 94% rename from app/views/settings/_work_packages.html.erb rename to app/views/work_packages/settings/work_package_tracking.html.erb index 496c14a723..951342a7f0 100644 --- a/app/views/settings/_work_packages.html.erb +++ b/app/views/work_packages/settings/work_package_tracking.html.erb @@ -26,7 +26,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. See docs/COPYRIGHT.rdoc for more details. ++#%> -<%= styled_form_tag({action: 'edit', tab: 'work_packages'}) do %> + +<% html_title l(:label_administration), l(:label_work_package_tracking) -%> + +<%= toolbar title: l(:label_work_package_tracking) %> + +<%= styled_form_tag({action: 'edit'}) do %>
<%= setting_check_box :cross_project_work_package_relations %>
<%= setting_check_box :work_package_group_assignment %>
@@ -44,7 +49,7 @@ See docs/COPYRIGHT.rdoc for more details. options[:disabled] = 'disabled' unless EnterpriseToken.allows_to?(:conditional_highlighting) } %> - <%= render partial: 'enterprise_feature_hint', + <%= render partial: 'work_packages/settings/enterprise_feature_hint', locals: { ee_feature: :conditional_highlighting, explanation: t('js.work_packages.table_configuration.upsale.attribute_highlighting'), diff --git a/config/initializers/menus.rb b/config/initializers/menus.rb index ed879e8894..e3cd3b228e 100644 --- a/config/initializers/menus.rb +++ b/config/initializers/menus.rb @@ -75,7 +75,7 @@ Redmine::MenuManager.map :account_menu do |menu| { controller: '/my', action: 'account' }, if: Proc.new { User.current.logged? } menu.push :administration, - { controller: '/users', action: 'index' }, + { controller: '/admin', action: 'index' }, if: Proc.new { User.current.admin? } menu.push :logout, :signout_path, @@ -123,35 +123,67 @@ Redmine::MenuManager.map :my_menu do |menu| end Redmine::MenuManager.map :admin_menu do |menu| + menu.push :admin_overview, + { controller: '/admin' }, + caption: :label_overview, + icon: 'icon2 icon-home', + first: true + + menu.push :users_and_permissions, + { controller: '/users_settings' }, + caption: :label_user_and_permission, + icon: 'icon2 icon-group' + + menu.push :user_settings, + { controller: '/users_settings' }, + caption: :label_settings, + parent: :users_and_permissions + menu.push :users, { controller: '/users' }, caption: :label_user_plural, - icon: 'icon2 icon-user' + parent: :users_and_permissions menu.push :groups, { controller: '/groups' }, caption: :label_group_plural, - icon: 'icon2 icon-group' + parent: :users_and_permissions + menu.push :roles, { controller: '/roles' }, caption: :label_role_and_permissions, - icon: 'icon2 icon-settings' + parent: :users_and_permissions + + menu.push :user_avatars, + { controller: '/settings', action: 'plugin', id: :openproject_avatars }, + caption: :label_avatar_plural, + parent: :users_and_permissions + + menu.push :admin_work_packages, + { controller: '/work_packages/settings' }, + caption: :label_work_package_plural, + icon: 'icon2 icon-view-timeline' + + menu.push :work_packages_setting, + { controller: '/work_packages/settings' }, + caption: :label_settings, + parent: :admin_work_packages menu.push :types, { controller: '/types' }, - caption: :label_work_package_types, - icon: 'icon2 icon-types' + caption: :label_type_plural, + parent: :admin_work_packages menu.push :statuses, { controller: '/statuses' }, - caption: :label_work_package_status_plural, - icon: 'icon2 icon-flag', + caption: :label_status, + parent: :admin_work_packages, html: { class: 'statuses' } menu.push :workflows, { controller: '/workflows', action: 'edit' }, caption: Proc.new { Workflow.model_name.human }, - icon: 'icon2 icon-workflow' + parent: :admin_work_packages menu.push :custom_fields, { controller: '/custom_fields' }, @@ -162,12 +194,12 @@ Redmine::MenuManager.map :admin_menu do |menu| menu.push :custom_actions, { controller: '/custom_actions' }, caption: :'custom_actions.plural', - icon: 'icon2 icon-play' + parent: :admin_work_packages menu.push :attribute_help_texts, { controller: '/attribute_help_texts' }, caption: :'attribute_help_texts.label_plural', - icon: 'icon2 icon-help2', + parent: :admin_work_packages, if: Proc.new { EnterpriseToken.allows_to?(:attribute_help_texts) } @@ -181,16 +213,27 @@ Redmine::MenuManager.map :admin_menu do |menu| caption: :label_system_settings, icon: 'icon2 icon-settings2' + menu.push :authentication, + { controller: '/authentication', action: 'authentication_settings' }, + caption: :label_authentication, + icon: 'icon2 icon-two-factor-authentication' + + menu.push :authentication_settings, + { controller: '/authentication', action: 'authentication_settings' }, + caption: :label_settings, + parent: :authentication + menu.push :ldap_authentication, { controller: '/ldap_auth_sources', action: 'index' }, + parent: :authentication, html: { class: 'server_authentication' }, - icon: 'icon2 icon-flag', + last: true, if: proc { !OpenProject::Configuration.disable_password_login? } menu.push :oauth_applications, { controller: '/oauth/applications', action: 'index' }, - html: { class: 'oauth_applications' }, - icon: 'icon2 icon-key' + parent: :authentication, + html: { class: 'oauth_applications' } menu.push :announcements, { controller: '/announcements', action: 'edit' }, @@ -223,6 +266,26 @@ Redmine::MenuManager.map :admin_menu do |menu| caption: :label_enterprise_edition, icon: 'icon2 icon-headset', if: proc { OpenProject::Configuration.ee_manager_visible? } + + menu.push :admin_costs, + { controller: '/settings', action: 'plugin', id: :openproject_costs }, + caption: :label_cost_object_plural, + icon: 'icon2 icon-budget' + + menu.push :costs_setting, + { controller: '/settings', action: 'plugin', id: :openproject_costs }, + caption: :label_settings, + parent: :admin_costs + + menu.push :admin_backlogs, + { controller: '/settings', action: 'plugin', id: :openproject_backlogs }, + caption: :label_backlogs, + icon: 'icon2 icon-backlogs' + + menu.push :backlogs_settings, + { controller: '/settings', action: 'plugin', id: :openproject_backlogs }, + caption: :label_settings, + parent: :admin_backlogs end Redmine::MenuManager.map :project_menu do |menu| diff --git a/config/locales/en.yml b/config/locales/en.yml index ca571fc466..9160b4acdc 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1608,6 +1608,7 @@ en: label_used_by_types: "Used by types" label_used_in_projects: "Used in projects" label_user: "User" + label_user_and_permission: "Users & Permissions" label_user_named: "User %{name}" label_user_activity: "%{value}'s activity" label_user_anonymous: "Anonymous" @@ -1620,6 +1621,7 @@ en: label_user_new: "New user" label_user_plural: "Users" label_user_search: "Search for user" + label_user_settings: "User settings" label_version_new: "New version" label_version_plural: "Versions" label_version_sharing_descendants: "With subprojects" diff --git a/config/routes.rb b/config/routes.rb index e956ec31ef..962279ab03 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -411,6 +411,11 @@ OpenProject::Application.routes.draw do get '/bulk' => 'bulk#destroy' end + scope controller: 'work_packages/settings' do + get 'work_package_tracking' => 'work_packages/settings#index' + post 'work_package_tracking' => 'work_packages/settings#edit' + end + resources :work_packages, only: [:index] do get :column_data, on: :collection # TODO move to API @@ -464,6 +469,11 @@ OpenProject::Application.routes.draw do end end + scope controller: 'users_settings' do + get 'users_settings' => 'users_settings#index' + post 'users_settings' => 'users_settings#edit' + end + resources :forums, only: [] do resources :topics, controller: 'messages', except: [:index], shallow: true do member do @@ -539,7 +549,12 @@ OpenProject::Application.routes.draw do patch 'user_settings', action: 'user_settings' end - get 'authentication' => 'authentication#index' + + scope controller: 'authentication' do + get 'authentication' => 'authentication#index' + get 'authentication_settings' => 'authentication#authentication_settings' + post 'authentication_settings' => 'authentication#edit' + end resources :colors do member do diff --git a/lib/redmine/menu_manager/menu_helper.rb b/lib/redmine/menu_manager/menu_helper.rb index 3b42cc5eab..10cda8a2df 100644 --- a/lib/redmine/menu_manager/menu_helper.rb +++ b/lib/redmine/menu_manager/menu_helper.rb @@ -61,6 +61,7 @@ module Redmine::MenuManager::MenuHelper links = [] menu_items = first_level_menu_items_for(menu, project) do |node| + @menu = menu links << render_menu_node(node, project) end @@ -145,7 +146,7 @@ module Redmine::MenuManager::MenuHelper content_tag :li, html_options do # Standard children standard_children_list = node.children.map { |child| - render_menu_node(child, project) + render_menu_node(child, project) if visible_node?(@menu, child) }.join.html_safe # Unattached children diff --git a/modules/avatars/config/locales/en.yml b/modules/avatars/config/locales/en.yml index 1cdf428d1a..abbfc326ea 100644 --- a/modules/avatars/config/locales/en.yml +++ b/modules/avatars/config/locales/en.yml @@ -1,6 +1,7 @@ # English strings go here en: label_avatar: "Avatar" + label_avatar_plural: "Avatars" label_current_avatar: "Current Avatar" label_choose_avatar: "Choose Avatar from file" message_avatar_uploaded: "Avatar changed successfully." diff --git a/modules/avatars/lib/open_project/avatars/engine.rb b/modules/avatars/lib/open_project/avatars/engine.rb index cea4fab230..c14cc124f2 100644 --- a/modules/avatars/lib/open_project/avatars/engine.rb +++ b/modules/avatars/lib/open_project/avatars/engine.rb @@ -30,7 +30,8 @@ module OpenProject::Avatars enable_gravatars: true, enable_local_avatars: true }, - partial: 'settings/openproject_avatars' + partial: 'settings/openproject_avatars', + menu_item: :user_avatars }, bundled: true do diff --git a/modules/backlogs/app/views/shared/_settings.html.erb b/modules/backlogs/app/views/shared/_settings.html.erb index f140a103aa..8f7d6f4fec 100644 --- a/modules/backlogs/app/views/shared/_settings.html.erb +++ b/modules/backlogs/app/views/shared/_settings.html.erb @@ -66,7 +66,8 @@ See doc/COPYRIGHT.rdoc for more details. }); <% end %> -<% html_title l(:label_administration), l(:label_plugins), 'Backlogs' %> +<% html_title l(:label_administration), l(:label_plugins), l(:label_backlogs) %> +
<%= styled_label_tag("settings[story_types]", l(:backlogs_story_type)) %>
diff --git a/modules/backlogs/lib/open_project/backlogs/engine.rb b/modules/backlogs/lib/open_project/backlogs/engine.rb index a2e3a144f6..679d9728fd 100644 --- a/modules/backlogs/lib/open_project/backlogs/engine.rb +++ b/modules/backlogs/lib/open_project/backlogs/engine.rb @@ -44,7 +44,8 @@ module OpenProject::Backlogs 'task_type' => nil, 'card_spec' => nil }, - partial: 'shared/settings' } + partial: 'shared/settings', + menu_item: :backlogs_settings } end include OpenProject::Plugins::ActsAsOpEngine diff --git a/modules/costs/lib/open_project/costs/engine.rb b/modules/costs/lib/open_project/costs/engine.rb index 10f37458e1..2d22bd30fd 100644 --- a/modules/costs/lib/open_project/costs/engine.rb +++ b/modules/costs/lib/open_project/costs/engine.rb @@ -30,7 +30,8 @@ module OpenProject::Costs bundled: true, settings: { default: { 'costs_currency' => 'EUR','costs_currency_format' => '%n %u' }, - partial: 'settings/openproject_costs' + partial: 'settings/openproject_costs', + menu_item: :costs_setting }, name: 'OpenProject Costs' do @@ -66,7 +67,7 @@ module OpenProject::Costs menu :admin_menu, :cost_types, { controller: '/cost_types', action: 'index' }, - icon: 'icon2 icon-cost-types', + parent: :admin_costs, caption: :label_cost_type_plural menu :project_menu, diff --git a/modules/ldap_groups/config/locales/en.yml b/modules/ldap_groups/config/locales/en.yml index d7dabbbf47..7bab241459 100644 --- a/modules/ldap_groups/config/locales/en.yml +++ b/modules/ldap_groups/config/locales/en.yml @@ -7,7 +7,7 @@ en: models: ldap_groups/synchronized_group: 'Synchronized LDAP group' ldap_groups: - label_menu_item: 'Group synchronization' + label_menu_item: 'LDAP group synchronization' label_group_key: 'LDAP group filter key' label_group_key: 'LDAP group filter key' settings: diff --git a/modules/ldap_groups/lib/open_project/ldap_groups/engine.rb b/modules/ldap_groups/lib/open_project/ldap_groups/engine.rb index 644bec0c47..39db88f268 100644 --- a/modules/ldap_groups/lib/open_project/ldap_groups/engine.rb +++ b/modules/ldap_groups/lib/open_project/ldap_groups/engine.rb @@ -15,7 +15,8 @@ module OpenProject::LdapGroups menu :admin_menu, :plugin_ldap_groups, { controller: '/ldap_groups/synchronized_groups', action: :index }, - parent: :ldap_authentication, + parent: :authentication, + last: true, caption: ->(*) { I18n.t('ldap_groups.label_menu_item') } end diff --git a/modules/openid_connect/lib/open_project/openid_connect/engine.rb b/modules/openid_connect/lib/open_project/openid_connect/engine.rb index d2bc616047..9a6510b81b 100644 --- a/modules/openid_connect/lib/open_project/openid_connect/engine.rb +++ b/modules/openid_connect/lib/open_project/openid_connect/engine.rb @@ -14,9 +14,8 @@ module OpenProject::OpenIDConnect menu :admin_menu, :plugin_openid_connect, :openid_connect_providers_path, - after: :ldap_authentication, - caption: ->(*) { I18n.t('openid_connect.menu_title') }, - icon: 'icon2 icon-openid' + parent: :authentication, + caption: ->(*) { I18n.t('openid_connect.menu_title') } end assets %w( diff --git a/modules/pdf_export/lib/open_project/pdf_export/engine.rb b/modules/pdf_export/lib/open_project/pdf_export/engine.rb index 81d19b9b51..7e816acc60 100644 --- a/modules/pdf_export/lib/open_project/pdf_export/engine.rb +++ b/modules/pdf_export/lib/open_project/pdf_export/engine.rb @@ -39,7 +39,7 @@ module OpenProject::PdfExport :export_card_configurations, { controller: '/export_card_configurations', action: 'index' }, caption: :label_export_card_configuration_plural, - icon: 'icon2 icon-ticket-down' + parent: :admin_backlogs end end end diff --git a/modules/two_factor_authentication/lib/open_project/two_factor_authentication/engine.rb b/modules/two_factor_authentication/lib/open_project/two_factor_authentication/engine.rb index 2eefc733d8..3ab964a829 100644 --- a/modules/two_factor_authentication/lib/open_project/two_factor_authentication/engine.rb +++ b/modules/two_factor_authentication/lib/open_project/two_factor_authentication/engine.rb @@ -32,9 +32,8 @@ module OpenProject::TwoFactorAuthentication :two_factor_authentication, { controller: '/two_factor_authentication/two_factor_settings', action: :show }, caption: ->(*) { I18n.t('two_factor_authentication.label_two_factor_authentication') }, - after: :ldap_authentication, - if: ->(*) { ::OpenProject::TwoFactorAuthentication::TokenStrategyManager.configurable_by_ui? }, - icon: 'icon2 icon-two-factor-authentication' + parent: :authentication, + if: ->(*) { ::OpenProject::TwoFactorAuthentication::TokenStrategyManager.configurable_by_ui? } end initializer 'two_factor_authentication.precompile_assets' do |app| diff --git a/spec/controllers/admin_controller_spec.rb b/spec/controllers/admin_controller_spec.rb new file mode 100644 index 0000000000..1855fc422a --- /dev/null +++ b/spec/controllers/admin_controller_spec.rb @@ -0,0 +1,88 @@ +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2018 the OpenProject Foundation (OPF) +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2017 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See docs/COPYRIGHT.rdoc for more details. +#++ + +require 'spec_helper' + +describe AdminController, type: :controller do + let(:user) { FactoryBot.build :admin } + + before do + allow(User).to receive(:current).and_return user + end + + describe '#index' do + it 'renders index' do + get :index + + expect(response).to be_successful + expect(response).to render_template 'index' + end + end + + describe '#plugins' do + render_views + + context 'with plugins' do + before do + Redmine::Plugin.register :foo do end + Redmine::Plugin.register :bar do end + end + + it 'renders the plugins' do + get :plugins + + expect(response).to be_successful + expect(response).to render_template 'plugins' + + expect(response.body).to have_selector('td span', text: 'Foo') + expect(response.body).to have_selector('td span', text: 'Bar') + end + end + + context 'without plugins' do + before do + Redmine::Plugin.clear + end + + it 'renders even without plugins' do + get :plugins + expect(response).to be_successful + expect(response).to render_template 'plugins' + end + end + end + + describe '#info' do + it 'renders info' do + get :info + + expect(response).to be_successful + expect(response).to render_template 'info' + end + end +end diff --git a/spec/features/auth/consent_auth_stage_spec.rb b/spec/features/auth/consent_auth_stage_spec.rb index 5939d8880d..86a104ef78 100644 --- a/spec/features/auth/consent_auth_stage_spec.rb +++ b/spec/features/auth/consent_auth_stage_spec.rb @@ -134,12 +134,10 @@ describe 'Authentication Stages', type: :feature, js: true do expect_logged_in # Update consent date - visit settings_path(tab: 'users') + visit users_settings_path find("#toggle_consent_time").set(true) - within '#tab-content-users' do - click_on 'Save' - end + click_on 'Save' expect(page).to have_selector('.flash.notice') Setting.clear_cache diff --git a/spec/features/menu_items/admin_menu_item_spec.rb b/spec/features/menu_items/admin_menu_item_spec.rb index 667f2d5594..48a47aac8d 100644 --- a/spec/features/menu_items/admin_menu_item_spec.rb +++ b/spec/features/menu_items/admin_menu_item_spec.rb @@ -45,7 +45,7 @@ feature 'Admin menu items' do expect(page).to have_selector('a', text: I18n.t('label_user_plural')) expect(page).to have_selector('a', text: I18n.t('label_role_plural')) - expect(page).to have_selector('a', text: I18n.t('label_work_package_types')) + expect(page).to have_selector('a', text: I18n.t('label_type_plural')) end end @@ -60,7 +60,7 @@ feature 'Admin menu items' do expect(page).to have_selector('a', text: I18n.t('label_user_plural')) expect(page).not_to have_selector('a', text: I18n.t('label_role_plural')) - expect(page).not_to have_selector('a', text: I18n.t('label_work_package_types')) + expect(page).not_to have_selector('a', text: I18n.t('label_type_plural')) end end end diff --git a/spec/features/users/delete_spec.rb b/spec/features/users/delete_spec.rb index 7bb3d3187c..47907e4ab1 100644 --- a/spec/features/users/delete_spec.rb +++ b/spec/features/users/delete_spec.rb @@ -107,14 +107,12 @@ describe 'user deletion: ', type: :feature, js: true do Setting.users_deletable_by_admins = 0 Setting.users_deletable_by_self = 0 - visit settings_path(tab: 'users') + visit users_settings_path find(:css, "#settings_users_deletable_by_admins").set(true) find(:css, "#settings_users_deletable_by_self").set(true) - within '#tab-content-users' do - click_on 'Save' - end + click_on 'Save' expect(Setting.users_deletable_by_admins?).to eq true expect(Setting.users_deletable_by_self?).to eq true diff --git a/spec/features/users/password_change_spec.rb b/spec/features/users/password_change_spec.rb index c118191179..ce41371dc3 100644 --- a/spec/features/users/password_change_spec.rb +++ b/spec/features/users/password_change_spec.rb @@ -118,12 +118,9 @@ describe 'random password generation', end it 'can configure and enforce password rules', js: true do - visit '/settings' + visit authentication_settings_path expect_angular_frontend_initialized - # Go to authentication - find('#tab-authentication').click - # Enforce rules # 3 of 'lowercase, uppercase, special' find('.form--check-box[value=uppercase]').set true diff --git a/spec/views/settings/_authentication.html.erb_spec.rb b/spec/views/authentication/authentication_settings.html.erb_spec.rb similarity index 97% rename from spec/views/settings/_authentication.html.erb_spec.rb rename to spec/views/authentication/authentication_settings.html.erb_spec.rb index 2ac2d86fb8..321cf804b4 100644 --- a/spec/views/settings/_authentication.html.erb_spec.rb +++ b/spec/views/authentication/authentication_settings.html.erb_spec.rb @@ -28,7 +28,7 @@ require 'spec_helper' -describe 'settings/_authentication', type: :view do +describe 'authentication/authentication_settings', type: :view do context 'with password login enabled' do before do allow(OpenProject::Configuration).to receive(:disable_password_login?).and_return(false) diff --git a/spec_legacy/functional/admin_controller_spec.rb b/spec_legacy/functional/admin_controller_spec.rb deleted file mode 100644 index 5bab60c816..0000000000 --- a/spec_legacy/functional/admin_controller_spec.rb +++ /dev/null @@ -1,102 +0,0 @@ -#-- encoding: UTF-8 - -#-- copyright -# OpenProject is a project management system. -# Copyright (C) 2012-2018 the OpenProject Foundation (OPF) -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License version 3. -# -# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: -# Copyright (C) 2006-2017 Jean-Philippe Lang -# Copyright (C) 2010-2013 the ChiliProject Team -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# See docs/COPYRIGHT.rdoc for more details. -#++ -require_relative '../legacy_spec_helper' -require 'admin_controller' - -describe AdminController, type: :controller do - render_views - - fixtures :all - - before do - User.current = nil - request.session[:user_id] = 1 # admin - end - - it 'should index' do - get :index - assert_select 'div', false, - attributes: { class: /nodata/ } - end - - it 'should no plugins' do - Redmine::Plugin.clear - - get :plugins - assert_response :success - assert_template 'plugins' - end - - it 'should plugins' do - # Register a few plugins - Redmine::Plugin.register :foo do - name 'Foo plugin' - author 'John Smith' - description 'This is a test plugin' - version '0.0.1' - settings default: { 'sample_setting' => 'value', 'foo' => 'bar' }, partial: 'foo/settings' - end - Redmine::Plugin.register :bar do - end - - get :plugins - assert_response :success - assert_template 'plugins' - - assert_select 'td', child: { tag: 'span', content: 'Foo plugin' } - assert_select 'td', child: { tag: 'span', content: 'Bar' } - end - - it 'should info' do - get :info - assert_response :success - assert_template 'info' - end - - it 'should admin menu plugin extension' do - Redmine::MenuManager.map :admin_menu do |menu| - menu.push :test_admin_menu_plugin_extension, - { controller: '/admin', action: 'plugins' }, - caption: 'Test' - end - - User.current = User.find(1) - - get :plugins - assert_response :success - assert_select 'a', - attributes: { href: '/admin/plugins' }, - content: 'Test' - - Redmine::MenuManager.map :admin_menu do |menu| - menu.delete :test_admin_menu_plugin_extension - end - end -end