https://community.openproject.com/wp/27607pull/6809/head
parent
1728da9d1f
commit
039cb26b6e
@ -0,0 +1,95 @@ |
||||
// -- 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, Input, EventEmitter, Output} from '@angular/core'; |
||||
import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-resource'; |
||||
import {WorkPackageRelationsHierarchyService} from 'core-app/components/wp-relations/wp-relations-hierarchy/wp-relations-hierarchy.service'; |
||||
import {WorkPackageNotificationService} from 'core-app/components/wp-edit/wp-notification.service'; |
||||
import {I18nService} from 'core-app/modules/common/i18n/i18n.service'; |
||||
|
||||
@Component({ |
||||
templateUrl: './wp-breadcrumb-parent.html', |
||||
selector: 'wp-breadcrumb-parent', |
||||
}) |
||||
export class WorkPackageBreadcrumbParentComponent { |
||||
@Input('workPackage') workPackage:WorkPackageResource; |
||||
@Output('onSwitch') onSwitch = new EventEmitter<boolean>(); |
||||
|
||||
public isSaving = false; |
||||
public text = { |
||||
edit_parent: this.I18n.t('js.relation_buttons.change_parent'), |
||||
set_or_remove_parent: this.I18n.t('js.relations_autocomplete.parent_placeholder'), |
||||
set_parent: this.I18n.t('js.relation_buttons.set_parent'), |
||||
}; |
||||
|
||||
private editing:boolean; |
||||
|
||||
public constructor( |
||||
protected readonly I18n:I18nService, |
||||
protected readonly wpRelationsHierarchy:WorkPackageRelationsHierarchyService, |
||||
protected readonly wpNotifications:WorkPackageNotificationService |
||||
) { |
||||
} |
||||
|
||||
public canModifyParent():boolean { |
||||
return !!this.workPackage.changeParent; |
||||
} |
||||
|
||||
public get parent() { |
||||
return this.workPackage && this.workPackage.parent; |
||||
} |
||||
|
||||
public get active():boolean { |
||||
return this.editing; |
||||
} |
||||
|
||||
public toggle():void { |
||||
this.editing = !this.editing; |
||||
this.onSwitch.emit(this.editing); |
||||
} |
||||
|
||||
public updateParent(newParentId:string|null) { |
||||
this.toggle(); |
||||
if (_.isNil(newParentId)) { |
||||
newParentId = null; |
||||
} |
||||
|
||||
if (_.get(this.parent, 'id', null) === newParentId) { |
||||
return; |
||||
} |
||||
|
||||
this.isSaving = true; |
||||
this.wpRelationsHierarchy.changeParent(this.workPackage, newParentId) |
||||
.catch((error:any) => { |
||||
this.wpNotifications.handleRawError(error, this.workPackage); |
||||
}) |
||||
.then(() => this.isSaving = false); // Behaves as .finally()
|
||||
} |
||||
} |
||||
|
||||
|
@ -0,0 +1,25 @@ |
||||
<ng-container *ngIf="!active"> |
||||
<a *ngIf="parent" |
||||
[attr.title]="parent.name" |
||||
uiSref="work-packages.show.activity" |
||||
[uiParams]="{workPackageId: parent.id}" |
||||
class="wp-breadcrumb-parent breadcrumb-project-title nocut"> |
||||
<span [textContent]="parent.name"></span> |
||||
</a> |
||||
<accessible-by-keyboard |
||||
(execute)="toggle()" |
||||
*ngIf="canModifyParent()" |
||||
[linkTitle]="parent ? text.edit_parent : text.set_parent" |
||||
linkClass="wp-relation--parent-change"> |
||||
<op-icon icon-classes="icon-small {{ parent ? 'icon-edit icon2' : 'icon-add icon4' }}"></op-icon> |
||||
<span *ngIf="!parent" [textContent]="text.set_parent"></span> |
||||
</accessible-by-keyboard> |
||||
</ng-container> |
||||
<wp-relations-autocomplete-upgraded |
||||
*ngIf="active" |
||||
[inputPlaceholder]="text.set_or_remove_parent" |
||||
[workPackage]="workPackage" |
||||
(onEscape)="this.toggle()" |
||||
(onWorkPackageIdSelected)="updateParent($event)" |
||||
filterCandidatesFor="parent"> |
||||
</wp-relations-autocomplete-upgraded> |
@ -1,15 +1,22 @@ |
||||
<div class="wp-breadcrumb -show" |
||||
*ngIf="workPackage && workPackage.ancestors.length > 0"> |
||||
*ngIf="workPackage"> |
||||
<ul class="breadcrumb"> |
||||
<li *ngFor="let ancestor of workPackage.ancestors" |
||||
class="icon4 icon-small icon-arrow-right5"> |
||||
<a [attr.title]="ancestor.name" |
||||
[textContent]="ancestor.name" |
||||
uiSref="work-packages.show.activity" |
||||
[uiParams]="{workPackageId: ancestor.id}" |
||||
class="breadcrumb-project-title nocut"></a> |
||||
<ng-container *ngIf="!inputActive && hierarchyCount > 0"> |
||||
<li> |
||||
<span>{{ hierarchyLabel }}: </span> |
||||
</li> |
||||
<li *ngFor="let ancestor of workPackage.ancestors; let first = first ; let last = last" |
||||
[ngClass]="{ 'icon4 icon-small icon-arrow-right5': !first }"> |
||||
<a *ngIf="!last" |
||||
[attr.title]="ancestor.name" |
||||
[textContent]="ancestor.name" |
||||
uiSref="work-packages.show.activity" |
||||
[uiParams]="{workPackageId: ancestor.id}" |
||||
class="breadcrumb-project-title nocut"></a> |
||||
</li> |
||||
</ng-container> |
||||
<li [ngClass]="{ 'active-parent-select': inputActive }"> |
||||
<wp-breadcrumb-parent (onSwitch)="inputActive = !inputActive" [workPackage]="workPackage"></wp-breadcrumb-parent> |
||||
</li> |
||||
<li class="icon4 icon-small icon-arrow-right5" |
||||
[textContent]="workPackage.name"></li> |
||||
</ul> |
||||
</div> |
||||
|
@ -0,0 +1,2 @@ |
||||
.active-parent-select |
||||
width: 100% |
@ -1,93 +0,0 @@ |
||||
import {Component, ElementRef, Inject, Input, OnDestroy, OnInit} from '@angular/core'; |
||||
import {I18nService} from 'core-app/modules/common/i18n/i18n.service'; |
||||
import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-resource'; |
||||
import {PathHelperService} from 'core-app/modules/common/path-helper/path-helper.service'; |
||||
import {componentDestroyed} from 'ng2-rx-componentdestroyed'; |
||||
import {takeUntil} from 'rxjs/operators'; |
||||
import {WorkPackageCacheService} from '../../work-packages/work-package-cache.service'; |
||||
import {WorkPackageNotificationService} from '../../wp-edit/wp-notification.service'; |
||||
import {WorkPackageRelationsHierarchyService} from '../wp-relations-hierarchy/wp-relations-hierarchy.service'; |
||||
|
||||
@Component({ |
||||
selector: 'wp-relation-parent', |
||||
templateUrl: './wp-relations-parent.html' |
||||
}) |
||||
export class WpRelationParentComponent implements OnInit, OnDestroy { |
||||
@Input() public workPackage:WorkPackageResource; |
||||
public showEditForm:boolean = false; |
||||
public canModifyHierarchy:boolean = false; |
||||
public selectedWpId:string | null = null; |
||||
public isSaving = false; |
||||
|
||||
constructor(readonly elementRef:ElementRef, |
||||
readonly wpRelationsHierarchyService:WorkPackageRelationsHierarchyService, |
||||
readonly wpCacheService:WorkPackageCacheService, |
||||
readonly wpNotificationsService:WorkPackageNotificationService, |
||||
readonly PathHelper:PathHelperService, |
||||
readonly I18n:I18nService) { |
||||
} |
||||
|
||||
public text = { |
||||
add_parent: this.I18n.t('js.relation_buttons.add_parent'), |
||||
change_parent: this.I18n.t('js.relation_buttons.change_parent'), |
||||
remove_parent: this.I18n.t('js.relation_buttons.remove_parent'), |
||||
remove: this.I18n.t('js.relation_buttons.remove'), |
||||
parent: this.I18n.t('js.relation_labels.parent'), |
||||
abort: this.I18n.t('js.relation_buttons.abort'), |
||||
save: this.I18n.t('js.relation_buttons.save'), |
||||
}; |
||||
|
||||
ngOnDestroy() { |
||||
// Nothing to do
|
||||
} |
||||
|
||||
ngOnInit() { |
||||
this.canModifyHierarchy = !!this.workPackage.changeParent; |
||||
|
||||
this.wpCacheService.state(this.workPackage.id) |
||||
.values$() |
||||
.pipe( |
||||
takeUntil(componentDestroyed(this)) |
||||
) |
||||
.subscribe(wp => this.workPackage = wp); |
||||
} |
||||
|
||||
public updateSelectedId(workPackageId:string) { |
||||
this.selectedWpId = workPackageId; |
||||
} |
||||
|
||||
public changeParent() { |
||||
if (_.isNil(this.selectedWpId)) { |
||||
return; |
||||
} |
||||
|
||||
const newParentId = this.selectedWpId; |
||||
this.showEditForm = false; |
||||
this.selectedWpId = null; |
||||
this.isSaving = true; |
||||
|
||||
this.wpRelationsHierarchyService.changeParent(this.workPackage, newParentId) |
||||
.then((updatedWp:WorkPackageResource) => { |
||||
setTimeout(() => jQuery('#hierarchy--parent').focus()); |
||||
}) |
||||
.catch((err:any) => { |
||||
this.wpNotificationsService.handleRawError(err, this.workPackage); |
||||
}) |
||||
.then(() => this.isSaving = false); // Behaves as .finally()
|
||||
} |
||||
|
||||
public get relationReady() { |
||||
return this.workPackage.parent && this.workPackage.parent.$loaded; |
||||
} |
||||
|
||||
public removeParent() { |
||||
this.wpRelationsHierarchyService |
||||
.removeParent(this.workPackage) |
||||
.then(() => { |
||||
this.wpNotificationsService.showSave(this.workPackage); |
||||
setTimeout(() => { |
||||
jQuery('#hierarchy--add-parent').focus(); |
||||
}); |
||||
}); |
||||
} |
||||
} |
@ -1,87 +0,0 @@ |
||||
<div class="relation-row relation-row--parent" |
||||
focus-within> |
||||
<div class="grid-block v-align hierarchy-item" |
||||
*ngIf="!showEditForm && relationReady"> |
||||
<div class="grid-content medium-7 collapse" wp-single-relation> |
||||
<span ng-style="{'padding-left': indentBy + 'px'}" |
||||
class="wp-relations-hierarchy-subject"> |
||||
<a uiSref="work-packages.show.relations" |
||||
[uiParams]="{ workPackageId: workPackage.parent.id }" |
||||
class="wp-relations--subject-field" |
||||
id="wp-relations-parent-element" |
||||
[attr.aria-label]="text.parent" |
||||
[textContent]="workPackage.parent.subjectWithType()"> |
||||
</a> |
||||
</span> |
||||
</div> |
||||
<div class="grid-content medium-3 collapse wp-relations-status-field"> |
||||
<wp-edit-field-group [workPackage]="workPackage.parent"> |
||||
<div *ngIf="relationReady"> |
||||
<wp-edit-field [workPackageId]="workPackage.parent.id" |
||||
fieldName="status"> |
||||
</wp-edit-field> |
||||
</div> |
||||
</wp-edit-field-group> |
||||
</div> |
||||
<div class="grid-content medium-2 collapse wp-relations-controls-section focus-within--depending"> |
||||
<accessible-by-keyboard *ngIf="canModifyHierarchy" |
||||
(execute)="showEditForm = true" |
||||
linkClass="wp-relation--edit"> |
||||
<op-icon icon-classes="icon-edit -padded" [icon-title]="text.change_parent"></op-icon> |
||||
</accessible-by-keyboard> |
||||
|
||||
<accessible-by-keyboard *ngIf="canModifyHierarchy" |
||||
(execute)="removeParent()" |
||||
linkClass="wp-relation--remove"> |
||||
<op-icon icon-classes="icon-remove -padded" |
||||
[icon-title]="text.remove_parent"></op-icon> |
||||
</accessible-by-keyboard> |
||||
</div> |
||||
</div> |
||||
|
||||
<div *ngIf="canModifyHierarchy && (!workPackage.parent || showEditForm)" class="hide-when-print"> |
||||
<div class="wp-relations-create-button -full-width" |
||||
*ngIf="!showEditForm"> |
||||
<div class="grid-block"> |
||||
<div class="grid-content collapse hide-when-print wp-inline-create-button"> |
||||
<a class="wp-inline-create--add-link relation-create" |
||||
(click)="showEditForm = true" |
||||
role="button" |
||||
id="hierarchy--add-parent"> |
||||
<op-icon icon-classes="icon icon-add"></op-icon> |
||||
<span [textContent]="text.add_parent"></span> |
||||
</a> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div class="loading-indicator--location" |
||||
*ngIf="showEditForm" |
||||
data-indicator-name="relationAddParent"> |
||||
<div class="v-align wp-relations-create--form wp-relations--parent-form"> |
||||
<div class="grid-content medium-10"> |
||||
<wp-relations-autocomplete-upgraded |
||||
[workPackage]="workPackage" |
||||
(onWorkPackageIdSelected)="updateSelectedId($event)" |
||||
loadingPromiseName="relationAddParent" |
||||
filterCandidatesFor="parent"> |
||||
</wp-relations-autocomplete-upgraded> |
||||
</div> |
||||
<div class="grid-content medium-2 collapse wp-relations-controls-section relation-row"> |
||||
<accessible-by-keyboard |
||||
linkClass="wp-create-relation--save" |
||||
[isDisabled]="!selectedWpId || isSaving" |
||||
(execute)="changeParent()" |
||||
aria-hidden="false"> |
||||
<op-icon icon-classes="icon-checkmark -padded" [icon-title]="text.save"></op-icon> |
||||
</accessible-by-keyboard> |
||||
<accessible-by-keyboard |
||||
linkClass="wp-create-relation--cancel" |
||||
(execute)="showEditForm = false" |
||||
aria-hidden="false"> |
||||
<op-icon icon-classes="icon-remove -padded" [icon-title]="text.abort"></op-icon> |
||||
</accessible-by-keyboard> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
Loading…
Reference in new issue