From 41e52a69a4b4e31fd7ab46eef189b9b16237b4a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20G=C3=BCnther?= Date: Mon, 20 Apr 2020 11:03:04 +0200 Subject: [PATCH] Correctly load groups trough hrefs We used the user service which does not allow loading groups. https://community.openproject.com/wp/33072 --- .../assignee/assignee-action.service.ts | 38 ++++++++++++------- .../modules/hal/resources/group-resource.ts | 33 ++++++++++++++++ .../hal/services/hal-resource.config.ts | 5 ++- .../action_boards/assignee_board_spec.rb | 35 +++++++++++++++-- .../spec/features/support/board_index_page.rb | 5 ++- 5 files changed, 97 insertions(+), 19 deletions(-) create mode 100644 frontend/src/app/modules/hal/resources/group-resource.ts diff --git a/frontend/src/app/modules/boards/board/board-actions/assignee/assignee-action.service.ts b/frontend/src/app/modules/boards/board/board-actions/assignee/assignee-action.service.ts index 71543abbd4..ff7f68ec2d 100644 --- a/frontend/src/app/modules/boards/board/board-actions/assignee/assignee-action.service.ts +++ b/frontend/src/app/modules/boards/board/board-actions/assignee/assignee-action.service.ts @@ -8,19 +8,21 @@ import {I18nService} from "core-app/modules/common/i18n/i18n.service"; import {FilterOperator} from "core-components/api/api-v3/api-v3-filter-builder"; import {CreateAutocompleterComponent} from "core-app/modules/common/autocomplete/create-autocompleter.component"; import {OpContextMenuItem} from "core-components/op-context-menu/op-context-menu.types"; -import {UserCacheService} from 'core-app/components/user/user-cache.service'; import {UserResource} from 'core-app/modules/hal/resources/user-resource'; import {CurrentProjectService} from 'core-app/components/projects/current-project.service'; import {CollectionResource} from 'core-app/modules/hal/resources/collection-resource'; import {HalResourceService} from 'core-app/modules/hal/services/hal-resource.service'; import {AssigneeBoardHeaderComponent} from "core-app/modules/boards/board/board-actions/assignee/assignee-board-header.component"; +import {input} from "reactivestates"; +import {take} from "rxjs/operators"; @Injectable() export class BoardAssigneeActionService implements BoardActionService { + private assignees = input(); + constructor(protected boardListsService:BoardListsService, protected I18n:I18nService, - protected userCache:UserCacheService, protected halResourceService:HalResourceService, protected currentProject:CurrentProjectService ) { @@ -49,15 +51,16 @@ export class BoardAssigneeActionService implements BoardActionService { * Returns the loaded assignee * @param query */ - public getLoadedFilterValue(query:QueryResource):Promise { + public getLoadedFilterValue(query:QueryResource):Promise { const href = this.getFilterHref(query); - if (href) { - const id = HalResource.idFromLink(href); - return this.userCache.require(id); - } else { + if (!href) { return Promise.resolve(undefined); } + + return this + .getAssignees() + .then(collection => collection.find(resource => resource.href === href)); } public canAddToQuery(query:QueryResource):Promise { @@ -95,7 +98,8 @@ export class BoardAssigneeActionService implements BoardActionService { queries.map(query => this.getFilterHref(query)) ); - return this.getAssignees(board) + return this + .getAssignees() .then(results => results.filter(assignee => !active.has(assignee.href!)) ); @@ -117,17 +121,23 @@ export class BoardAssigneeActionService implements BoardActionService { return AssigneeBoardHeaderComponent; } - public disabledAddButtonPlaceholder(assignee:UserResource) { + public disabledAddButtonPlaceholder(assignee:HalResource) { return undefined; } - private getAssignees(board:Board):Promise { + private getAssignees():Promise { const projectIdentifier = this.currentProject.identifier!; - let myData = this.halResourceService.get('/api/v3/projects/' + projectIdentifier + '/available_assignees').toPromise(); - + this.assignees.putFromPromiseIfPristine(() => + this.halResourceService + .get('/api/v3/projects/' + projectIdentifier + '/available_assignees') + .toPromise() + .then((collection:CollectionResource) => collection.elements) + ); - return myData - .then((collection:CollectionResource) => collection.elements); + return this.assignees + .values$() + .pipe(take(1)) + .toPromise(); } } diff --git a/frontend/src/app/modules/hal/resources/group-resource.ts b/frontend/src/app/modules/hal/resources/group-resource.ts new file mode 100644 index 0000000000..b50924d248 --- /dev/null +++ b/frontend/src/app/modules/hal/resources/group-resource.ts @@ -0,0 +1,33 @@ +//-- 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-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 docs/COPYRIGHT.rdoc for more details. +//++ + +import {HalResource} from 'core-app/modules/hal/resources/hal-resource'; + +export class GroupResource extends HalResource { + public name:string; +} diff --git a/frontend/src/app/modules/hal/services/hal-resource.config.ts b/frontend/src/app/modules/hal/services/hal-resource.config.ts index 0a319c63aa..e85752c964 100644 --- a/frontend/src/app/modules/hal/services/hal-resource.config.ts +++ b/frontend/src/app/modules/hal/services/hal-resource.config.ts @@ -48,7 +48,6 @@ import { HalResourceFactoryConfigInterface, HalResourceService } from 'core-app/modules/hal/services/hal-resource.service'; -import {Injectable} from '@angular/core'; import {HalResource} from 'core-app/modules/hal/resources/hal-resource'; import {WikiPageResource} from "core-app/modules/hal/resources/wiki-page-resource"; import {MeetingContentResource} from "core-app/modules/hal/resources/meeting-content-resource"; @@ -63,6 +62,7 @@ import {VersionResource} from "core-app/modules/hal/resources/version-resource"; import {MembershipResource} from "core-app/modules/hal/resources/membership-resource"; import {RoleResource} from "core-app/modules/hal/resources/role-resource"; import {ProjectResource} from "core-app/modules/hal/resources/project-resource"; +import {GroupResource} from "core-app/modules/hal/resources/group-resource"; const halResourceDefaultConfig:{ [typeName:string]:HalResourceFactoryConfigInterface } = { WorkPackage: { @@ -120,6 +120,9 @@ const halResourceDefaultConfig:{ [typeName:string]:HalResourceFactoryConfigInter User: { cls: UserResource }, + Group: { + cls: GroupResource + }, Collection: { cls: CollectionResource }, diff --git a/modules/boards/spec/features/action_boards/assignee_board_spec.rb b/modules/boards/spec/features/action_boards/assignee_board_spec.rb index 3f7dcce427..40a476f1fb 100644 --- a/modules/boards/spec/features/action_boards/assignee_board_spec.rb +++ b/modules/boards/spec/features/action_boards/assignee_board_spec.rb @@ -32,7 +32,6 @@ require_relative './../support/board_page' describe 'Assignee action board', type: :feature, - driver: :firefox_headless_en, js: true do let(:bobself_user) do FactoryBot.create(:user, @@ -65,6 +64,15 @@ describe 'Assignee action board', member_through_role: role) end + let!(:group) do + FactoryBot.create(:group, groupname: 'Grouped').tap do |group| + FactoryBot.create(:member, + principal: group, + project: project, + roles: [role]) + end + end + let!(:work_package) { FactoryBot.create :work_package, project: project, assigned_to: bobself_user, @@ -93,22 +101,31 @@ describe 'Assignee action board', board_page.add_list option: 'Foo Bar' board_page.expect_list 'Foo Bar' + # Add grouped list + board_page.add_list option: 'Grouped' + board_page.expect_list 'Grouped' + board_page.board(reload: true) do |board| expect(board.name).to eq 'Action board (assignee)' queries = board.contained_queries - expect(queries.count).to eq(2) + expect(queries.count).to eq(3) bob = queries.first - foo = queries.last + foo = queries.second + grouped = queries.last expect(bob.name).to eq 'Bob Self' expect(foo.name).to eq 'Foo Bar' + expect(grouped.name).to eq 'Grouped' expect(bob.filters.first.name).to eq :assigned_to_id expect(bob.filters.first.values).to eq [bobself_user.id.to_s] expect(foo.filters.first.name).to eq :assigned_to_id expect(foo.filters.first.values).to eq [foobar_user.id.to_s] + + expect(grouped.filters.first.name).to eq :assigned_to_id + expect(grouped.filters.first.values).to eq [group.id.to_s] end # First, expect work package to be assigned to "Bob self" @@ -128,5 +145,17 @@ describe 'Assignee action board', work_package.reload expect(work_package.assigned_to).to eq(foobar_user) + + # Move to group column + board_page.move_card(0, from: 'Foo Bar', to: 'Grouped') + board_page.expect_card 'Grouped', 'Some Task' + board_page.expect_card 'Foo Bar', 'Some Task', present: false + board_page.expect_card 'Bob Self', 'Some Task', present: false + + # Expect to have changed the avatar + expect(page).to have_selector('.wp-card--assignee .avatar-default', text: 'GG', wait: 10) + + work_package.reload + expect(work_package.assigned_to).to eq(group) end end diff --git a/modules/boards/spec/features/support/board_index_page.rb b/modules/boards/spec/features/support/board_index_page.rb index e0980ea271..8980d48006 100644 --- a/modules/boards/spec/features/support/board_index_page.rb +++ b/modules/boards/spec/features/support/board_index_page.rb @@ -66,7 +66,10 @@ module Pages find('.button', text: 'Action board').click end - unless expect_empty + if expect_empty + expect(page).to have_selector('.boards-list--add-item-text', wait: 10) + expect(page).to have_no_selector('.boards-list--item') + else expect(page).to have_selector('.boards-list--item', wait: 10) end