[32928] Move cost reports to a submenu (#8627)

* Move cost reports entries to submenu and adapt html structure to other submenus

* Adapt styling to wp query menu and make styles generic

* Highlight menu entry and sub entries on select, let submenu stay opened and make catergories toggleable

* Adapt styling of project and global cost reports to other submenus

* Only show category if it is not emtpy

* Fix failing spec

* WIP: Don't show empty submenu

* Add placeholder for empty queries and show categories again

* Fix menu entry highlighting

Co-authored-by: ulferts <jens.ulferts@googlemail.com>
pull/8912/head
Inga Mai 4 years ago committed by GitHub
parent 9545b2a432
commit 5a79243953
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      frontend/src/app/components/main-menu/main-menu-toggle.service.ts
  2. 30
      frontend/src/app/components/wp-query-select/wp-query-select-dropdown.component.ts
  3. 14
      frontend/src/app/components/wp-query-select/wp-query-select.template.html
  4. 9
      frontend/src/app/globals/tree-menu.ts
  5. 90
      frontend/src/global_styles/layout/_collapsible_menu.sass
  6. 1
      frontend/src/global_styles/layout/_index.sass
  7. 13
      frontend/src/global_styles/layout/_main_menu.sass
  8. 25
      frontend/src/global_styles/layout/_tree_menu.sass
  9. 1
      frontend/src/global_styles/layout/work_packages/_index.sass
  10. 27
      modules/reporting/app/controllers/cost_reports_controller.rb
  11. 27
      modules/reporting/app/models/cost_query.rb
  12. 38
      modules/reporting/app/views/cost_reports/_report_category.html.erb
  13. 22
      modules/reporting/app/views/cost_reports/_report_list.html.erb
  14. 55
      modules/reporting/app/views/cost_reports/_report_menu.html.erb
  15. 10
      modules/reporting/app/views/cost_reports/index.html.erb
  16. 1
      modules/reporting/config/locales/en.yml
  17. 8
      modules/reporting/lib/open_project/reporting/engine.rb
  18. 12
      modules/reporting/spec/features/saving_spec.rb
  19. 2
      spec/features/menu_items/query_menu_item_spec.rb
  20. 6
      spec/features/work_packages/navigation_spec.rb
  21. 2
      spec/features/work_packages/select/select_query_spec.rb
  22. 2
      spec/features/work_packages/table/queries/hidden_query_spec.rb
  23. 2
      spec/features/work_packages/table/queries/query_menu_refresh_spec.rb
  24. 4
      spec/features/work_packages/table/queries/query_menu_spec.rb
  25. 2
      spec/support/components/work_packages/query_menu.rb

@ -117,7 +117,7 @@ export class MainMenuToggleService {
public closeMenu():void {
this.setWidth(0);
window.OpenProject.guardedLocalStorage(this.localStorageStateKey, 'true');
jQuery('.wp-query-menu--search-input').blur();
jQuery('.collapsible-menu--search-input').blur();
}
public closeWhenOnMobile():void {

@ -290,16 +290,16 @@ export class WorkPackageQuerySelectDropdownComponent extends UntilDestroyedMixin
// e.g., https://community.openproject.com/wp/28197
if (sourceEvent && sourceEvent.type === 'keydown') {
this.queryResultsContainer
.find(`#wp-query-menu-item-${ui.item.auto_id} .wp-query-menu--item-link`)
.find(`#collapsible-menu-item-${ui.item.auto_id} .collapsible-menu--item-link`)
.focus();
}
return false;
},
appendTo: '.wp-query-menu--results-container',
appendTo: '.collapsible-menu--results-container',
classes: {
'ui-autocomplete': 'wp-query-menu--search-ul -inplace',
'ui-menu-divider': 'wp-query-menu--category-icon'
'ui-autocomplete': 'collapsible-menu--search-ul -inplace',
'ui-menu-divider': 'collapsible-menu--category-icon'
},
autoFocus: false, // Don't automatically select first entry since we 'open' the autocomplete on page load
minLength: 0
@ -312,18 +312,18 @@ export class WorkPackageQuerySelectDropdownComponent extends UntilDestroyedMixin
jQuery.widget('custom.querycomplete', jQuery.ui.autocomplete, {
_create: function (this:any) {
this._super();
this.widget().menu('option', 'items', '.wp-query-menu--item');
this.widget().menu('option', 'items', '.collapsible-menu--item');
this._search('');
},
_renderItem: function (this:{}, ul:any, item:IAutocompleteItem) {
const link = jQuery('<a>')
.addClass('wp-query-menu--item-link')
.addClass('collapsible-menu--item-link')
.attr('href', thisComponent.buildQueryItemUrl(item))
.text(item.label);
const li = jQuery('<li>')
.addClass(`ui-menu-item wp-query-menu--item`)
.attr('id', `wp-query-menu-item-${item.auto_id}`)
.addClass(`ui-menu-item collapsible-menu--item`)
.attr('id', `collapsible-menu-item-${item.auto_id}`)
.attr('data-category', item.category || '')
.data('ui-autocomplete-item', item) // Focus method of autocompleter needs this data for accessibility - if not set, it will throw errors
.append(link)
@ -342,9 +342,9 @@ export class WorkPackageQuerySelectDropdownComponent extends UntilDestroyedMixin
currentCategory = option.category!;
let label = thisComponent.labelFunction(currentCategory);
ul.append(`<a tabindex="0" class="wp-query-menu--category-icon wp-query-menu--category-toggle" data-category="${currentCategory}" aria-hidden="true"></a>`);
ul.append(`<a tabindex="0" class="collapsible-menu--category-icon collapsible-menu--category-toggle" data-category="${currentCategory}" aria-hidden="true"></a>`);
jQuery('<li>')
.addClass('ui-autocomplete--category wp-query-menu--category-toggle ellipsis')
.addClass('ui-autocomplete--category collapsible-menu--category-toggle ellipsis')
.attr('title', label)
.attr('data-category', currentCategory)
.text(label)
@ -356,7 +356,7 @@ export class WorkPackageQuerySelectDropdownComponent extends UntilDestroyedMixin
// Scroll to selected element if search is empty
if (thisComponent.searchInput.val() === '') {
let selected = thisComponent.queryResultsContainer.find('.wp-query-menu--item.selected');
let selected = thisComponent.queryResultsContainer.find('.collapsible-menu--item.selected');
if (selected.length > 0) {
setTimeout(() => selected[0].scrollIntoView({ behavior: 'auto', block: 'center' }), 20);
}
@ -423,7 +423,7 @@ export class WorkPackageQuerySelectDropdownComponent extends UntilDestroyedMixin
// Don't hide the categories themselves (Regression #28584)
.not('.ui-autocomplete--category')
.toggleClass('-hidden');
jQuery(`.wp-query-menu--category-icon[data-category="${category}"]`).toggleClass('-collapsed');
jQuery(`.collapsible-menu--category-icon[data-category="${category}"]`).toggleClass('-collapsed');
}
// On click of a menu item, load requested query
@ -465,7 +465,7 @@ export class WorkPackageQuerySelectDropdownComponent extends UntilDestroyedMixin
}
private highlightSelected(item:IAutocompleteItem) {
this.highlightBySelector(`#wp-query-menu-item-${item.auto_id}`);
this.highlightBySelector(`#collapsible-menu-item-${item.auto_id}`);
}
private highlightBySelector(selector:string) {
@ -490,7 +490,7 @@ export class WorkPackageQuerySelectDropdownComponent extends UntilDestroyedMixin
// Find the item from the clicked element
const target = jQuery(evt.target);
const item:IAutocompleteItem = target
.closest('.wp-query-menu--item')
.closest('.collapsible-menu--item')
.data('ui-autocomplete-item');
// Either the link is clicked with a modifier, then always cancel any propagation
@ -516,7 +516,7 @@ export class WorkPackageQuerySelectDropdownComponent extends UntilDestroyedMixin
return true;
})
.on('click keydown', '.wp-query-menu--category-toggle', (evt:JQuery.TriggeredEvent) => {
.on('click keydown', '.collapsible-menu--category-toggle', (evt:JQuery.TriggeredEvent) => {
if (evt.type === 'keydown' && evt.which !== keyCodes.ENTER) {
return true;
}

@ -1,19 +1,19 @@
<div id="querySelectDropdown" class="wp-query-menu--container">
<div class="wp-query-menu--search-container">
<div class="wp-query-menu--search-bar">
<div id="querySelectDropdown" class="collapsible-menu--container">
<div class="collapsible-menu--search-container">
<div class="collapsible-menu--search-bar">
<label for="query-title-filter"
class="hidden-for-sighted"
[textContent]="text.label" ></label>
<input #wpQueryMenuSearchInput
type="text"
class="wp-query-menu--search-input ui-autocomplete--input ellipsis"
class="collapsible-menu--search-input ui-autocomplete--input ellipsis"
name="query-title-filter"
id="query-title-filter"
[attr.placeholder]="text.search" />
<i class="icon-search wp-query-menu--search-icon"></i>
<i class="icon-search collapsible-menu--search-icon"></i>
</div>
<div #queryResultsContainer class="wp-query-menu--results-container">
<p class="wp-query-menu--no-results-container"
<div #queryResultsContainer class="collapsible-menu--results-container">
<p class="collapsible-menu--no-results-container"
[hidden]="!noResults || loading"
[textContent]="text.no_results"></p>
<div class="loading-indicator -compact" *ngIf="loading">

@ -31,12 +31,15 @@
$(function() {
// set selected page for menu tree if provided.
$('[data-selected-page].tree-menu--container').each(function(_i:number, tree:HTMLElement) {
$('[data-selected-page]').closest('.tree-menu--container').each(function(_i:number, tree:HTMLElement) {
let selectedPage = $(tree).data('selected-page');
if (selectedPage) {
let selected = $('[slug=' + selectedPage + ']', tree);
let selected = $('[slug="' + selectedPage + '"]', tree);
selected.toggleClass('-selected', true);
selected[0].scrollIntoView();
if (selected.length > 1) {
selected[0].scrollIntoView();
}
}
});

@ -1,10 +1,8 @@
$wp-query-menu-search-container-height: 35px
$collapsible-menu-search-container-height: 35px
// Wrap in global ID due to specificity issues
// from main_menu.sass :/
#querySelectDropdown
.wp-query-menu--search-ul
.collapsible-menu--container
.collapsible-menu--search-ul
+allow-vertical-scrolling
-ms-overflow-style: -ms-autohiding-scrollbar
left: 0 !important
@ -18,15 +16,15 @@ $wp-query-menu-search-container-height: 35px
@include styled-scroll-bar
.wp-query-menu--results-container
.collapsible-menu--results-container
padding-top: 5px
height: calc(100% - #{$wp-query-menu-search-container-height})
height: calc(100% - #{$collapsible-menu-search-container-height})
// Firefox needs more left padding for whatever reason
html.-browser-firefox &
padding-left: 10px
.wp-query-menu--no-results-container
.collapsible-menu--no-results-container
display: block
padding: 15px 15px 0
display: inline-block
@ -34,7 +32,7 @@ $wp-query-menu-search-container-height: 35px
white-space: normal
font-size: var(--main-menu-font-size)
.wp-query-menu--search-container
.collapsible-menu--search-container
padding-top: 10px
overflow: hidden
color: var(--main-menu-font-color)
@ -47,33 +45,33 @@ $wp-query-menu-search-container-height: 35px
background: none !important
color: inherit !important
.ui-autocomplete--category
width: 100%
padding-left: 33px
line-height: $menu-item-line-height
height: $menu-item-line-height
font-weight: normal
text-transform: uppercase
// border-bottom: 1px solid $main-menu-border-color
font-size: 0.7rem
color: var(--main-menu-fieldset-header-color)
cursor: pointer
&:hover
background: var(--main-menu-bg-hover-background)
.ui-autocomplete--category
width: auto
padding-left: 33px
line-height: $menu-item-line-height
height: $menu-item-line-height
font-weight: normal
text-transform: uppercase
// border-bottom: 1px solid $main-menu-border-color
font-size: 0.8rem
color: var(--main-menu-fieldset-header-color)
cursor: pointer
&:hover
background: var(--main-menu-bg-hover-background) !important
// The actual search input
.wp-query-menu--search-bar
height: $wp-query-menu-search-container-height
.collapsible-menu--search-bar
height: $collapsible-menu-search-container-height
position: relative
margin: 0 10px
min-width: 55px
// Category collapsible links
.wp-query-menu--category-icon
.collapsible-menu--category-icon
@include icon-font-common
// Overridden due to main menu :/
padding: initial
padding: initial !important
font-size: 0.6rem
line-height: $menu-item-line-height
height: $menu-item-line-height
@ -92,13 +90,14 @@ $wp-query-menu-search-container-height: 35px
@include icon-mixin-arrow-down1
// Add space above the category headings
.wp-query-menu--category-toggle
.collapsible-menu--category-toggle
color: var(--main-menu-fieldset-header-color) !important
margin-top: 10px
&:nth-child(1), &:nth-child(2)
margin-top: 0px
// Single result element wrapper
.wp-query-menu--item
.collapsible-menu--item
display: block !important
height: 30px !important
border-radius: 3px
@ -107,7 +106,7 @@ $wp-query-menu-search-container-height: 35px
display: none !important
&.selected
.wp-query-menu--item-link
.collapsible-menu--item-link
background: var(--main-menu-bg-selected-background)
color: var(--main-menu-selected-font-color)
@ -115,20 +114,21 @@ $wp-query-menu-search-container-height: 35px
color: var(--main-menu-font-color)
// Link within element wrapper
.wp-query-menu--item-link
.collapsible-menu--item-link
@include text-shortener
color: var(--main-menu-font-color)
color: var(--main-menu-font-color) !important
padding: 0px 2px 0px 33px !important
margin: 0
line-height: 30px
margin: 0 !important
line-height: 30px !important
height: 30px !important
text-decoration: none !important
&:hover, &:focus, &:active
background: var(--main-menu-bg-hover-background)
color: var(--main-menu-hover-font-color)
background: var(--main-menu-bg-hover-background) !important
color: var(--main-menu-hover-font-color) !important
// Rule complexed for specificity issues
input[type="text"].wp-query-menu--search-input
input[type="text"].collapsible-menu--search-input
color: var(--main-menu-font-color)
width: 100%
height: 35px
@ -147,9 +147,23 @@ $wp-query-menu-search-container-height: 35px
opacity: 0.5
@include text-shortener
.wp-query-menu--search-icon
.collapsible-menu--search-icon
position: absolute
top: 5px
right: 10px
color: var(--main-menu-font-color)
opacity: 0.5
.collapsible-menu--submenu
margin-bottom: 10px
.collapsible-menu--placeholder
@include text-shortener
color: var(--main-menu-font-color)
font-size: var(--main-menu-font-size)
padding: 0 10px
#sidebar
// Cancel out the sidebar padding
.collapsible-menu--container
margin: 0 -15px

@ -38,6 +38,7 @@
@import breadcrumb
@import main_menu
@import main_menu_mobile
@import collapsible_menu
@import colors
@import drop_down
@import drop_down_mobile

@ -55,8 +55,8 @@ $menu-item-line-height: 30px
.menu_root.closed,
.menu_root > li.open,
wp-query-select,
.wp-query-menu--container,
.wp-query-menu--search-container,
.collapsible-menu--container,
.collapsible-menu--search-container,
.main-menu--children > li.partial:only-child
height: 100%
@ -294,10 +294,11 @@ a.main-menu--parent-node
margin-top: 0
a, a:link
color: var(--main-menu-sidebar-link-color)
display: inline
position: static
text-decoration: underline
&:not(.collapsible-menu--item-link):not(.collapsible-menu--category-icon)
color: var(--main-menu-sidebar-link-color)
display: inline
position: static
text-decoration: underline
a:hover
text-decoration: underline

@ -1,24 +1,26 @@
$hierarchy-span-width: 25px
$tree-menu-item-height: 30px
.tree-menu--container
padding-top: 10px
#main-menu ul ul.main-menu--children ul.pages-hierarchy,
div.wiki ul.pages-hierarchy,
.pages-hierarchy
line-height: $tree-menu-item-height
margin-left: 0
padding-left: 0
overflow-x: hidden
.tree-menu--title
display: inline-block
width: calc(100% - #{$hierarchy-span-width})
width: inherit
vertical-align: bottom
height: $tree-menu-item-height
line-height: $tree-menu-item-height
text-decoration: none !important
.tree-menu--hierarchy-span
display: inline-block
width: $hierarchy-span-width
padding-left: 8px
line-height: $tree-menu-item-height
.tree-menu--hierarchy-indicator-icon,
@ -33,6 +35,7 @@ div.wiki ul.pages-hierarchy,
color: var(--content-link-color)
height: $tree-menu-item-height
line-height: $tree-menu-item-height
text-decoration: none !important
&:hover
text-decoration: none
@ -53,10 +56,11 @@ div.wiki ul.pages-hierarchy,
@include icon-common
@extend .icon-arrow-down1
font-size: 0.6rem
padding-right: 10px
&.-with-hierarchy
.-with-hierarchy
padding-left: 18px
padding-left: 22px
.-hierarchy-collapsed
> .tree-menu--item > .tree-menu--hierarchy-span > .tree-menu--hierarchy-indicator > .tree-menu--hierarchy-indicator-icon
@ -76,15 +80,16 @@ div.wiki ul.pages-hierarchy,
width: 100%
border-radius: 3px
line-height: $tree-menu-item-height
height: $tree-menu-item-height
padding: 0 10px
overflow-x: hidden
&.-selected
background: var(--drop-down-selected-bg-color)
background: var(--main-menu-bg-hover-background)
.tree-menu--title
color: var(--drop-down-selected-font-color)
color: var(--main-menu-hover-font-color)
&:hover
background: var(--drop-down-hover-bg-color)
background: var(--main-menu-bg-hover-background)
.tree-menu--title
color: var(--drop-down-hover-font-color)
color: var(--main-menu-hover-font-color)

@ -4,4 +4,3 @@
@import full_view
@import mobile
@import print
@import query_menu

@ -48,8 +48,6 @@ class CostReportsController < ApplicationController
helper_method :cost_types
helper_method :cost_type
helper_method :unit_id
helper_method :public_queries
helper_method :private_queries
attr_accessor :report_engine
helper_method :current_user
@ -95,7 +93,7 @@ class CostReportsController < ApplicationController
end
end
current_menu_item :index do |controller|
current_menu_item [:index, :show] do |controller|
controller.menu_item_to_highlight_on_index
end
@ -388,29 +386,6 @@ class CostReportsController < ApplicationController
end
end
def public_queries
if @project
CostQuery.where(['is_public = ? AND (project_id IS NULL OR project_id = ?)', true, @project])
.order(Arel.sql('name ASC'))
else
CostQuery.where(['is_public = ? AND project_id IS NULL', true])
.order(Arel.sql('name ASC'))
end
end
def private_queries
if @project
CostQuery.where(['user_id = ? AND is_public = ? AND (project_id IS NULL OR project_id = ?)',
current_user,
false,
@project])
.order(Arel.sql('name ASC'))
else
CostQuery.where(['user_id = ? AND is_public = ? AND project_id IS NULL', current_user, false])
.order(Arel.sql('name ASC'))
end
end
def display_report_list
report_type = params[:report_type] || :public
render partial: 'report_list', locals: { report_type: report_type }, layout: !request.xhr?

@ -58,6 +58,33 @@ class CostQuery < ApplicationRecord
end
end
def self.public(project)
if project
CostQuery.where(['is_public = ? AND (project_id IS NULL OR project_id = ?)', true, project])
.order(Arel.sql('name ASC'))
else
CostQuery.where(['is_public = ? AND project_id IS NULL', true])
.order(Arel.sql('name ASC'))
end
end
def self.private(project, user)
if project
CostQuery.where(['user_id = ? AND is_public = ? AND (project_id IS NULL OR project_id = ?)',
user,
false,
project])
.order(Arel.sql('name ASC'))
else
CostQuery.where(['user_id = ? AND is_public = ? AND project_id IS NULL', user, false])
.order(Arel.sql('name ASC'))
end
end
def self.exists_in?(project, user)
public(project).or(private(project, user)).exists?
end
def serialize
# have to take the reverse group_bys to retain the original order when deserializing
self.serialized = { filters: (filters.map(&:serialize).reject(&:nil?).sort { |a, b| a.first <=> b.first }),

@ -1,38 +0,0 @@
<%#-- copyright
OpenProject is an open source project management software.
Copyright (C) 2012-2020 the OpenProject GmbH
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.
++#%>
<%# needs locals:
report_type: symbol referring to helper methods of the sort #{report_type}_queries
%>
<% queries = respond_to?(:"#{report_type}_queries") ? send(:"#{report_type}_queries") : [] %>
<% if queries.any? %>
<h3><%= t(:"label_#{report_type}_report_plural") %></h3>
<%= render :partial => "report_list", :locals => { :report_type => report_type, :queries => queries } %>
<% end -%>

@ -27,13 +27,19 @@ See docs/COPYRIGHT.rdoc for more details.
++#%>
<% queries ||= respond_to?(:"#{report_type}_queries") ? send(:"#{report_type}_queries") : [] %>
<ul id='<%= "#{report_type}_sidebar_report_list" %>'
class="report_list list"
data-update-url="<%= url_for(:action => :display_report_list, :report_type => report_type) %>">
<% queries = report_type == :public ? CostQuery.public(@project) : CostQuery.private(@project, current_user) %>
<% if queries.any? %>
<% queries.each do |query| -%>
<li>
<%= link_to(h(query.name), :controller => 'cost_reports', :action => 'show', :id => query.id) %>
</li>
<ul class="pages-hierarchy -with-hierarchy">
<li class="tree-menu--item ui-menu-item collapsible-menu--item" slug="<%= query.name %>">
<%= link_to(h(query.name),
{:controller => '/cost_reports', :action => 'show', :id => query.id},
:class => 'tree-menu--title ellipsis') %>
</li>
</ul>
<% end -%>
</ul>
<% else %>
<ul class="pages-hierarchy -with-hierarchy">
<li class="collapsible-menu--placeholder"><%= t(:"label_no_reports") %></li>
</ul>
<% end -%>

@ -0,0 +1,55 @@
<%#-- copyright
OpenProject is an open source project management software.
Copyright (C) 2012-2020 the OpenProject GmbH
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.
++#%>
<% [:private, :public].each do |report_type| %>
<div class="tree-menu--container" data-selected-page="<%= @query ? @query.name : '' %>">
<ul class="pages-hierarchy -with-hierarchy collapsible-menu--container">
<li class="-hierarchy-expanded">
<span class="tree-menu--item">
<span class="tree-menu--hierarchy-span">
<a tabindex="0" role="button" class="tree-menu--hierarchy-indicator collapsible-menu--category-toggle">
<span aria-hidden="true" class="tree-menu--hierarchy-indicator-icon"></span>
<span class="tree-menu--hierarchy-indicator-expanded hidden-for-sighted">
<%= t("label_expanded_click_to_collapse") %></span>
<span class="tree-menu--hierarchy-indicator-collapsed hidden-for-sighted">
<%= t("label_collapsed_click_to_show") %></span>
</a>
</span>
<a id='<%= "#{report_type}_sidebar_report_category" %>'
class="tree-menu--title ellipsis ui-autocomplete--category collapsible-menu--category-toggle">
<%= t(:"label_#{report_type}_report_plural") %>
</a>
</span>
<%= render :partial => "cost_reports/report_list", :locals => { :report_type => report_type } %>
</li>
</ul>
</div>
<% end %>

@ -58,8 +58,8 @@ See docs/COPYRIGHT.rdoc for more details.
<%= "<br />#{t(:information_restricted_depending_on_permission)}".html_safe unless User.current.admin?%>
</p>
<% content_for :sidebar do %>
<% [:private, :public].each do |type| %>
<%= render :partial => "report_category", :locals => { :report_type => type } %>
<% end %>
<% end -%>
<% if @project.blank? %>
<% content_for :sidebar do %>
<%= render :partial => "report_menu" %>
<% end -%>
<% end %>

@ -81,6 +81,7 @@ en:
label_inactive: "«inactive»"
label_no: "No"
label_none: "(no data)"
label_no_reports: "There are no cost reports yet."
label_report: "Report"
label_yes: "Yes"

@ -78,6 +78,14 @@ module OpenProject::Reporting
caption: :cost_reports_title,
if: Proc.new { |project| project.module_enabled?(:costs) },
icon: 'icon2 icon-cost-reports'
menu :project_menu,
:costs_menu,
{ controller: '/cost_reports', action: 'index' },
param: :project_id,
if: Proc.new { |project| project.module_enabled?(:costs) },
partial: '/cost_reports/report_menu',
parent: :costs
end
initializer "reporting.register_hooks" do

@ -20,8 +20,10 @@ describe 'Cost report saving', type: :feature, js: true do
report_page.save as: 'Testreport'
expect(page).to have_selector('#ur_caption', text: 'Testreport')
expect(page).to have_selector('#private_sidebar_report_list', text: 'Testreport')
# Check if the category is displayed
expect(page).to have_selector('#private_sidebar_report_category', text: I18n.t(:label_private_report_plural).upcase)
# Check if the new report is displayed
expect(page).to have_selector('.tree-menu--title', text: 'Testreport')
report_page.expect_column_element 'Work package'
report_page.expect_row_element 'Project'
@ -35,8 +37,10 @@ describe 'Cost report saving', type: :feature, js: true do
report_page.save as: 'Public report', public: true
expect(page).to have_selector('#ur_caption', text: 'Public report')
expect(page).to have_selector('#public_sidebar_report_list', text: 'Public report')
# Check if the category is displayed
expect(page).to have_selector('#public_sidebar_report_category', text: I18n.t(:label_public_report_plural).upcase)
# Check if the new report is displayed
expect(page).to have_selector('.tree-menu--title', text: 'Public report')
report_page.expect_column_element 'Work package'
report_page.expect_row_element 'Project'

@ -77,7 +77,7 @@ RSpec.feature 'Query menu items', js: true do
click_on 'Save'
notification.expect_success('Successful update')
expect(page).to have_selector('.wp-query-menu--item[data-category=starred]', text: query.name)
expect(page).to have_selector('.collapsible-menu--item[data-category=starred]', text: query.name)
end
after do

@ -160,8 +160,8 @@ RSpec.feature 'Work package navigation', js: true, selenium: true do
visit project_path(project)
find('#main-menu-work-packages ~ .toggler').click
expect(page).to have_selector('.wp-query-menu--search-ul')
find('.wp-query-menu--item-link', text: query.name).click
expect(page).to have_selector('.collapsible-menu--search-ul')
find('.collapsible-menu--item-link', text: query.name).click
expect(page).not_to have_selector('.title-container', text: 'Overview')
expect(page).to have_field('editable-toolbar-title', with: query.name)
@ -202,7 +202,7 @@ RSpec.feature 'Work package navigation', js: true, selenium: true do
wp_display.expect_state 'Gantt'
# Click on All open
find('.wp-query-menu--item-link', text: 'All open').click
find('.collapsible-menu--item-link', text: 'All open').click
if OpenProject::Configuration.bim?
wp_display.expect_state 'Cards'

@ -103,7 +103,7 @@ describe 'Query selection', type: :feature do
it 'updates the page upon query switching', js: true do
wp_page.expect_title query.name, editable: false
find('.wp-query-menu--item-link', text: query2.name).click
find('.collapsible-menu--item-link', text: query2.name).click
end
end
end

@ -16,7 +16,7 @@ describe 'Visiting a hidden query', js: true do
end
it 'does not render the hidden query' do
expect(page).to have_selector('.wp-query-menu--search-ul')
expect(page).to have_selector('.collapsible-menu--search-ul')
expect(page).to have_no_selector('.ui-menu-item', text: 'my hidden query')
query.update(name: 'my visible query', hidden: false)

@ -60,7 +60,7 @@ describe 'Refreshing query menu item', js: true do
expect(url).not_to match(/query_props=.+/)
# Locate query and refresh
query_item = page.find(".wp-query-menu--item", text: last_query.name)
query_item = page.find(".collapsible-menu--item", text: last_query.name)
query_item.click
wp_table.expect_work_package_listed work_package, other_work_package

@ -43,8 +43,8 @@ describe 'Query menu item', js: true do
let(:wp_table) { ::Pages::WorkPackagesTable.new }
it 'should show the query menu (Regression #30082)' do
wp_table.visit!
expect(page).to have_selector('.wp-query-menu--container')
expect(page).to have_selector('.wp-query-menu--item', wait: 20, minimum: 1)
expect(page).to have_selector('.collapsible-menu--container')
expect(page).to have_selector('.collapsible-menu--item', wait: 20, minimum: 1)
end
end

@ -46,7 +46,7 @@ module Components
end
def autocompleter_results_selector
'.wp-query-menu--results-container'
'.collapsible-menu--results-container'
end
def autocompleter_selector

Loading…
Cancel
Save