extract wp table config menu trigger into own component

This commit is contained in:
ulferts
2019-06-12 08:19:45 +02:00
parent 9c0455afb5
commit 32bbbca2bf
19 changed files with 252 additions and 77 deletions
+3
View File
@@ -86,6 +86,7 @@ import {MainMenuNavigationService} from "core-components/main-menu/main-menu-nav
import {StatusCacheService} from "core-components/statuses/status-cache.service";
import {VersionCacheService} from "core-components/versions/version-cache.service";
import {FormsCacheService} from "core-components/forms/forms-cache.service";
import {OpenprojectContextMenuModule} from "core-app/modules/context-menu/openproject-context-menu.module";
@NgModule({
imports: [
@@ -93,6 +94,8 @@ import {FormsCacheService} from "core-components/forms/forms-cache.service";
BrowserModule,
// Commons
OpenprojectCommonModule,
// ContextMenus
OpenprojectContextMenuModule,
// Router module
OpenprojectRouterModule,
// Hal Module
@@ -0,0 +1,30 @@
import {I18nService} from "core-app/modules/common/i18n/i18n.service";
import {Component, OnInit, Injector} from '@angular/core';
import {OpModalService} from "core-components/op-modals/op-modal.service";
import {OPContextMenuService} from "core-components/op-context-menu/op-context-menu.service";
import {WpTableConfigurationModalComponent} from "core-components/wp-table/configuration-modal/wp-table-configuration.modal";
@Component({
templateUrl: './config-menu.template.html',
selector: 'wp-table-config-menu',
})
export class WorkPackagesTableConfigMenu implements OnInit {
public text:any;
constructor(readonly I18n:I18nService,
readonly injector:Injector,
readonly opModalService:OpModalService,
readonly opContextMenu:OPContextMenuService) {
}
ngOnInit():void {
this.text = {
configureTable: I18n.t('js.toolbar.settings.configure_view')
};
}
public openTableConfigurationModal() {
this.opContextMenu.close();
this.opModalService.show(WpTableConfigurationModalComponent, this.injector);
}
}
@@ -0,0 +1,7 @@
<accessible-by-keyboard
(execute)="openTableConfigurationModal()"
linkClass="wp-table--columns-selection"
[linkTitle]="text.configureTable"
[linkAriaLabel]="text.configureTable">
<op-icon icon-classes="icon-button icon-small icon-settings"></op-icon>
</accessible-by-keyboard>
@@ -32,14 +32,8 @@
<th class="wp-table--configuration-modal--trigger wp-table--context-menu-th -short hide-when-print"
*ngIf="configuration.columnMenuEnabled || configuration.actionsColumnEnabled">
<div class="generic-table--sort-header-outer">
<accessible-by-keyboard
(execute)="openTableConfigurationModal()"
linkClass="wp-table--columns-selection"
[linkTitle]="text.configureTable"
[linkAriaLabel]="text.configureTable"
*ngIf="configuration.columnMenuEnabled">
<op-icon icon-classes="icon-button icon-small icon-settings"></op-icon>
</accessible-by-keyboard>
<wp-table-config-menu>
</wp-table-config-menu>
</div>
</th>
</tr>
@@ -112,8 +112,6 @@ export class WorkPackagesTableController implements OnInit, OnDestroy {
readonly injector:Injector,
readonly states:States,
readonly querySpace:IsolatedQuerySpace,
readonly opModalService:OpModalService,
readonly opContextMenu:OPContextMenuService,
readonly I18n:I18nService,
readonly cdRef:ChangeDetectorRef,
readonly wpTableGroupBy:WorkPackageTableGroupByService,
@@ -138,7 +136,6 @@ export class WorkPackagesTableController implements OnInit, OnDestroy {
title: I18n.t('js.work_packages.no_results.title'),
description: I18n.t('js.work_packages.no_results.description')
},
configureTable: I18n.t('js.toolbar.settings.configure_view'),
tableSummary: I18n.t('js.work_packages.table.summary'),
tableSummaryHints: [
I18n.t('js.work_packages.table.text_inline_edit'),
@@ -200,11 +197,6 @@ export class WorkPackagesTableController implements OnInit, OnDestroy {
this.cdRef.detectChanges();
}
public openTableConfigurationModal() {
this.opContextMenu.close();
this.opModalService.show(WpTableConfigurationModalComponent, this.injector);
}
public get isEmbedded() {
return this.configuration.isEmbedded;
}
@@ -0,0 +1,5 @@
<ng-container class="board-list--more-menu" *ngIf="canDelete">
<icon-triggered-context-menu
[menu-items]="menuItems">
</icon-triggered-context-menu>
</ng-container>
@@ -0,0 +1,94 @@
//-- copyright
// OpenProject is a project management system.
// Copyright (C) 2012-2015 the OpenProject Foundation (OPF)
//
// 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 doc/COPYRIGHT.rdoc for more details.
//++
import {Component, Output, EventEmitter, Input} from '@angular/core';
import {I18nService} from 'core-app/modules/common/i18n/i18n.service';
import {AuthorisationService} from 'core-app/modules/common/model-auth/model-auth.service';
import {OpModalService} from "core-components/op-modals/op-modal.service";
import {IsolatedQuerySpace} from "core-app/modules/work_packages/query-space/isolated-query-space";
import {Board} from "core-app/modules/boards/board/board";
import {BoardActionsRegistryService} from "core-app/modules/boards/board/board-actions/board-actions-registry.service";
import {OpContextMenuItem} from "core-components/op-context-menu/op-context-menu.types";
import {BoardService} from "core-app/modules/boards/board/board.service";
import {BoardActionService} from "core-app/modules/boards/board/board-actions/board-action.service";
@Component({
selector: 'board-list-menu',
templateUrl: './board-list-menu.component.html',
})
export class BoardListMenuComponent {
@Input() board:Board;
@Output() onRemove = new EventEmitter<void>();
constructor(readonly opModalService:OpModalService,
readonly authorisationService:AuthorisationService,
private readonly querySpace:IsolatedQuerySpace,
private readonly boardService:BoardService,
private readonly boardActionRegistry:BoardActionsRegistryService,
readonly I18n:I18nService) {
}
public get menuItems() {
return async () => {
let items:OpContextMenuItem[] = [
{
disabled: !this.canDelete,
linkText: this.I18n.t('js.boards.lists.delete'),
onClick: () => {
this.onRemove.emit();
return true;
}
}
];
// Add action specific menu entries
if (this.board.isAction) {
const additional = await this.actionService.getAdditionalListMenuItems(this.query);
return items.concat(additional);
}
return items;
};
}
private get actionService():BoardActionService {
return this.boardActionRegistry.get(this.board.actionAttribute!);
}
private get canManage() {
return this.boardService.canManage(this.board);
}
public canDelete() {
return this.canManage && !!this.query.delete;
}
private get query() {
return this.querySpace.query.value!;
}
}
@@ -24,11 +24,10 @@
class="-small">
</editable-toolbar-title>
<div class="board-list--menu">
<a boardListDropdown class="board-list--more-menu" *ngIf="canDelete">
<op-icon icon-classes="icon-show-more-horizontal"></op-icon>
</a>
</div>
<board-list-menu class="board-list--menu"
[board]="board"
(onRemove)="deleteList()">
</board-list-menu>
</div>
<div class="board-list--query-container drop-zone"
@@ -70,7 +70,3 @@ $board-list-max-width: 300px
.board-list--menu
visibility: hidden
@include without-link-styling
a, a:hover
color: var(--light-gray)
@@ -45,6 +45,7 @@ import {BoardActionService} from "core-app/modules/boards/board/board-actions/bo
import {ComponentType} from "@angular/cdk/portal";
import {IFieldSchema} from "core-app/modules/fields/field.base";
import {CausedUpdatesService} from "core-app/modules/boards/board/caused-updates/caused-updates.service";
import {BoardListMenuComponent} from "core-app/modules/boards/board/board-list/board-list-menu.component";
export interface DisabledButtonPlaceholder {
text:string;
@@ -57,7 +58,8 @@ export interface DisabledButtonPlaceholder {
styleUrls: ['./board-list.component.sass'],
providers: [
{provide: WorkPackageInlineCreateService, useClass: BoardInlineCreateService},
CausedUpdatesService
CausedUpdatesService,
BoardListMenuComponent,
]
})
export class BoardListComponent extends AbstractWidgetComponent implements OnInit, OnDestroy, OnChanges {
@@ -198,9 +200,9 @@ export class BoardListComponent extends AbstractWidgetComponent implements OnIni
return this.boardService.canManage(this.board);
}
public get canDelete() {
return this.canManage && !!this.query.delete;
}
//public get canDelete() {
// return this.canManage && !!this.query.delete;
//}
public get canRename() {
return this.canManage &&
@@ -50,12 +50,13 @@ import {BoardHighlightingTabComponent} from "core-app/modules/boards/board/confi
import {AddCardDropdownMenuDirective} from "core-app/modules/boards/board/add-card-dropdown/add-card-dropdown-menu.directive";
import {BoardFilterComponent} from "core-app/modules/boards/board/board-filter/board-filter.component";
import {DragScrollModule} from "cdk-drag-scroll";
import {BoardListDropdownMenuDirective} from "core-app/modules/boards/board/board-list/board-list-dropdown.directive";
import {BoardListMenuComponent} from "core-app/modules/boards/board/board-list/board-list-menu.component";
import {VersionBoardHeaderComponent} from "core-app/modules/boards/board/board-actions/version/version-board-header.component";
import {DynamicModule} from "ng-dynamic-component";
import {BoardStatusActionService} from "core-app/modules/boards/board/board-actions/status/status-action.service";
import {BoardVersionActionService} from "core-app/modules/boards/board/board-actions/version/version-action.service";
import {QueryUpdatedService} from "core-app/modules/boards/board/query-updated/query-updated.service";
import {OpenprojectContextMenuModule} from "core-app/modules/context-menu/openproject-context-menu.module";
const menuItemClass = 'board-view-menu-item';
@@ -128,6 +129,7 @@ export function registerBoardsModule(injector:Injector) {
@NgModule({
imports: [
OpenprojectCommonModule,
OpenprojectContextMenuModule,
OpenprojectWorkPackagesModule,
DragScrollModule,
@@ -170,7 +172,7 @@ export function registerBoardsModule(injector:Injector) {
NewBoardModalComponent,
AddListModalComponent,
AddCardDropdownMenuDirective,
BoardListDropdownMenuDirective,
BoardListMenuComponent,
BoardFilterComponent,
VersionBoardHeaderComponent,
],
@@ -0,0 +1,3 @@
<a href="#">
<op-icon icon-classes="icon-show-more-horizontal"></op-icon>
</a>
@@ -0,0 +1,5 @@
@import 'helpers'
a
@include without-link-styling
color: var(--light-gray)
@@ -26,7 +26,7 @@
// See doc/COPYRIGHT.rdoc for more details.
//++
import {ChangeDetectorRef, Directive, ElementRef, Injector} from '@angular/core';
import {ChangeDetectorRef, Component, ElementRef, Injector, Input} from '@angular/core';
import {I18nService} from 'core-app/modules/common/i18n/i18n.service';
import {AuthorisationService} from 'core-app/modules/common/model-auth/model-auth.service';
import {OpContextMenuTrigger} from 'core-components/op-context-menu/handlers/op-context-menu-trigger.directive';
@@ -38,27 +38,24 @@ import {Board} from "core-app/modules/boards/board/board";
import {BoardActionsRegistryService} from "core-app/modules/boards/board/board-actions/board-actions-registry.service";
import {OpContextMenuItem} from "core-components/op-context-menu/op-context-menu.types";
@Directive({
selector: '[boardListDropdown]'
@Component({
selector: 'icon-triggered-context-menu',
templateUrl: './icon-triggered-context-menu.component.html',
styleUrls: ['./icon-triggered-context-menu.component.sass']
})
export class BoardListDropdownMenuDirective extends OpContextMenuTrigger {
private board:Board;
export class IconTriggeredContextMenuComponent extends OpContextMenuTrigger {
constructor(readonly elementRef:ElementRef,
readonly opContextMenu:OPContextMenuService,
readonly opModalService:OpModalService,
readonly authorisationService:AuthorisationService,
readonly boardList:BoardListComponent,
readonly injector:Injector,
readonly querySpace:IsolatedQuerySpace,
readonly cdRef:ChangeDetectorRef,
readonly I18n:I18nService,
readonly boardActions:BoardActionsRegistryService) {
readonly I18n:I18nService) {
super(elementRef, opContextMenu);
this.board = this.boardList.board;
}
@Input('menu-items') menuItems:Function;
protected async open(evt:JQueryEventObject) {
this.items = await this.buildItems();
this.opContextMenu.show(this, evt);
@@ -82,23 +79,11 @@ export class BoardListDropdownMenuDirective extends OpContextMenuTrigger {
}
private async buildItems() {
let items:OpContextMenuItem[] = [
{
disabled: !this.boardList.canDelete,
linkText: this.I18n.t('js.boards.lists.delete'),
onClick: () => {
this.boardList.deleteList();
return true;
}
}
];
let items:OpContextMenuItem[] = [];
// Add action specific menu entries
if (this.board.isAction) {
const actionService = this.boardActions.get(this.board.actionAttribute!);
const query = this.querySpace.query.value!;
const additional = await actionService.getAdditionalListMenuItems(query);
if (this.menuItems) {
const additional = await this.menuItems();
return items.concat(additional);
}
@@ -0,0 +1,52 @@
// -- copyright
// OpenProject is a project management system.
// Copyright (C) 2012-2018 the OpenProject Foundation (OPF)
//
// 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 doc/COPYRIGHT.rdoc for more details.
// ++
import {NgModule} from "@angular/core";
import {CommonModule} from "@angular/common";
import {IconTriggeredContextMenuComponent} from "core-app/modules/context-menu/icon-triggered-context-menu.component";
import {OpenprojectCommonModule} from "core-app/modules/common/openproject-common.module";
@NgModule({
imports: [
// Angular browser + common module
CommonModule,
OpenprojectCommonModule,
],
exports: [
IconTriggeredContextMenuComponent
],
declarations: [
IconTriggeredContextMenuComponent
],
entryComponents: [
],
providers: [ ]
})
export class OpenprojectContextMenuModule { }
@@ -1,20 +1,24 @@
<h3 class="widget-box--header"
*ngIf="(query$ | async) as query"
cdkDragHandle>
<span class="grid--area-drag-handle
icon
icon-drag-handle"
cdkDragHandle></span>
<i class="icon-context icon-view-timeline" aria-hidden="true"></i>
<editable-toolbar-title [title]="query.name"
[inFlight]="inFlight"
(onSave)="renameQuery(query, $event)"
[editable]="!!query.updateImmediately"
class="widget-box--header-title">
</editable-toolbar-title>
</h3>
<ng-container wp-isolated-query-space>
<h3 class="widget-box--header"
*ngIf="(query$ | async) as query"
cdkDragHandle>
<span class="grid--area-drag-handle
icon
icon-drag-handle"
cdkDragHandle></span>
<i class="icon-context icon-view-timeline" aria-hidden="true"></i>
<editable-toolbar-title [title]="query.name"
[inFlight]="inFlight"
(onSave)="renameQuery(query, $event)"
[editable]="!!query.updateImmediately"
class="widget-box--header-title">
</editable-toolbar-title>
<wp-table-config-menu>
</wp-table-config-menu>
</h3>
<wp-embedded-table [queryId]="queryId"
[configuration]="configuration"
[externalHeight]="true"
@@ -1,4 +1,4 @@
import {AfterViewInit, Component, OnDestroy, OnInit, ViewChild} from "@angular/core";
import {Component, OnInit, OnDestroy, ViewChild, AfterViewInit, Injector} from "@angular/core";
import {WidgetWpListComponent} from "core-app/modules/grids/widgets/wp-widget/wp-widget.component";
import {WorkPackageTableConfiguration} from "core-components/wp-table/wp-table-configuration";
import {QueryResource} from "core-app/modules/hal/resources/query-resource";
@@ -25,7 +25,7 @@ export class WidgetWpTableComponent extends WidgetWpListComponent implements OnI
public configuration:Partial<WorkPackageTableConfiguration> = {
actionsColumnEnabled: false,
columnMenuEnabled: true,
columnMenuEnabled: false,
hierarchyToggleEnabled: true,
contextMenuEnabled: false
};
@@ -156,6 +156,7 @@ import {WorkPackageDmService} from "core-app/modules/hal/dm-services/work-packag
import {WorkPackageRelationsService} from "core-components/wp-relations/wp-relations.service";
import {OpenprojectBcfModule} from "core-app/modules/bcf/openproject-bcf.module";
import {WorkPackageRelationsAutocomplete} from "core-components/wp-relations/wp-relations-create/wp-relations-autocomplete/wp-relations-autocomplete.component";
import {WorkPackagesTableConfigMenu} from "core-components/wp-table/config-menu/config-menu.component";
@NgModule({
imports: [
@@ -238,6 +239,7 @@ import {WorkPackageRelationsAutocomplete} from "core-components/wp-relations/wp-
WpRelationInlineAddExistingComponent,
WorkPackagesTableController,
WorkPackagesTableConfigMenu,
WorkPackageTablePaginationComponent,
WpResizerDirective,
@@ -445,6 +447,7 @@ import {WorkPackageRelationsAutocomplete} from "core-components/wp-relations/wp-
WorkPackageFilterButtonComponent,
WorkPackageFilterContainerComponent,
WorkPackageIsolatedQuerySpaceDirective,
WorkPackagesTableConfigMenu,
]
})
export class OpenprojectWorkPackagesModule {
-1
View File
@@ -33,7 +33,6 @@
module API
module Helpers
module AttachmentRenderer
##
# Render an attachment, either by redirecting
# to the external storage,