Merge pull request #10206 from opf/feature/41138/index-action-team-planner

[41138] Add index action to team planner
pull/10231/head
Oliver Günther 3 years ago committed by GitHub
commit 9e0c47c171
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 12
      frontend/src/app/core/routing/openproject.routes.ts
  2. 2
      frontend/src/app/features/boards/index-page/boards-index-page.component.html
  3. 1
      frontend/src/app/features/boards/index-page/boards-index-page.component.ts
  4. 6
      frontend/src/app/features/calendar/op-calendar.service.ts
  5. 4
      frontend/src/app/features/team-planner/team-planner/team-planner.routes.ts
  6. 2
      frontend/src/app/shared/components/op-view-select/op-static-queries.service.ts
  7. 2
      frontend/src/app/shared/components/op-view-select/op-view-select.component.ts
  8. 2
      modules/boards/spec/features/support/board_index_page.rb
  9. 76
      modules/team_planner/app/cells/team_planner/row_cell.rb
  10. 48
      modules/team_planner/app/cells/team_planner/table_cell.rb
  11. 42
      modules/team_planner/app/controllers/team_planner/team_planner_controller.rb
  12. 17
      modules/team_planner/app/views/team_planner/team_planner/index.html.erb
  13. 1
      modules/team_planner/app/views/team_planner/team_planner/show.html.erb
  14. 2
      modules/team_planner/config/locales/en.yml
  15. 11
      modules/team_planner/config/routes.rb
  16. 11
      modules/team_planner/lib/open_project/team_planner/engine.rb
  17. 108
      modules/team_planner/spec/features/team_planner_index_spec.rb
  18. 4
      modules/team_planner/spec/features/team_planner_menu_spec.rb
  19. 139
      modules/team_planner/spec/features/team_planner_navigation_spec.rb
  20. 5
      modules/team_planner/spec/features/team_planner_spec.rb
  21. 6
      modules/team_planner/spec/features/team_planner_split_view_spec.rb
  22. 56
      modules/team_planner/spec/features/team_planner_upsale_spec.rb
  23. 29
      modules/team_planner/spec/routing/team_planner_routing_spec.rb
  24. 2
      modules/team_planner/spec/support/pages/team_planner.rb

@ -208,6 +208,18 @@ export function uiRouterConfiguration(uiRouter:UIRouter, injector:Injector, modu
equals: (a:any, b:any) => _.isEqual(a, b), equals: (a:any, b:any) => _.isEqual(a, b),
}, },
); );
uiRouter.urlService.config.type(
'opQueryId',
{
encode: (id:string|null) => id || 'new',
decode: (id:string) => (id === 'new' ? null : id),
raw: true,
dynamic: true,
is: (val:unknown) => typeof (val) === 'string',
equals: (a:unknown, b:unknown) => _.isEqual(a, b),
},
);
} }
export function initializeUiRouterListeners(injector:Injector) { export function initializeUiRouterListeners(injector:Injector) {

@ -12,7 +12,7 @@
<op-icon icon-classes="button--icon icon-add"> <op-icon icon-classes="button--icon icon-add">
</op-icon> </op-icon>
<span class="button--text" <span class="button--text"
[textContent]="text.board"> [textContent]="text.create">
</span> </span>
</a> </a>
</li> </li>

@ -26,6 +26,7 @@ import { map } from 'rxjs/operators';
export class BoardsIndexPageComponent extends UntilDestroyedMixin implements OnInit, AfterViewInit { export class BoardsIndexPageComponent extends UntilDestroyedMixin implements OnInit, AfterViewInit {
public text = { public text = {
name: this.I18n.t('js.modals.label_name'), name: this.I18n.t('js.modals.label_name'),
create: this.I18n.t('js.button_create'),
board: this.I18n.t('js.label_board'), board: this.I18n.t('js.label_board'),
boards: this.I18n.t('js.label_board_plural'), boards: this.I18n.t('js.label_board_plural'),
type: this.I18n.t('js.boards.label_board_type'), type: this.I18n.t('js.boards.label_board_type'),

@ -314,14 +314,16 @@ export class OpCalendarService extends UntilDestroyedMixin {
} }
private get initializingWithQuery():boolean { private get initializingWithQuery():boolean {
return (this.areFiltersEmpty && this.urlParams.query_id && !this.urlParams.query_props) as boolean; return this.areFiltersEmpty
&& !!this.urlParams.query_id
&& !this.urlParams.query_props;
} }
private get urlParams() { private get urlParams() {
return this.uiRouterGlobals.params; return this.uiRouterGlobals.params;
} }
private get areFiltersEmpty() { private get areFiltersEmpty():boolean {
return this.wpTableFilters.isEmpty; return this.wpTableFilters.isEmpty;
} }

@ -37,13 +37,13 @@ export const TEAM_PLANNER_ROUTES:Ng2StateDeclaration[] = [
{ {
name: 'team_planner', name: 'team_planner',
parent: 'optional_project', parent: 'optional_project',
url: '/team_planner?query_id&query_props&cdate&cview', url: '/team_planners/:query_id?query_props&cdate&cview',
redirectTo: 'team_planner.page', redirectTo: 'team_planner.page',
views: { views: {
'!$default': { component: WorkPackagesBaseComponent }, '!$default': { component: WorkPackagesBaseComponent },
}, },
params: { params: {
query_id: { type: 'query', dynamic: true }, query_id: { type: 'opQueryId', dynamic: true },
cdate: { type: 'string', dynamic: true }, cdate: { type: 'string', dynamic: true },
cview: { type: 'string', dynamic: true }, cview: { type: 'string', dynamic: true },
// Use custom encoder/decoder that ensures validity of URL string // Use custom encoder/decoder that ensures validity of URL string

@ -194,7 +194,7 @@ export class StaticQueriesService {
title: this.text.create_new_team_planner, title: this.text.create_new_team_planner,
uiSref: 'team_planner.page.show', uiSref: 'team_planner.page.show',
uiParams: { uiParams: {
query_id: '', query_id: null,
query_props: '', query_props: '',
}, },
view: 'TeamPlanner', view: 'TeamPlanner',

@ -55,7 +55,7 @@ import { ApiV3ListParameters } from 'core-app/core/apiv3/paths/apiv3-list-resour
import { CurrentUserService } from 'core-app/core/current-user/current-user.service'; import { CurrentUserService } from 'core-app/core/current-user/current-user.service';
import { CurrentProjectService } from 'core-app/core/current-project/current-project.service'; import { CurrentProjectService } from 'core-app/core/current-project/current-project.service';
export type ViewType = 'WorkPackagesTable'|'Bim'|'TeamPlanner'; export type ViewType = 'WorkPackagesTable'|'Bim'|'TeamPlanner'|'WorkPackagesCalendar';
export const opViewSelectSelector = 'op-view-select'; export const opViewSelectSelector = 'op-view-select';

@ -57,7 +57,7 @@ module Pages
end end
def create_board(action: nil, expect_empty: false) def create_board(action: nil, expect_empty: false)
page.find('.toolbar-item a', text: 'Board').click page.find('.toolbar-item a', text: I18n.t('js.button_create')).click
if action == nil if action == nil
find('.tile-block-title', text: 'Basic').click find('.tile-block-title', text: 'Basic').click

@ -0,0 +1,76 @@
#-- encoding: UTF-8
#-- 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 COPYRIGHT and LICENSE files for more details.
#++
module TeamPlanner
class RowCell < ::RowCell
include ApplicationHelper
include ::Redmine::I18n
def query
model
end
delegate :project, to: :query
def name
link_to query.name, project_team_planner_path(project, query.id)
end
def created_at
format_time(query.created_at)
end
def assignees
query
.filters
.detect { |filter| filter.name == :assigned_to_id }
.then { |filter| filter ? filter.values.count : 0 }
end
def button_links
[delete_link].compact
end
def delete_link
if table.current_user.allowed_to?(:manage_team_planner, project)
link_to(
op_icon('icon icon-delete'),
project_team_planner_path(project, query.id),
method: :delete,
data: {
confirm: I18n.t(:text_are_you_sure),
'qa-selector': "team-planner-remove-#{query.id}"
},
title: t(:button_delete)
)
end
end
end
end

@ -0,0 +1,48 @@
#-- encoding: UTF-8
#-- 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 COPYRIGHT and LICENSE files for more details.
#++
module TeamPlanner
class TableCell < ::TableCell
options :current_user
columns :name, :assignees, :created_at
def sortable?
false
end
def headers
[
['name', { caption: I18n.t(:label_name) }],
['assignees', { caption: I18n.t('team_planner.label_assignees') }],
['created_at', { caption: I18n.t('attributes.created_at') }]
]
end
end
end

@ -2,21 +2,35 @@ module ::TeamPlanner
class TeamPlannerController < BaseController class TeamPlannerController < BaseController
include EnterpriseTrialHelper include EnterpriseTrialHelper
before_action :find_optional_project before_action :find_optional_project
before_action :authorize, only: %i[index] before_action :authorize
before_action :require_ee_token, only: %i[index] before_action :require_ee_token, except: %i[upsale]
before_action :redirect_to_first_plan, only: :index before_action :find_plan_view, only: %i[destroy]
menu_item :team_planner_view menu_item :team_planner_view
def index def index
@views = visible_plans
end
def show
render layout: 'angular/angular' render layout: 'angular/angular'
end end
def upsale; end def upsale; end
def destroy
if @view.destroy
flash[:notice] = t(:notice_successful_delete)
else
flash[:error] = t(:error_can_not_delete_entry)
end
redirect_to action: :index
end
def require_ee_token def require_ee_token
unless EnterpriseToken.allows_to?(:team_planner_view) unless EnterpriseToken.allows_to?(:team_planner_view)
redirect_to project_team_planner_upsale_path redirect_to action: :upsale
end end
end end
@ -26,27 +40,21 @@ module ::TeamPlanner
private private
def redirect_to_first_plan def find_plan_view
return unless @project @view = Query
return if team_planner_query_params? .visible(current_user)
.find(params[:id])
if (query_id = find_existing_plan) rescue ActiveRecord::RecordNotFound
redirect_to action: :index, query_id: query_id render_404
end
end end
def find_existing_plan def visible_plans
Query Query
.visible(current_user) .visible(current_user)
.joins(:views) .joins(:views)
.where('views.type' => 'team_planner') .where('views.type' => 'team_planner')
.where('queries.project_id' => @project.id) .where('queries.project_id' => @project.id)
.order('queries.name ASC') .order('queries.name ASC')
.pick('queries.id')
end
def team_planner_query_params?
params[:query_id] || params[:query_props]
end end
end end
end end

@ -1 +1,16 @@
<% html_title(t('team_planner.label_team_planner')) -%> <% html_title(t('team_planner.label_team_planner_plural')) -%>
<%= toolbar title: t(:'team_planner.label_team_planner_plural') do %>
<% if current_user.allowed_to?(:manage_team_planner, @project) %>
<li class="toolbar-item">
<%= link_to new_project_team_planners_path(@project),
class: 'button -alt-highlight',
title: t(:button_create) do %>
<%= op_icon('button--icon icon-add') %>
<span class="button--text"><%= t(:button_create) %></span>
<% end %>
</li>
<% end %>
<% end %>
<%= rails_cell ::TeamPlanner::TableCell, @views, current_user: current_user %>

@ -0,0 +1 @@
<% html_title(t('team_planner.label_team_planner')) -%>

@ -6,6 +6,8 @@ en:
team_planner: team_planner:
label_team_planner: "Team planner" label_team_planner: "Team planner"
label_team_planner_plural: "Team planners"
label_assignees: "Assignees"
upsale: upsale:
title: "Team planner" title: "Team planner"
description: "Team planner gives you a complete overview what each of team member is working on, one week at a time. Move, stretch and shrink work packages visually, and even drag them from one assignee to another to organise workload. You can even create new work packages or add existing ones, all from within team planner!" description: "Team planner gives you a complete overview what each of team member is working on, one week at a time. Move, stretch and shrink work packages visually, and even drag them from one assignee to another to organise workload. You can even create new work packages or add existing ones, all from within team planner!"

@ -1,6 +1,13 @@
OpenProject::Application.routes.draw do OpenProject::Application.routes.draw do
scope 'projects/:project_id', as: 'project' do scope 'projects/:project_id', as: 'project' do
get '/team_planner/upsale', to: 'team_planner/team_planner#upsale', as: :team_planner_upsale resources :team_planners,
get '/team_planner(/*state)', to: 'team_planner/team_planner#index', as: :team_planner controller: 'team_planner/team_planner',
only: %i[index destroy],
as: :team_planners do
get :upsale, to: 'team_planner/team_planner#upsale', on: :collection, as: :upsale
get '/new' => 'team_planner/team_planner#show', on: :collection, as: 'new'
get '(/*state)' => 'team_planner/team_planner#show', on: :member, as: ''
end
end end
end end

@ -29,11 +29,11 @@ module OpenProject::TeamPlanner
name: 'OpenProject Team Planner' do name: 'OpenProject Team Planner' do
project_module :team_planner_view, dependencies: :work_package_tracking do project_module :team_planner_view, dependencies: :work_package_tracking do
permission :view_team_planner, permission :view_team_planner,
{ 'team_planner/team_planner': %i[index upsale] }, { 'team_planner/team_planner': %i[index show upsale] },
dependencies: %i[view_work_packages], dependencies: %i[view_work_packages],
contract_actions: { team_planner: %i[read] } contract_actions: { team_planner: %i[read] }
permission :manage_team_planner, permission :manage_team_planner,
{ 'team_planner/team_planner': %i[index upsale] }, { 'team_planner/team_planner': %i[index show new destroy upsale] },
dependencies: %i[view_team_planner add_work_packages edit_work_packages save_queries manage_public_queries], dependencies: %i[view_team_planner add_work_packages edit_work_packages save_queries manage_public_queries],
contract_actions: { team_planner: %i[create update destroy] } contract_actions: { team_planner: %i[create update destroy] }
end end
@ -41,10 +41,9 @@ module OpenProject::TeamPlanner
menu :project_menu, menu :project_menu,
:team_planner_view, :team_planner_view,
{ controller: '/team_planner/team_planner', action: :index }, { controller: '/team_planner/team_planner', action: :index },
caption: :'team_planner.label_team_planner', caption: :'team_planner.label_team_planner_plural',
after: :work_packages, after: :work_packages,
icon: 'icon2 icon-calendar', icon: 'icon2 icon-calendar'
badge: 'label_menu_badge.pre_alpha'
menu :project_menu, menu :project_menu,
:team_planner_menu, :team_planner_menu,
@ -52,7 +51,7 @@ module OpenProject::TeamPlanner
parent: :team_planner_view, parent: :team_planner_view,
partial: 'team_planner/team_planner/menu', partial: 'team_planner/team_planner/menu',
last: true, last: true,
caption: :'team_planner.label_team_planner' caption: :'team_planner.label_team_planner_plural'
end end
add_view :TeamPlanner, add_view :TeamPlanner,

@ -0,0 +1,108 @@
#-- encoding: UTF-8
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2021 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-2013 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 COPYRIGHT and LICENSE files for more details.
#++
require 'spec_helper'
require_relative './shared_context'
describe 'Team planner index', type: :feature, js: true, with_ee: %i[team_planner_view] do
include_context 'with team planner full access'
let(:current_user) { user }
let(:query) { create :query, user: user, project: project, public: true }
let(:team_plan) { create :view_team_planner, query: query }
before do
login_as current_user
team_plan
visit project_team_planners_path(project)
end
context 'with no view' do
let(:team_plan) { nil }
it 'shows an index action' do
expect(page).to have_text 'There is currently nothing to display.'
expect(page).to have_selector '.button', text: 'Create'
end
it 'can create an action through the sidebar' do
click_on 'Create new planner'
team_planner.expect_title
# Also works from the frontend
click_on 'Create new planner'
team_planner.expect_no_toaster
team_planner.expect_title
end
end
context 'with an existing view' do
it 'shows that view' do
expect(page).to have_selector 'td', text: query.name
expect(page).to have_selector "[data-qa-selector='team-planner-remove-#{query.id}']"
end
context 'with another user with limited access' do
let(:current_user) do
create :user,
firstname: 'Bernd',
member_in_project: project,
member_with_permissions: %w[view_work_packages view_team_planner]
end
it 'does not show the create button' do
expect(page).to have_selector 'td', text: query.name
# Does not show the delete
expect(page).to have_no_selector "[data-qa-selector='team-planner-remove-#{query.id}']"
# Does not show the create button
expect(page).to have_no_selector '.button', text: 'Create'
end
context 'when the view is non-public' do
let(:query) { create :query, user: user, project: project, public: false }
it 'does not show a non-public view' do
expect(page).to have_text 'There is currently nothing to display.'
expect(page).to have_no_selector 'td', text: query.name
# Does not show the delete
expect(page).to have_no_selector "[data-qa-selector='team-planner-remove-#{query.id}']"
# Does not show the create button
expect(page).to have_no_selector '.button', text: 'Create'
end
end
end
end
end

@ -53,7 +53,7 @@ describe 'Team planner sidemenu', type: :feature, js: true do
visit project_path(project) visit project_path(project)
within '#main-menu' do within '#main-menu' do
click_link 'Team planner' click_link 'Team planners'
end end
query_menu.expect_menu_entry_not_visible('Create new planner') query_menu.expect_menu_entry_not_visible('Create new planner')
@ -76,7 +76,7 @@ describe 'Team planner sidemenu', type: :feature, js: true do
visit project_path(project) visit project_path(project)
within '#main-menu' do within '#main-menu' do
click_link 'Team planner' click_link 'Team planners'
end end
query_menu.expect_menu_entry('Create new planner') query_menu.expect_menu_entry('Create new planner')

@ -1,139 +0,0 @@
#-- encoding: UTF-8
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2021 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-2013 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 COPYRIGHT and LICENSE files for more details.
#++
require 'spec_helper'
require_relative './shared_context'
describe 'Team planner', type: :feature, js: true, with_ee: %i[team_planner_view] do
include_context 'with team planner full access'
# We need a default status
shared_let(:default_status) { create :default_status }
it 'redirects to the first active plan' do
visit project_path(project)
within '#main-menu' do
click_link 'Team planner'
end
team_planner.expect_title
team_planner.save_as 'Foobar'
visit project_path(project)
within '#main-menu' do
click_link 'Team planner'
end
query = View.where(type: 'team_planner').last.query
expect(query.name).to eq 'Foobar'
expect(page).to have_current_path /query_id=#{query.id}/
end
shared_examples 'loads a new team planner' do
it do
visit project_path(project)
within '#main-menu' do
click_link 'Team planner'
end
team_planner.expect_title
expect(page).to have_no_current_path /query_id=#{query.id}/
end
end
shared_examples 'loads the query view' do
it do
visit project_path(project)
within '#main-menu' do
click_link 'Team planner'
end
team_planner.expect_title query.name
expect(page).to have_current_path /query_id=#{query.id}/
end
end
context 'with an existing saved plan' do
shared_let(:other_user) { create :user }
let!(:view) { create :view_team_planner, query: query }
context 'when the query is from another user and private' do
let!(:query) { create :query, user: other_user, project: project, public: false }
it_behaves_like 'loads a new team planner'
end
context 'when the query is from another user and public' do
let!(:query) { create :query, user: other_user, project: project, public: true }
it_behaves_like 'loads the query view'
end
context 'when the query is from the same user and private' do
let!(:query) { create :query, user: user, project: project, public: false }
it_behaves_like 'loads the query view'
end
end
context 'with an existing plan and creating a new one' do
let!(:view) { create :view_team_planner, query: query }
let!(:query) { create :query, user: user, project: project, public: true }
it 'allows to reload with query props active' do
team_planner.visit!
team_planner.expect_assignee(user, present: false)
click_on 'Create new planner'
team_planner.expect_assignee(user, present: false)
retry_block do
team_planner.click_add_user
page.find('[data-qa-selector="tp-add-assignee"] input')
team_planner.select_user_to_add user.name
end
team_planner.expect_assignee(user)
page.driver.refresh
expect(page).to have_current_path /query_props=/
expect(page).to have_current_path /cview=/
team_planner.expect_assignee(user)
end
end
end

@ -42,9 +42,12 @@ describe 'Team planner', type: :feature, js: true do
visit project_path(project) visit project_path(project)
within '#main-menu' do within '#main-menu' do
click_link 'Team planner' click_link 'Team planners'
end end
expect(page).to have_content 'There is currently nothing to display.'
click_on 'Create'
team_planner.expect_title team_planner.expect_title
filters.expect_filter_count("1") filters.expect_filter_count("1")

@ -68,14 +68,14 @@ describe 'Team planner split view navigation', type: :feature, js: true, with_ee
# Expect clicking on a work package does not open the details # Expect clicking on a work package does not open the details
page.find('[data-qa-selector="op-wp-single-card--content-subject"]', text: work_package1.subject).click page.find('[data-qa-selector="op-wp-single-card--content-subject"]', text: work_package1.subject).click
expect(page).to have_no_current_path /team_planner\/details\/#{work_package1.id}/ expect(page).to have_no_current_path /team_planners\/new\/details\/#{work_package1.id}/
# Open split view through info icon # Open split view through info icon
team_planner.open_split_view_by_info_icon work_package1 team_planner.open_split_view_by_info_icon work_package1
expect(page).to have_current_path /team_planner\/details\/#{work_package1.id}/ expect(page).to have_current_path /team_planners\/new\/details\/#{work_package1.id}/
# now clicking on another card switches # now clicking on another card switches
page.find('[data-qa-selector="op-wp-single-card--content-subject"]', text: work_package2.subject).click page.find('[data-qa-selector="op-wp-single-card--content-subject"]', text: work_package2.subject).click
expect(page).to have_current_path /team_planner\/details\/#{work_package2.id}/ expect(page).to have_current_path /team_planners\/new\/details\/#{work_package2.id}/
end end
end end

@ -0,0 +1,56 @@
#-- encoding: UTF-8
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2021 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-2013 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 COPYRIGHT and LICENSE files for more details.
#++
require 'spec_helper'
require_relative './shared_context'
describe 'Team planner index', type: :feature, js: true do
include_context 'with team planner full access'
let(:current_user) { user }
before do
login_as current_user
end
it 'redirects routes to upsale' do
visit project_team_planners_path(project)
expect(page).to have_text 'Upgrade now'
click_on 'Create new planner'
expect(page).to have_text 'Upgrade now'
visit project_team_planner_path(project, id: 'new')
expect(page).to have_text 'Upgrade now'
end
end

@ -31,7 +31,32 @@ require 'spec_helper'
describe 'Team planner routing', type: :routing do describe 'Team planner routing', type: :routing do
it 'routes to team_planner#index' do it 'routes to team_planner#index' do
expect(subject) expect(subject)
.to route(:get, '/projects/foobar/team_planner/state') .to route(:get, '/projects/foobar/team_planners')
.to(controller: 'team_planner/team_planner', action: 'index', project_id: 'foobar', state: 'state') .to(controller: 'team_planner/team_planner', action: :index, project_id: 'foobar')
end
it 'routes to team_planner#show' do
expect(subject)
.to route(:get, '/projects/foobar/team_planners/1234')
.to(controller: 'team_planner/team_planner', action: :show, project_id: 'foobar', id: '1234')
end
it 'routes to team_planner#new' do
expect(subject)
.to route(:get, '/projects/foobar/team_planners/new')
.to(controller: 'team_planner/team_planner', action: :show, project_id: 'foobar')
end
it 'routes to team_planner#show with state' do
expect(subject)
.to route(:get, '/projects/foobar/team_planners/1234/details/555')
.to(controller: 'team_planner/team_planner', action: :show, project_id: 'foobar', id: '1234',
state: 'details/555')
end
it 'routes to team_planner#destroy' do
expect(subject)
.to route(:delete, '/projects/foobar/team_planners/1234')
.to(controller: 'team_planner/team_planner', action: :destroy, project_id: 'foobar', id: '1234')
end end
end end

@ -42,7 +42,7 @@ module Pages
end end
def path def path
project_team_planner_path(project) new_project_team_planners_path(project)
end end
def expect_title(title = 'Unnamed team planner') def expect_title(title = 'Unnamed team planner')

Loading…
Cancel
Save