Skip to content

Commit

Permalink
Merge pull request #14576 from opf/implementation/51287-different-too…
Browse files Browse the repository at this point in the history
…lbar-for-gantt-and-work-packages

[51287] Different toolbar for Gantt and Work Packages
  • Loading branch information
oliverguenther committed Jan 23, 2024
2 parents dfb29e4 + 8befe5f commit 22407ee
Show file tree
Hide file tree
Showing 33 changed files with 554 additions and 597 deletions.
Expand Up @@ -34,6 +34,7 @@ import { WorkPackageNotificationService } from 'core-app/features/work-packages/
import { ApiV3Service } from 'core-app/core/apiv3/api-v3.service';
import { QueryFormResource } from 'core-app/features/hal/resources/query-form-resource';
import { QueryResource } from 'core-app/features/hal/resources/query-resource';
import { StateService } from '@uirouter/angular';

export const WpTableConfigurationModalPrependToken = new InjectionToken<ComponentType<any>>('WpTableConfigurationModalPrependComponent');

Expand Down Expand Up @@ -67,9 +68,10 @@ export class WpTableConfigurationModalComponent extends OpModalComponent impleme

// Try to load an optional provided configuration service, and fall back to the default one
private wpTableConfigurationService:WpTableConfigurationService =
this.injector.get(WpTableConfigurationService, new WpTableConfigurationService(this.I18n));
this.injector.get(WpTableConfigurationService, new WpTableConfigurationService(this.I18n, this.$state, this.configurationService));

constructor(@Inject(OpModalLocalsToken) public locals:OpModalLocalsMap,
constructor(
@Inject(OpModalLocalsToken) public locals:OpModalLocalsMap,
@Optional() @Inject(WpTableConfigurationModalPrependToken) public prependModalComponent:ComponentType<any>|null,
readonly I18n:I18nService,
readonly injector:Injector,
Expand All @@ -83,7 +85,10 @@ export class WpTableConfigurationModalComponent extends OpModalComponent impleme
readonly wpTableColumns:WorkPackageViewColumnsService,
readonly cdRef:ChangeDetectorRef,
readonly ConfigurationService:ConfigurationService,
readonly elementRef:ElementRef) {
readonly elementRef:ElementRef,
readonly $state:StateService,
readonly configurationService:ConfigurationService,
) {
super(locals, cdRef, elementRef);
}

Expand Down
Expand Up @@ -8,6 +8,8 @@ import { WpTableConfigurationSortByTabComponent } from 'core-app/features/work-p
import { WpTableConfigurationTimelinesTabComponent } from 'core-app/features/work-packages/components/wp-table/configuration-modal/tabs/timelines-tab.component';
import { WpTableConfigurationHighlightingTabComponent } from 'core-app/features/work-packages/components/wp-table/configuration-modal/tabs/highlighting-tab.component';
import { OpBaselineComponent } from 'core-app/features/work-packages/components/wp-baseline/baseline/baseline.component';
import { StateService } from '@uirouter/angular';
import { ConfigurationService } from 'core-app/core/config/configuration.service';

@Injectable()
export class WpTableConfigurationService {
Expand Down Expand Up @@ -42,17 +44,26 @@ export class WpTableConfigurationService {
name: this.I18n.t('js.work_packages.table_configuration.highlighting'),
componentClass: WpTableConfigurationHighlightingTabComponent,
},
{
id: 'timelines',
name: this.I18n.t('js.gantt_chart.label'),
componentClass: WpTableConfigurationTimelinesTabComponent,
},
];

constructor(readonly I18n:I18nService) {
constructor(
readonly I18n:I18nService,
readonly $state:StateService,
readonly configurationService:ConfigurationService,
) {
}

public get tabs() {
return this._tabs;
if (this.configurationService.activeFeatureFlags.includes('showSeparateGanttModule') && (this.$state.current.name?.includes('work-packages') || this.$state.current.name?.includes('bim'))) {
return this._tabs;
}

return this._tabs.concat([
{
id: 'timelines',
name: this.I18n.t('js.gantt_chart.label'),
componentClass: WpTableConfigurationTimelinesTabComponent,
},
]);
}
}
Expand Up @@ -4,19 +4,25 @@ import { TabInterface } from 'core-app/features/work-packages/components/wp-tabl
import { WpTableConfigurationService } from 'core-app/features/work-packages/components/wp-table/configuration-modal/wp-table-configuration.service';
import { QueryConfigurationLocals } from 'core-app/features/work-packages/components/wp-table/external-configuration/external-query-configuration.component';
import { OpQueryConfigurationLocalsToken } from 'core-app/features/work-packages/components/wp-table/external-configuration/external-query-configuration.constants';
import { StateService } from '@uirouter/angular';
import { ConfigurationService } from 'core-app/core/config/configuration.service';

@Injectable()
export class RestrictedWpTableConfigurationService extends WpTableConfigurationService {
constructor(@Inject(OpQueryConfigurationLocalsToken) readonly locals:QueryConfigurationLocals,
readonly I18n:I18nService) {
super(I18n);
constructor(
@Inject(OpQueryConfigurationLocalsToken) readonly locals:QueryConfigurationLocals,
readonly I18n:I18nService,
readonly $state:StateService,
readonly configurationService:ConfigurationService,
) {
super(I18n, $state, configurationService);
}

public get tabs():TabInterface[] {
const disabledTabs = this.locals.disabledTabs || {};

return this
._tabs
return super
.tabs
.map((el) => {
const reason = disabledTabs[el.id];
if (reason != null) {
Expand Down
Expand Up @@ -230,9 +230,6 @@ import {
import {
WorkPackagesTableConfigMenuComponent,
} from 'core-app/features/work-packages/components/wp-table/config-menu/config-menu.component';
import {
WorkPackageViewToggleButtonComponent,
} from 'core-app/features/work-packages/components/wp-buttons/wp-view-toggle-button/work-package-view-toggle-button.component';
import {
WorkPackageViewDropdownMenuDirective,
} from 'core-app/shared/components/op-context-menu/handlers/wp-view-dropdown-menu.directive';
Expand Down Expand Up @@ -417,6 +414,7 @@ import {
import {
WorkPackageShareModalComponent,
} from 'core-app/features/work-packages/components/wp-share-modal/wp-share.modal';
import { WorkPackageViewToggleButtonComponent } from 'core-app/features/work-packages/components/wp-buttons/wp-view-toggle-button/work-package-view-toggle-button.component';

@NgModule({
imports: [
Expand Down
Expand Up @@ -37,7 +37,6 @@ import {
} from 'core-app/features/work-packages/routing/partitioned-query-space-page/partitioned-query-space-page.component';
import { WorkPackageCreateButtonComponent } from 'core-app/features/work-packages/components/wp-buttons/wp-create-button/wp-create-button.component';
import { WorkPackageFilterButtonComponent } from 'core-app/features/work-packages/components/wp-buttons/wp-filter-button/wp-filter-button.component';
import { WorkPackageViewToggleButtonComponent } from 'core-app/features/work-packages/components/wp-buttons/wp-view-toggle-button/work-package-view-toggle-button.component';
import { WorkPackageDetailsViewButtonComponent } from 'core-app/features/work-packages/components/wp-buttons/wp-details-view-button/wp-details-view-button.component';
import { WorkPackageTimelineButtonComponent } from 'core-app/features/work-packages/components/wp-buttons/wp-timeline-toggle-button/wp-timeline-toggle-button.component';
import { ZenModeButtonComponent } from 'core-app/features/work-packages/components/wp-buttons/zen-mode-toggle-button/zen-mode-toggle-button.component';
Expand All @@ -46,6 +45,7 @@ import { of } from 'rxjs';
import { WorkPackageFoldToggleButtonComponent } from 'core-app/features/work-packages/components/wp-buttons/wp-fold-toggle-button/wp-fold-toggle-button.component';
import { OpProjectIncludeComponent } from 'core-app/shared/components/project-include/project-include.component';
import { OpBaselineModalComponent } from 'core-app/features/work-packages/components/wp-baseline/baseline-modal/baseline-modal.component';
import { WorkPackageViewToggleButtonComponent } from 'core-app/features/work-packages/components/wp-buttons/wp-view-toggle-button/work-package-view-toggle-button.component';

@Component({
selector: 'wp-view-page',
Expand All @@ -66,7 +66,7 @@ export class WorkPackageViewPageComponent extends PartitionedQuerySpacePageCompo
{
component: WorkPackageCreateButtonComponent,
inputs: {
stateName$: of('work-packages.partitioned.list.new'),
stateName$: of(this.stateName),
allowed: ['work_packages.createWorkPackage'],
},
},
Expand All @@ -83,6 +83,7 @@ export class WorkPackageViewPageComponent extends PartitionedQuerySpacePageCompo
{
component: WorkPackageViewToggleButtonComponent,
containerClasses: 'hidden-for-tablet',
show: () => !this.configuration.activeFeatureFlags.includes('showSeparateGanttModule'),
},
{
component: WorkPackageFoldToggleButtonComponent,
Expand Down Expand Up @@ -123,4 +124,12 @@ export class WorkPackageViewPageComponent extends PartitionedQuerySpacePageCompo
protected shouldUpdateHtmlTitle():boolean {
return this.$state.current.name === 'work-packages.partitioned.list';
}

private get stateName() {
if (this.configuration.activeFeatureFlags.includes('showSeparateGanttModule') && this.$state.current.name?.includes('gantt')) {
return 'gantt.partitioned.list.new';
}

return 'work-packages.partitioned.list.new';
}
}
123 changes: 123 additions & 0 deletions modules/bim/spec/features/card_view/bulk_actions_spec.rb
@@ -0,0 +1,123 @@
require 'spec_helper'
require_relative '../../support/pages/ifc_models/show_default'

RSpec.describe 'Copy work packages through Rails view', :js, :with_cuprite, with_config: { edition: 'bim' } do
shared_let(:project) { create(:project, name: 'Source', enabled_module_names: %i[bim work_package_tracking]) }

shared_let(:dev) do
create(:user,
firstname: 'Dev',
lastname: 'Guy',
member_with_permissions: { project => %i[view_work_packages work_package_assigned
view_ifc_models view_linked_issues] })
end
shared_let(:mover) do
create(:user,
firstname: 'Manager',
lastname: 'Guy',
member_with_permissions: {
project => %i[view_work_packages view_ifc_models view_linked_issues
copy_work_packages move_work_packages manage_subtasks assign_versions edit_work_packages
add_work_packages]
})
end

shared_let(:work_package) do
create(:work_package, project:)
end
shared_let(:work_package2) do
create(:work_package, project:)
end

let(:wp_table) { Pages::IfcModels::ShowDefault.new(project) }
let(:context_menu) { Components::WorkPackages::ContextMenu.new }

before do
login_as current_user
wp_table.visit!
expect_angular_frontend_initialized
wp_table.expect_work_package_listed work_package, work_package2

wp_table.switch_view 'Cards'
loading_indicator_saveguard

# Select all work packages
find('body').send_keys [:control, 'a']
end

describe 'accessing the bulk copy from the card view' do
context 'with permissions' do
let(:current_user) { mover }

it 'does allow to copy' do
context_menu.open_for work_package, card_view: true
context_menu.expect_options 'Bulk copy'
end
end

context 'without permission' do
let(:current_user) { dev }

it 'does not allow to copy' do
context_menu.open_for work_package, card_view: true
context_menu.expect_no_options 'Bulk copy'
end
end
end

describe 'accessing the bulk move from the card view' do
context 'with permissions' do
let(:current_user) { mover }

it 'does allow to move' do
context_menu.open_for work_package, card_view: true
context_menu.expect_options 'Bulk change of project'
end
end

context 'without permission' do
let(:current_user) { dev }

it 'does not allow to move' do
context_menu.open_for work_package, card_view: true
context_menu.expect_no_options 'Bulk change of project'
end
end
end

describe 'accessing the bulk edit from the card view' do
context 'with permissions' do
let(:current_user) { mover }

it 'does allow to edit' do
context_menu.open_for work_package, card_view: true
context_menu.expect_options 'Bulk edit'
end

context 'with a project budget' do
let!(:budget) { create(:budget, project:) }

it 'updates all the work packages' do
context_menu.open_for work_package, card_view: true
context_menu.choose 'Bulk edit'

select budget.subject, from: 'work_package_budget_id'
click_on 'Submit'
wp_table.expect_and_dismiss_toaster message: 'Successful update.'

expect(work_package.reload.budget_id).to eq(budget.id)
expect(work_package2.reload.budget_id).to eq(budget.id)
end
end
end

context 'without permission' do
let(:current_user) { dev }

it 'does not allow to edit' do
context_menu.open_for work_package, card_view: true
context_menu.expect_no_options 'Bulk edit'
end
end
end
end
66 changes: 66 additions & 0 deletions modules/bim/spec/features/card_view/context_menu_spec.rb
@@ -0,0 +1,66 @@
require 'spec_helper'
require_relative '../../../../../spec/features/work_packages/table/context_menu/context_menu_shared_examples'
require_relative '../../support/pages/ifc_models/show_default'

RSpec.describe 'Work Package table hierarchy and sorting', :js, :with_cuprite, with_config: { edition: 'bim' } do
shared_let(:project) { create(:project, enabled_module_names: %i[bim work_package_tracking costs]) }

let(:wp_table) { Pages::IfcModels::ShowDefault.new(project) }
let(:hierarchy) { Components::WorkPackages::Hierarchies.new }

shared_let(:work_package) do
create(:work_package,
project:,
subject: 'Parent')
end

shared_let(:wp_child1) do
create(:work_package,
project:,
parent: work_package,
subject: 'WP child 1')
end

shared_let(:wp_child2) do
create(:work_package,
project:,
parent: work_package,
subject: 'WP child 2')
end
shared_let(:menu) { Components::WorkPackages::ContextMenu.new }

shared_current_user { create(:admin) }

it 'does not show indentation context in card view' do
wp_table.visit!
loading_indicator_saveguard
wp_table.expect_work_package_listed(work_package, wp_child1, wp_child2)

wp_table.switch_view 'Cards'
expect(page).to have_test_selector('op-wp-single-card', count: 3)

# Expect indent-able for none
hierarchy.expect_indent(work_package, indent: false, outdent: false, card_view: true)
hierarchy.expect_indent(wp_child1, indent: false, outdent: false, card_view: true)
hierarchy.expect_indent(wp_child2, indent: false, outdent: false, card_view: true)
end

it_behaves_like 'provides a single WP context menu' do
let(:open_context_menu) do
-> {
# Go to table
wp_table.visit!
loading_indicator_saveguard

wp_table.expect_work_package_listed(work_package)

wp_table.switch_view 'Cards'
loading_indicator_saveguard

# Open context menu
menu.expect_closed
menu.open_for(work_package, card_view: true)
}
end
end
end

0 comments on commit 22407ee

Please sign in to comment.