BUG/34971 Order of work packages in XLS, PDF, CSV export differs from order in OpenProject (#10719)

* Save the new queries when manually sorting the work packages

* fixup! Save the new queries when manually sorting the work packages

* fixup! Save the new queries when manually sorting the work packages
This commit is contained in:
Dombi Attila
2022-06-01 12:00:22 +03:00
committed by GitHub
parent 235e3f3b42
commit 69e83fc0d4
10 changed files with 202 additions and 161 deletions
@@ -64,6 +64,10 @@ export class QueryResource extends HalResource {
public sortBy:QuerySortByResource[];
public setSortBy(newSortBy:QuerySortByResource[]):void {
this.sortBy = newSortBy;
}
public filters:QueryFilterInstanceResource[];
public starred:boolean;
@@ -102,7 +102,7 @@ export class DragAndDropTransformer {
// Save the query when switching to manual
const query = this.querySpace.query.value;
if (query && this.wpTableSortBy.switchToManualSorting(query)) {
await this.wpListService.save(query);
await this.wpListService.createOrSave(query);
}
} catch (e) {
this.halNotification.handleRawError(e);
@@ -120,7 +120,7 @@ export class WorkPackagesGridComponent implements WorkPackageViewOutputs {
public switchToManualSorting() {
const query = this.querySpace.query.value;
if (query && this.wpTableSortBy.switchToManualSorting(query)) {
this.wpList.save(query);
void this.wpList.createOrSave(query);
}
}
}
@@ -32,6 +32,7 @@ import { AuthorisationService } from 'core-app/core/model-auth/model-auth.servic
import { StateService } from '@uirouter/core';
import { IsolatedQuerySpace } from 'core-app/features/work-packages/directives/query-space/isolated-query-space';
import { Injectable } from '@angular/core';
import isPersistedResource from 'core-app/features/hal/helpers/is-persisted-resource';
import { UrlParamsHelperService } from 'core-app/features/work-packages/components/wp-query/url-params-helper';
import { ToastService } from 'core-app/shared/components/toaster/toast.service';
import { I18nService } from 'core-app/core/i18n/i18n.service';
@@ -333,6 +334,13 @@ export class WorkPackagesListService {
return promise;
}
public async createOrSave(query:QueryResource):Promise<unknown> {
if (!isPersistedResource(query)) {
return this.create(query, 'New manually sorted query');
}
return this.save(query);
}
public toggleStarred(query:QueryResource):Promise<any> {
const promise = this
.apiV3Service
@@ -34,7 +34,6 @@ import { QueryResource } from 'core-app/features/hal/resources/query-resource';
import { IsolatedQuerySpace } from 'core-app/features/work-packages/directives/query-space/isolated-query-space';
import { States } from 'core-app/core/states/states.service';
import { QuerySortByResource } from 'core-app/features/hal/resources/query-sort-by-resource';
import isPersistedResource from 'core-app/features/hal/helpers/is-persisted-resource';
import { PathHelperService } from 'core-app/core/path-helper/path-helper.service';
import { QueryColumn } from 'core-app/features/work-packages/components/wp-query/query-column';
import { WorkPackageQueryStateService } from './wp-view-base.service';
@@ -123,13 +122,8 @@ export class WorkPackageViewSortByService extends WorkPackageQueryStateService<Q
public switchToManualSorting(query:QueryResource):boolean {
const { manualSortObject } = this;
if (manualSortObject && !this.isManualSortingMode) {
if (query && isPersistedResource(query)) {
// Save the query if it is persisted
query.sortBy = [manualSortObject];
return true;
}
// Query cannot be saved, just update the props for now
this.update([manualSortObject]);
query.setSortBy([manualSortObject]);
return true;
}
return false;
@@ -36,44 +36,45 @@ describe 'Manual sorting of WP table', type: :feature, js: true do
let(:type_task) { create :type_task }
let(:type_bug) { create :type_bug }
let(:project) { create(:project, types: [type_task, type_bug]) }
let(:work_package_1) do
create(:work_package, subject: 'WP1', project: project, type: type_task, created_at: Time.now)
let(:work_package1) do
create(:work_package, subject: 'WP1', project:, type: type_task, created_at: Time.zone.now)
end
let(:work_package_2) do
let(:work_package2) do
create(:work_package,
subject: 'WP2',
project: project,
parent: work_package_1,
project:,
parent: work_package1,
type: type_task,
created_at: Time.now - 1.minutes)
created_at: 1.minute.ago)
end
let(:work_package_3) do
let(:work_package3) do
create(:work_package,
subject: 'WP3',
project: project,
parent: work_package_2,
project:,
parent: work_package2,
type: type_bug,
created_at: Time.now - 2.minutes)
created_at: 2.minutes.ago)
end
let(:work_package_4) do
let(:work_package4) do
create(:work_package,
subject: 'WP4',
project: project,
parent: work_package_3,
project:,
parent: work_package3,
type: type_bug,
created_at: Time.now - 3.minutes)
created_at: 3.minutes.ago)
end
let(:sort_by) { ::Components::WorkPackages::SortBy.new }
let(:hierarchies) { ::Components::WorkPackages::Hierarchies.new }
let(:dialog) { ::Components::ConfirmationDialog.new }
let(:pagination) { ::Components::TablePagination.new }
let(:display_representation) { ::Components::WorkPackages::DisplayRepresentation.new }
def expect_query_order(query, expected)
retry_block do
query.reload
# work_package_4 was not positioned
# work_package4 was not positioned
found = query.ordered_work_packages.pluck(:work_package_id)
raise "Backend order is incorrect: #{found} != #{expected}" unless found == expected
@@ -83,10 +84,10 @@ describe 'Manual sorting of WP table', type: :feature, js: true do
before do
login_as(user)
work_package_1
work_package_2
work_package_3
work_package_4
work_package1
work_package2
work_package3
work_package4
end
describe 'hierarchy mode' do
@@ -94,30 +95,27 @@ describe 'Manual sorting of WP table', type: :feature, js: true do
wp_table.visit!
# Hierarchy enabled
wp_table.expect_work_package_order(work_package_1, work_package_2, work_package_3, work_package_4)
hierarchies.expect_hierarchy_at(work_package_1, work_package_2, work_package_3)
hierarchies.expect_leaf_at(work_package_4)
wp_table.expect_work_package_order(work_package1, work_package2, work_package3, work_package4)
hierarchies.expect_hierarchy_at(work_package1, work_package2, work_package3)
hierarchies.expect_leaf_at(work_package4)
end
it 'maintains the order until saved' do
it 'maintains the order and automatically saves the query' do
wp_table.drag_and_drop_work_package from: 3, to: 1
loading_indicator_saveguard
hierarchies.expect_hierarchy_at(work_package_1, work_package_2)
hierarchies.expect_leaf_at(work_package_4, work_package_3)
expect(page).to have_selector('.editable-toolbar-title--save')
wp_table.save_as "My sorted query"
hierarchies.expect_hierarchy_at(work_package1, work_package2)
hierarchies.expect_leaf_at(work_package4, work_package3)
wp_table.expect_and_dismiss_toaster message: 'Successful creation.'
query = nil
retry_block do
query = Query.last
raise "Query was not yet saved." unless query.name == 'My sorted query'
raise "Query was not yet saved." unless query.name == 'New manually sorted query'
end
# Expect sorted 1 and 2, the rest is not positioned
expect_query_order(query, [work_package_1, work_package_4].map(&:id))
expect_query_order(query, [work_package1, work_package4].map(&:id))
# Pagination information is shown but no per page options
pagination.expect_range(1, 4, 4)
@@ -128,72 +126,72 @@ describe 'Manual sorting of WP table', type: :feature, js: true do
# Move up the hierarchy
wp_table.drag_and_drop_work_package from: 3, to: 1
loading_indicator_saveguard
hierarchies.expect_hierarchy_at(work_package_1, work_package_2)
hierarchies.expect_leaf_at(work_package_3, work_package_4)
hierarchies.expect_hierarchy_at(work_package1, work_package2)
hierarchies.expect_leaf_at(work_package3, work_package4)
# Keep after table refresh
page.driver.browser.navigate.refresh
hierarchies.expect_hierarchy_at(work_package_1, work_package_2)
hierarchies.expect_leaf_at(work_package_3, work_package_4)
hierarchies.expect_hierarchy_at(work_package1, work_package2)
hierarchies.expect_leaf_at(work_package3, work_package4)
end
it 'can drag an element completely out of the hierarchy' do
# Move up the hierarchy
wp_table.drag_and_drop_work_package from: 3, to: 0
loading_indicator_saveguard
hierarchies.expect_hierarchy_at(work_package_1, work_package_2)
hierarchies.expect_leaf_at(work_package_4)
hierarchies.expect_hierarchy_at(work_package1, work_package2)
hierarchies.expect_leaf_at(work_package4)
# Expect WP has no parent
wp_page = Pages::SplitWorkPackage.new(work_package_4)
wp_page = Pages::SplitWorkPackage.new(work_package4)
wp_page.visit!
wp_page.expect_no_parent
# Keep after table refresh
page.driver.browser.navigate.refresh
hierarchies.expect_hierarchy_at(work_package_1, work_package_2)
hierarchies.expect_leaf_at(work_package_3, work_package_4)
hierarchies.expect_hierarchy_at(work_package1, work_package2)
hierarchies.expect_leaf_at(work_package3, work_package4)
wp_page.expect_no_parent
end
context 'drag an element partly out of the hierarchy' do
let(:work_package_5) do
create(:work_package, subject: 'WP5', project: project, parent: work_package_1)
context 'when dragging an element partly out of the hierarchy' do
let(:work_package5) do
create(:work_package, subject: 'WP5', project:, parent: work_package1)
end
let(:work_package_6) do
create(:work_package, subject: 'WP6', project: project, parent: work_package_1)
let(:work_package6) do
create(:work_package, subject: 'WP6', project:, parent: work_package1)
end
before do
work_package_5
work_package_6
work_package_4.parent = work_package_2
work_package_4.save!
work_package5
work_package6
work_package4.parent = work_package2
work_package4.save!
wp_table.visit!
# Hierarchy enabled
wp_table.expect_work_package_order(work_package_1,
work_package_2,
work_package_3,
work_package_4,
work_package_5,
work_package_6)
hierarchies.expect_hierarchy_at(work_package_1, work_package_2)
hierarchies.expect_leaf_at(work_package_3, work_package_4, work_package_5, work_package_6)
wp_table.expect_work_package_order(work_package1,
work_package2,
work_package3,
work_package4,
work_package5,
work_package6)
hierarchies.expect_hierarchy_at(work_package1, work_package2)
hierarchies.expect_leaf_at(work_package3, work_package4, work_package5, work_package6)
end
it 'move below a sibling of my parent' do
wp_table.drag_and_drop_work_package from: 3, to: 5
loading_indicator_saveguard
wp_table.expect_work_package_order(work_package_1,
work_package_2,
work_package_3,
work_package_5,
work_package_4,
work_package_6)
hierarchies.expect_hierarchy_at(work_package_1, work_package_2)
hierarchies.expect_leaf_at(work_package_3, work_package_4, work_package_5, work_package_6)
wp_table.expect_work_package_order(work_package1,
work_package2,
work_package3,
work_package5,
work_package4,
work_package6)
hierarchies.expect_hierarchy_at(work_package1, work_package2)
hierarchies.expect_leaf_at(work_package3, work_package4, work_package5, work_package6)
end
end
end
@@ -208,12 +206,12 @@ describe 'Manual sorting of WP table', type: :feature, js: true do
wp_table.save_as 'Type query'
wp_table.expect_and_dismiss_toaster message: 'Successful creation.'
expect(page).to have_selector('.group--value', text: 'Task (2)')
expect(page).to have_selector('.group--value', text: 'Bug (2)')
end
it 'updates the work packages appropriately' do
expect(page).to have_selector('.group--value', text: 'Task (2)')
expect(page).to have_selector('.group--value', text: 'Bug (2)')
wp_table.drag_and_drop_work_package from: 0, to: 3
expect(page).to have_selector('.group--value', text: 'Task (1)')
@@ -221,6 +219,9 @@ describe 'Manual sorting of WP table', type: :feature, js: true do
end
it 'dragging item with parent does not result in an error (Regression #30832)' do
expect(page).to have_selector('.group--value', text: 'Task (2)')
expect(page).to have_selector('.group--value', text: 'Bug (2)')
wp_table.drag_and_drop_work_package from: 1, to: 3
expect(page).to have_selector('.group--value', text: 'Task (1)')
@@ -233,7 +234,7 @@ describe 'Manual sorting of WP table', type: :feature, js: true do
describe 'with a saved query and positions increasing from zero' do
let(:query) do
create(:query, user: user, project: project, show_hierarchies: false).tap do |q|
create(:query, user:, project:, show_hierarchies: false).tap do |q|
q.sort_criteria = [[:manual_sorting, 'asc']]
q.save!
end
@@ -242,15 +243,15 @@ describe 'Manual sorting of WP table', type: :feature, js: true do
let!(:priority) { create :default_priority }
before do
::OrderedWorkPackage.create(query: query, work_package: work_package_1, position: 0)
::OrderedWorkPackage.create(query: query, work_package: work_package_2, position: 1)
::OrderedWorkPackage.create(query: query, work_package: work_package_3, position: 2)
::OrderedWorkPackage.create(query: query, work_package: work_package_4, position: 3)
::OrderedWorkPackage.create(query:, work_package: work_package1, position: 0)
::OrderedWorkPackage.create(query:, work_package: work_package2, position: 1)
::OrderedWorkPackage.create(query:, work_package: work_package3, position: 2)
::OrderedWorkPackage.create(query:, work_package: work_package4, position: 3)
end
it 'can inline create a work package and it is positioned to the bottom (Regression #31078)' do
wp_table.visit_query query
wp_table.expect_work_package_order work_package_1, work_package_2, work_package_3, work_package_4
wp_table.expect_work_package_order work_package1, work_package2, work_package3, work_package4
wp_table.click_inline_create
subject_field = wp_table.edit_field(nil, :subject)
@@ -271,26 +272,26 @@ describe 'Manual sorting of WP table', type: :feature, js: true do
# Wait until the order was saved, this might take a few moments
retry_block do
order = ::OrderedWorkPackage.find_by(query: query, work_package: inline_created)
order = ::OrderedWorkPackage.find_by(query:, work_package: inline_created)
unless order&.position == 8195
raise "Expected order of #{inline_created.id} to be 8195. Was: #{order&.position}. Retrying"
end
end
wp_table.expect_work_package_order work_package_1, work_package_2, work_package_3, work_package_4, inline_created
wp_table.expect_work_package_order work_package1, work_package2, work_package3, work_package4, inline_created
# Revisit the query
wp_table.visit_query query
# Expect same order
wp_table.expect_work_package_order work_package_1, work_package_2, work_package_3, work_package_4, inline_created
wp_table.expect_work_package_order work_package1, work_package2, work_package3, work_package4, inline_created
end
end
describe 'with a saved query that is NOT manually sorted' do
let(:query) do
create(:query, user: user, project: project, show_hierarchies: false).tap do |q|
create(:query, user:, project:, show_hierarchies: false).tap do |q|
q.sort_criteria = [[:id, 'asc']]
q.save!
end
@@ -298,11 +299,11 @@ describe 'Manual sorting of WP table', type: :feature, js: true do
it 'can drag and drop and will save the query' do
wp_table.visit_query query
wp_table.expect_work_package_order work_package_1, work_package_2, work_package_3, work_package_4
wp_table.expect_work_package_order work_package1, work_package2, work_package3, work_package4
wp_table.drag_and_drop_work_package from: 1, to: 3
wp_table.expect_work_package_order work_package_1, work_package_3, work_package_2, work_package_4
wp_table.expect_work_package_order work_package1, work_package3, work_package2, work_package4
wp_table.expect_and_dismiss_toaster message: 'Successful update.'
@@ -323,26 +324,24 @@ describe 'Manual sorting of WP table', type: :feature, js: true do
before do
wp_table.visit!
hierarchies.disable_via_header
wp_table.expect_work_package_order work_package_1, work_package_2, work_package_3, work_package_4
wp_table.expect_work_package_order work_package1, work_package2, work_package3, work_package4
end
it 'can sort table rows via DragNDrop' do
wp_table.drag_and_drop_work_package from: 1, to: 3
wp_table.expect_work_package_order work_package_1, work_package_3, work_package_2, work_package_4
wp_table.save_as 'Manual sorted query'
wp_table.expect_work_package_order work_package1, work_package3, work_package2, work_package4
wp_table.expect_and_dismiss_toaster message: 'Successful creation.'
query = Query.last
expect(query.name).to eq 'Manual sorted query'
expect(query.name).to eq 'New manually sorted query'
expect_query_order(query, [work_package_1.id, work_package_3.id, work_package_2.id])
expect_query_order(query, [work_package1.id, work_package3.id, work_package2.id])
wp_table.drag_and_drop_work_package from: 0, to: 2
expect_query_order(query, [work_package_3.id, work_package_1.id, work_package_2.id])
expect_query_order(query, [work_package3.id, work_package1.id, work_package2.id])
end
it 'saves the changed order in a previously saved query' do
@@ -354,11 +353,11 @@ describe 'Manual sorting of WP table', type: :feature, js: true do
wp_table.drag_and_drop_work_package from: 1, to: 3
wp_table.expect_work_package_order work_package_1, work_package_3, work_package_2, work_package_4
wp_table.expect_work_package_order work_package1, work_package3, work_package2, work_package4
query = Query.last
expect(query.name).to eq 'Manual sorted query'
expect_query_order(query, [work_package_1.id, work_package_3.id, work_package_2.id])
expect_query_order(query, [work_package1.id, work_package3.id, work_package2.id])
pagination.expect_range(1, 4, 4)
pagination.expect_no_per_page_options
@@ -367,7 +366,7 @@ describe 'Manual sorting of WP table', type: :feature, js: true do
it 'does not loose the current order when switching to manual sorting' do
# Sort by creation date
sort_by.update_criteria 'Created on'
wp_table.expect_work_package_order work_package_4, work_package_3, work_package_2, work_package_1
wp_table.expect_work_package_order work_package4, work_package3, work_package2, work_package1
# Enable manual sorting
sort_by.open_modal
@@ -375,13 +374,13 @@ describe 'Manual sorting of WP table', type: :feature, js: true do
sort_by.apply_changes
# Expect same order
wp_table.expect_work_package_order work_package_4, work_package_3, work_package_2, work_package_1
wp_table.expect_work_package_order work_package4, work_package3, work_package2, work_package1
end
it 'shows a warning when switching from manual to automatic sorting' do
wp_table.drag_and_drop_work_package from: 1, to: 3
wp_table.expect_work_package_order work_package_1, work_package_3, work_package_2, work_package_4
wp_table.expect_work_package_order work_package1, work_package3, work_package2, work_package4
# Try to sort by creation date
sort_by.sort_via_header 'Subject'
@@ -389,10 +388,10 @@ describe 'Manual sorting of WP table', type: :feature, js: true do
# Shows a warning
dialog.expect_open
dialog.confirm
wp_table.expect_work_package_order work_package_1, work_package_2, work_package_3, work_package_4
wp_table.expect_work_package_order work_package1, work_package2, work_package3, work_package4
end
context 'the gantt chart' do
context 'when view is gantt chart' do
let(:wp_timeline) { Pages::WorkPackagesTimeline.new(project) }
it 'reloads after drop' do
@@ -400,11 +399,36 @@ describe 'Manual sorting of WP table', type: :feature, js: true do
wp_timeline.expect_timeline!
wp_timeline.expect_row_count(4)
wp_timeline.expect_work_package_order work_package_1, work_package_2, work_package_3, work_package_4
wp_timeline.expect_work_package_order work_package1, work_package2, work_package3, work_package4
wp_table.drag_and_drop_work_package from: 1, to: 3
wp_table.expect_work_package_order work_package_1, work_package_3, work_package_2, work_package_4
wp_timeline.expect_work_package_order work_package_1, work_package_3, work_package_2, work_package_4
wp_table.expect_work_package_order work_package1, work_package3, work_package2, work_package4
wp_timeline.expect_work_package_order work_package1, work_package3, work_package2, work_package4
end
end
context 'when view is card' do
let(:wp_card) { Pages::WorkPackageCards.new(project) }
before do
display_representation.switch_to_card_layout
loading_indicator_saveguard
end
it 'can sort cards via DragNDrop' do
wp_card.drag_and_drop_work_package from: 0, to: 3
wp_card.expect_work_package_order work_package2, work_package3, work_package4, work_package1
wp_card.expect_and_dismiss_toaster message: 'Successful creation.'
query = Query.last
expect(query.name).to eq 'New manually sorted query'
expect_query_order(query, [work_package2.id, work_package3.id, work_package4.id, work_package1.id])
wp_card.drag_and_drop_work_package from: 0, to: 2
expect_query_order(query, [work_package3.id, work_package4.id, work_package1.id, work_package2.id])
end
end
end
+54 -5
View File
@@ -74,14 +74,14 @@ module Pages
Capybara.current_session.driver.is_a?(Capybara::Selenium::Driver)
end
def set_items_per_page!(n)
Setting.per_page_options = "#{n}, 50, 100"
def set_items_per_page!(number)
Setting.per_page_options = "#{number}, 50, 100"
end
def expect_current_path(query_params = nil)
uri = URI.parse(current_url)
current_path = uri.path
current_path += '?' + uri.query if uri.query
current_path += "?#{uri.query}" if uri.query
expected_path = path
expected_path += "?#{query_params}" if query_params
@@ -102,9 +102,9 @@ module Pages
end
def expect_and_dismiss_toaster(message:, type: :success)
expect_toast(type: type, message: message)
expect_toast(type:, message:)
dismiss_toaster!
expect_no_toaster(type: type, message: message)
expect_no_toaster(type:, message:)
end
def dismiss_toaster!
@@ -123,6 +123,55 @@ module Pages
end
end
def drag_and_drop_list(from:, to:, elements:, handler:)
# Wait a bit because drag & drop in selenium is easily offended
sleep 1
list = page.all(elements)
source = list[from]
target = list[to]
scroll_to_element(source)
source.hover
page
.driver
.browser
.action
.move_to(source.native)
.click_and_hold(source.find(handler).native)
.perform
## Hover over each item to be sure,
# that the dragged element is reduced to the minimum height.
# Thus we can afterwards drag to the correct position.
list.each do |item|
next if item == source
page
.driver
.browser
.action
.move_to(item.native)
.perform
end
sleep 2
scroll_to_element(target)
page
.driver
.browser
.action
.move_to(target.native)
.release
.perform
# Wait a bit because drag & drop in selenium is easily offended
sleep 1
end
def path
nil
end
@@ -35,6 +35,7 @@ module Pages
def initialize(project = nil)
@project = project
super()
end
def expect_work_package_listed(*work_packages)
@@ -80,6 +81,10 @@ module Pages
::Pages::SplitWorkPackage.new(work_package, project)
end
def drag_and_drop_work_package(from:, to:)
drag_and_drop_list(from:, to:, elements: 'wp-single-card', handler: '.op-wp-single-card--content')
end
def select_work_package(work_package)
card(work_package).click
end
@@ -37,6 +37,7 @@ module Pages
def initialize(project = nil)
@project = project
super()
end
def visit_query(query)
@@ -75,9 +76,9 @@ module Pages
end
end
def expect_work_package_count(n)
def expect_work_package_count(count)
within(table_container) do
expect(page).to have_selector(".wp--row", count: n, wait: 20)
expect(page).to have_selector(".wp--row", count:, wait: 20)
end
end
@@ -171,60 +172,15 @@ module Pages
end
def drag_and_drop_work_package(from:, to:)
# Wait a bit because drag & drop in selenium is easily offended
sleep 1
rows = page.all('.wp-table--row')
source = rows[from]
target = rows[to]
scroll_to_element(source)
source.hover
page
.driver
.browser
.action
.move_to(source.native)
.click_and_hold(source.find('.wp-table--drag-and-drop-handle', visible: false).native)
.perform
## Hover over each row to be sure,
# that the dragged element is reduced to the minimum height.
# Thus we can afterwards drag to the correct position.
rows.each do |row|
next if row == source
page
.driver
.browser
.action
.move_to(row.native)
.perform
end
sleep 2
scroll_to_element(target)
page
.driver
.browser
.action
.move_to(target.native)
.release
.perform
# Wait a bit because drag & drop in selenium is easily offended
sleep 1
drag_and_drop_list(from:, to:, elements: '.wp-table--row', handler: '.wp-table--drag-and-drop-handle')
end
def row(work_package)
table_container.find(row_selector(work_package))
end
def row_selector(el)
id = el.is_a?(WorkPackage) ? el.id.to_s : el.to_s
def row_selector(elem)
id = elem.is_a?(WorkPackage) ? elem.id.to_s : elem.to_s
".wp-row-#{id}-table"
end
@@ -34,6 +34,7 @@ class WorkPackageCards
def initialize(project = nil)
@project = project
super()
end
def open_full_screen_by_doubleclick(work_package)