extract common functionality into create service

pull/6973/head
Jens Ulferts 6 years ago
parent d5d70bfb1a
commit 84e54b7417
No known key found for this signature in database
GPG Key ID: 3CAA4B1182CF5308
  1. 11
      frontend/src/app/components/wp-copy/wp-copy.controller.ts
  2. 2
      frontend/src/app/components/wp-edit-form/work-package-filter-values.ts
  3. 50
      frontend/src/app/components/wp-inline-create/wp-inline-create.component.ts
  4. 49
      frontend/src/app/components/wp-new/wp-create.controller.ts
  5. 97
      frontend/src/app/components/wp-new/wp-create.service.ts
  6. 3
      frontend/src/app/components/wp-table/embedded/wp-embedded-table.component.ts
  7. 3
      spec/features/work_packages/new/new_work_package_spec.rb
  8. 1
      spec/support/components/work_packages/relations.rb

@ -32,12 +32,15 @@ import {WorkPackageChangeset} from 'core-components/wp-edit-form/work-package-ch
import {WorkPackageCreateController} from 'core-components/wp-new/wp-create.controller';
import {WorkPackageRelationsService} from "core-components/wp-relations/wp-relations.service";
import {untilComponentDestroyed} from "ng2-rx-componentdestroyed";
import {WorkPackageEditingService} from "core-components/wp-edit-form/work-package-editing-service";
import {IWorkPackageEditingServiceToken} from "core-components/wp-edit-form/work-package-editing.service.interface";
export class WorkPackageCopyController extends WorkPackageCreateController {
private __initialized_at:Number;
private copiedWorkPackageId:string;
private wpRelations:WorkPackageRelationsService = this.injector.get(WorkPackageRelationsService);
protected wpEditing:WorkPackageEditingService = this.injector.get<WorkPackageEditingService>(IWorkPackageEditingServiceToken);
ngOnInit() {
super.ngOnInit();
@ -53,8 +56,8 @@ export class WorkPackageCopyController extends WorkPackageCreateController {
});
}
protected newWorkPackageFromParams(stateParams:any) {
this.copiedWorkPackageId = stateParams.copiedFromWorkPackageId;
protected createdWorkPackage() {
this.copiedWorkPackageId = this.stateParams.copiedFromWorkPackageId;
return new Promise<WorkPackageChangeset>((resolve, reject) => {
this.wpCacheService.loadWorkPackage(this.copiedWorkPackageId)
.values$()
@ -80,6 +83,10 @@ export class WorkPackageCopyController extends WorkPackageCreateController {
.copyWorkPackage(form, wp.project.identifier)
.then((changeset) => {
this.__initialized_at = changeset.workPackage.__initialized_at;
this.wpCacheService.updateWorkPackage(changeset.workPackage);
this.wpEditing.updateValue('new', changeset);
return changeset;
})
);

@ -32,7 +32,7 @@ export class WorkPackageFilterValues {
}
// Select the first value
var value = filter.values[0];
let value = filter.values[0];
// Avoid empty values
if (value) {

@ -41,12 +41,8 @@ import {AuthorisationService} from 'core-app/modules/common/model-auth/model-aut
import {WorkPackageTableFocusService} from 'core-components/wp-fast-table/state/wp-table-focus.service';
import {filter} from 'rxjs/operators';
import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-resource';
import {WorkPackageCacheService} from '../work-packages/work-package-cache.service';
import {TableRowEditContext} from '../wp-edit-form/table-row-edit-context';
import {WorkPackageChangeset} from '../wp-edit-form/work-package-changeset';
import {WorkPackageEditForm} from '../wp-edit-form/work-package-edit-form';
import {WorkPackageEditingService} from '../wp-edit-form/work-package-editing-service';
import {WorkPackageFilterValues} from '../wp-edit-form/work-package-filter-values';
import {TimelineRowBuilder} from '../wp-fast-table/builders/timeline/timeline-row-builder';
import {onClickOrEnter} from '../wp-fast-table/handlers/click-or-enter-handler';
import {WorkPackageTableColumnsService} from '../wp-fast-table/state/wp-table-columns.service';
@ -61,7 +57,6 @@ import {TableState} from 'core-components/wp-table/table-state/table-state';
import {untilComponentDestroyed} from 'ng2-rx-componentdestroyed';
import {I18nService} from 'core-app/modules/common/i18n/i18n.service';
import {FocusHelperService} from 'core-app/modules/common/focus/focus-helper';
import {IWorkPackageEditingServiceToken} from "../wp-edit-form/work-package-editing.service.interface";
import {IWorkPackageCreateServiceToken} from "core-components/wp-new/wp-create.service.interface";
import {CurrentUserService} from "core-components/user/current-user.service";
import {WorkPackageInlineCreateService} from "core-components/wp-inline-create/wp-inline-create.service";
@ -92,7 +87,7 @@ export class WorkPackageInlineCreateComponent implements OnInit, OnChanges, OnDe
private rowBuilder:InlineCreateRowBuilder;
private timelineBuilder:TimelineRowBuilder;
private editingSubscription:Subscription;
private editingSubscription:Subscription|undefined;
private $element:JQuery;
@ -101,9 +96,7 @@ export class WorkPackageInlineCreateComponent implements OnInit, OnChanges, OnDe
protected readonly FocusHelper:FocusHelperService,
protected readonly I18n:I18nService,
protected readonly tableState:TableState,
protected readonly wpCacheService:WorkPackageCacheService,
protected readonly currentUser:CurrentUserService,
@Inject(IWorkPackageEditingServiceToken) protected readonly wpEditing:WorkPackageEditingService,
@Inject(IWorkPackageCreateServiceToken) protected readonly wpCreate:WorkPackageCreateService,
protected readonly wpInlineCreate:WorkPackageInlineCreateService,
protected readonly wpTableColumns:WorkPackageTableColumnsService,
@ -196,7 +189,7 @@ export class WorkPackageInlineCreateComponent implements OnInit, OnChanges, OnDe
this.wpInlineCreate.newInlineWorkPackageCreated.next(wp.id);
} else {
// Remove current row
this.table.editing.stopEditing('new');
this.wpCreate.cancelCreation();
this.removeWorkPackageRow();
this.showRow();
}
@ -223,22 +216,16 @@ export class WorkPackageInlineCreateComponent implements OnInit, OnChanges, OnDe
public addWorkPackageRow() {
this.wpCreate
.createNewWorkPackage(this.projectIdentifier)
.createOrContinueWorkPackage(this.projectIdentifier)
.then((changeset:WorkPackageChangeset) => {
if (!changeset) {
throw 'No new work package was created';
}
const wp = this.currentWorkPackage = changeset.workPackage;
this.applyDefaults(changeset, wp);
this.editingSubscription = this
.wpEditing
.state(wp.id)
.values$()
.wpCreate
.changesetUpdates$()
.pipe(
filter((cs) => !!this.currentWorkPackage && !!cs.form),
//untilComponentDestroyed(this)
).subscribe((form) => {
if (!this.isActive) {
this.insertRow(wp);
@ -250,25 +237,6 @@ export class WorkPackageInlineCreateComponent implements OnInit, OnChanges, OnDe
});
}
// TODO: Move into Service?
/**
* Apply values to the work package from the current set of filters
*
* @param changeset
* @param wp
*/
private applyDefaults(changeset:WorkPackageChangeset, wp:WorkPackageResource) {
if (this.tableState.query.hasValue()) {
const filter = new WorkPackageFilterValues(this.injector, changeset, this.tableState.query.value!.filters);
filter.applyDefaultsFromFilters();
}
// Update the changeset with any added filtered values
this.wpEditing.updateValue('new', changeset);
this.wpCacheService.updateWorkPackage(this.currentWorkPackage!);
}
private insertRow(wp:WorkPackageResource) {
// Actually render the row
const form = this.workPackageEditForm = this.renderInlineCreateRow(wp);
@ -320,11 +288,12 @@ export class WorkPackageInlineCreateComponent implements OnInit, OnChanges, OnDe
}
public removeWorkPackageRow() {
this.wpCreate.cancelCreation();
this.currentWorkPackage = null;
this.table.editing.stopEditing('new');
this.wpCacheService.clearSome('new');
this.$element.find('.wp-row-new').remove();
this.editingSubscription.unsubscribe();
if (this.editingSubscription) {
this.editingSubscription.unsubscribe();
}
}
public showRow() {
@ -346,5 +315,4 @@ export class WorkPackageInlineCreateComponent implements OnInit, OnChanges, OnDe
public get canAdd():boolean {
return this.wpInlineCreate.canAdd;
}
}

@ -35,8 +35,6 @@ import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-r
import {RootResource} from 'core-app/modules/hal/resources/root-resource';
import {WorkPackageCacheService} from '../work-packages/work-package-cache.service';
import {WorkPackageChangeset} from '../wp-edit-form/work-package-changeset';
import {WorkPackageEditingService} from '../wp-edit-form/work-package-editing-service';
import {WorkPackageFilterValues} from '../wp-edit-form/work-package-filter-values';
import {WorkPackageNotificationService} from '../wp-edit/wp-notification.service';
import {WorkPackageTableFiltersService} from '../wp-fast-table/state/wp-table-filters.service';
import {WorkPackageCreateService} from './wp-create.service';
@ -44,9 +42,6 @@ import {takeUntil} from 'rxjs/operators';
import {RootDmService} from 'core-app/modules/hal/dm-services/root-dm.service';
import {OpTitleService} from 'core-components/html/op-title.service';
import {I18nService} from "core-app/modules/common/i18n/i18n.service";
import {
IWorkPackageEditingServiceToken
} from "../wp-edit-form/work-package-editing.service.interface";
import {IWorkPackageCreateServiceToken} from "core-components/wp-new/wp-create.service.interface";
import {CurrentUserService} from "core-app/components/user/current-user.service";
@ -57,7 +52,6 @@ export class WorkPackageCreateController implements OnInit, OnDestroy {
public newWorkPackage:WorkPackageResource;
public parentWorkPackage:WorkPackageResource;
public changeset:WorkPackageChangeset;
protected wpEditing:WorkPackageEditingService = this.injector.get<WorkPackageEditingService>(IWorkPackageEditingServiceToken);
public stateParams = this.$transition.params('to');
public text = {
@ -81,16 +75,14 @@ export class WorkPackageCreateController implements OnInit, OnDestroy {
}
public ngOnInit() {
this.newWorkPackageFromParams(this.stateParams)
this
.createdWorkPackage()
.then((changeset:WorkPackageChangeset) => {
this.changeset = changeset;
this.newWorkPackage = changeset.workPackage;
this.setTitle();
this.wpCacheService.updateWorkPackage(this.newWorkPackage);
this.wpEditing.updateValue('new', changeset);
if (this.stateParams['parent_id']) {
this.changeset.setValue(
'parent',
@ -137,36 +129,15 @@ export class WorkPackageCreateController implements OnInit, OnDestroy {
this.titleService.setFirstPart(this.I18n.t('js.work_packages.create.title'));
}
// TODO: move to service
protected newWorkPackageFromParams(stateParams:any):Promise<WorkPackageChangeset> {
const type = parseInt(stateParams.type);
// If there is an open edit for this type, continue it
const changeset = this.wpEditing.state('new').value;
if (changeset !== undefined) {
const changeType = changeset.workPackage.type;
const hasChanges = !changeset.empty;
const typeEmpty = (!changeType && !type);
const typeMatches = (changeType && changeType.idFromLink === type.toString());
if (hasChanges && (typeEmpty || typeMatches)) {
return Promise.resolve(changeset);
}
}
return this.wpCreate.createNewTypedWorkPackage(stateParams.projectPath, type).then(changeset => {
const filter = new WorkPackageFilterValues(this.injector, changeset, this.wpTableFilters.current, ['type']);
filter.applyDefaultsFromFilters();
return changeset;
});
}
public cancelAndBackToList() {
this.wpEditing.stopEditing(this.newWorkPackage.id);
this.wpCreate.cancelCreation();
this.$state.go('work-packages.list', this.$state.params);
}
protected createdWorkPackage() {
const type = this.stateParams.type ? parseInt(this.stateParams.type) : undefined;
const project = this.stateParams.projectPath;
return this.wpCreate.createOrContinueWorkPackage(project, type);
}
}

@ -26,7 +26,7 @@
// See doc/COPYRIGHT.rdoc for more details.
// ++
import {Injectable, Injector} from '@angular/core';
import {Injectable, Injector, Inject} from '@angular/core';
import {ApiWorkPackagesService} from '../api/api-work-packages/api-work-packages.service';
import {HalResource} from 'core-app/modules/hal/resources/hal-resource';
import {WorkPackageCacheService} from '../work-packages/work-package-cache.service';
@ -36,6 +36,11 @@ import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-r
import {HalResourceService} from 'core-app/modules/hal/services/hal-resource.service';
import {IWorkPackageCreateService} from "core-components/wp-new/wp-create.service.interface";
import {HookService} from 'core-app/modules/plugins/hook-service';
import {WorkPackageFilterValues} from "core-components/wp-edit-form/work-package-filter-values";
import {IWorkPackageEditingServiceToken} from "core-components/wp-edit-form/work-package-editing.service.interface";
import {WorkPackageEditingService} from "core-components/wp-edit-form/work-package-editing-service";
import {WorkPackageTableFiltersService} from "core-components/wp-fast-table/state/wp-table-filters.service";
import {TableState} from "core-components/wp-table/table-state/table-state";
@Injectable()
export class WorkPackageCreateService implements IWorkPackageCreateService {
@ -48,6 +53,8 @@ export class WorkPackageCreateService implements IWorkPackageCreateService {
protected hooks:HookService,
protected wpCacheService:WorkPackageCacheService,
protected halResourceService:HalResourceService,
@Inject(IWorkPackageEditingServiceToken) protected readonly wpEditing:WorkPackageEditingService,
protected readonly tableState:TableState,
protected apiWorkPackages:ApiWorkPackagesService) {
}
@ -115,4 +122,92 @@ export class WorkPackageCreateService implements IWorkPackageCreateService {
return this.form;
}
public cancelCreation() {
this.wpEditing.stopEditing('new');
this.wpCacheService.clearSome('new');
}
public changesetUpdates$() {
return this
.wpEditing
.state('new')
.values$();
}
public createOrContinueWorkPackage(projectIdentifier:string, type?:number) {
let changesetPromise = this.continueExistingEdit(type);
if (!changesetPromise) {
changesetPromise = this.createNewWithDefaults(projectIdentifier, type);
}
return changesetPromise.then((changeset) => {
this.wpEditing.updateValue('new', changeset);
this.wpCacheService.updateWorkPackage(changeset.workPackage);
return changeset;
});
}
protected continueExistingEdit(type?:number) {
const changeset = this.wpEditing.state('new').value;
if (changeset !== undefined) {
const changeType = changeset.workPackage.type;
const hasChanges = !changeset.empty;
const typeEmpty = !changeType && !type;
const typeMatches = type && changeType && changeType.idFromLink === type.toString();
if (hasChanges && (typeEmpty || typeMatches)) {
return Promise.resolve(changeset);
}
}
return null;
}
protected createNewWithDefaults(projectIdentifier:string, type?:number) {
let changesetPromise = null;
if (type) {
changesetPromise = this.createNewTypedWorkPackage(projectIdentifier, type);
} else {
changesetPromise = this.createNewWorkPackage(projectIdentifier);
}
return changesetPromise.then((changeset:WorkPackageChangeset) => {
if (!changeset) {
throw 'No new work package was created';
}
let except:string[] = [];
if (type) {
except = ['type'];
}
this.applyDefaults(changeset, changeset.workPackage, except);
return changeset;
});
}
/**
* Apply values to the work package from the current set of filters
*
* @param changeset
* @param wp
* @param except
*/
private applyDefaults(changeset:WorkPackageChangeset, wp:WorkPackageResource, except:string[]) {
// Not using WorkPackageTableFiltersService here as the embedded table does not load the form
// which will result in that service having empty current filters.
let query = this.tableState.query.value;
if (query) {
const filter = new WorkPackageFilterValues(this.injector, changeset, query.filters, except);
filter.applyDefaultsFromFilters();
}
}
}

@ -29,6 +29,8 @@ import {OpModalService} from 'core-components/op-modals/op-modal.service';
import {I18nService} from "core-app/modules/common/i18n/i18n.service";
import {WorkPackageEmbeddedBaseComponent} from "core-components/wp-table/embedded/wp-embedded-base.component";
import {WorkPackageTableHighlightingService} from "core-components/wp-fast-table/state/wp-table-highlighting.service";
import {WorkPackageCreateService} from "core-components/wp-new/wp-create.service";
import {IWorkPackageCreateServiceToken} from "core-components/wp-new/wp-create.service.interface";
@Component({
selector: 'wp-embedded-table',
@ -49,6 +51,7 @@ import {WorkPackageTableHighlightingService} from "core-components/wp-fast-table
WorkPackageTableAdditionalElementsService,
WorkPackageTableRefreshService,
WorkPackageTableHighlightingService,
{ provide: IWorkPackageCreateServiceToken, useClass: WorkPackageCreateService },
// Order is important here, to avoid this service
// getting global injections
WorkPackageStatesInitializationService,

@ -306,6 +306,7 @@ describe 'new work package', js: true do
end
it 'can create the work package, but not update it after saving' do
type_field.activate!
type_field.set_value type_bug.name
# wait after the type change
sleep(0.2)
@ -321,7 +322,7 @@ describe 'new work package', js: true do
end
end
context 'a anonymous user is prompted to login' do
context 'an anonymous user is prompted to login' do
let(:user) { FactoryBot.create(:anonymous) }
let(:wp_page) { ::Pages::Page.new }

@ -153,7 +153,6 @@ module Components
expect(page).to have_no_selector '.wp-breadcrumb-parent', wait: 10
end
def remove_parent
# Open the parent edit
find('.wp-relation--parent-change').click

Loading…
Cancel
Save