Refactoring: use observable.pipe(map) instead of observable.map, etc.

pull/6207/head
Roman Roelofsen 7 years ago
parent 6e646577f7
commit 4a7e7175a8
  1. 21
      frontend/app/components/common/focus-within/focus-within.directive.ts
  2. 16
      frontend/app/components/common/focus-within/focus-within.upgraded.directive.ts
  3. 27
      frontend/app/components/common/hide-section/add-section-dropdown/add-section-dropdown.component.ts
  4. 21
      frontend/app/components/common/hide-section/hide-section.component.ts
  5. 0
      frontend/app/components/context-menus/settings-menu/settings-menu.controller.ts
  6. 20
      frontend/app/components/routing/wp-list/wp-list.component.ts
  7. 17
      frontend/app/components/routing/wp-split-view/wp-split-view.component.ts
  8. 30
      frontend/app/components/routing/wp-view-base/wp-view-base.controller.ts
  9. 19
      frontend/app/components/schemas/schema-cache.service.ts
  10. 3
      frontend/app/components/states.service.ts
  11. 16
      frontend/app/components/states/state-cache.service.ts
  12. 25
      frontend/app/components/states/switch-state.ts
  13. 20
      frontend/app/components/work-packages/work-package-cache.service.ts
  14. 12
      frontend/app/components/work-packages/wp-relations-count/wp-relations-count.component.ts
  15. 31
      frontend/app/components/work-packages/wp-single-view/wp-single-view.component.ts
  16. 13
      frontend/app/components/work-packages/wp-subject/wp-subject.component.ts
  17. 17
      frontend/app/components/work-packages/wp-watcher-button/wp-watcher-button.component.ts
  18. 9
      frontend/app/components/wp-copy/wp-copy.controller.ts
  19. 38
      frontend/app/components/wp-edit-form/work-package-editing-service.ts
  20. 46
      frontend/app/components/wp-edit/wp-edit-field/wp-edit-field-group.directive.ts
  21. 7
      frontend/app/components/wp-fast-table/handlers/state/columns-transformer.ts
  22. 9
      frontend/app/components/wp-fast-table/handlers/state/hierarchy-transformer.ts
  23. 11
      frontend/app/components/wp-fast-table/handlers/state/rows-transformer.ts
  24. 9
      frontend/app/components/wp-fast-table/handlers/state/selection-transformer.ts
  25. 10
      frontend/app/components/wp-fast-table/handlers/state/timeline-transformer.ts
  26. 21
      frontend/app/components/wp-fast-table/state/wp-table-base.service.ts
  27. 24
      frontend/app/components/wp-fast-table/state/wp-table-focus.service.ts
  28. 21
      frontend/app/components/wp-fast-table/state/wp-table-sort-by.service.ts
  29. 28
      frontend/app/components/wp-inline-create/wp-inline-create.directive.ts
  30. 31
      frontend/app/components/wp-new/wp-create.controller.ts
  31. 9
      frontend/app/components/wp-new/wp-create.service.ts
  32. 21
      frontend/app/components/wp-query-menu/wp-query-menu.service.ts
  33. 13
      frontend/app/components/wp-relations/wp-relations-hierarchy/wp-relations-hierarchy.directive.ts
  34. 31
      frontend/app/components/wp-relations/wp-relations.directive.ts
  35. 13
      frontend/app/components/wp-single-view-tabs/activity-panel/activity-base.controller.ts
  36. 7
      frontend/app/components/wp-single-view-tabs/keep-tab/keep-tab.service.ts
  37. 12
      frontend/app/components/wp-single-view-tabs/overview-tab/overview-tab.component.ts
  38. 11
      frontend/app/components/wp-single-view-tabs/relations-tab/relations-tab.component.ts
  39. 27
      frontend/app/components/wp-single-view-tabs/watchers-tab/watchers-tab.component.ts
  40. 13
      frontend/app/components/wp-table/sort-header/sort-header.directive.ts
  41. 2
      frontend/app/components/wp-table/table-pagination/wp-table-pagination.component.test.ts
  42. 8
      frontend/app/components/wp-table/table-state/table-state.ts
  43. 45
      frontend/app/components/wp-table/timeline/container/wp-timeline-container.directive.ts
  44. 23
      frontend/app/components/wp-table/timeline/global-elements/wp-timeline-relations.directive.ts
  45. 5
      frontend/app/components/wp-table/wp-table-sums-row/wp-table-sums-row.directive.ts
  46. 61
      frontend/app/helpers/angular-rx-utils.ts
  47. 966
      frontend/npm-shrinkwrap.json
  48. 1
      frontend/package.json
  49. 4
      frontend/webpack-main-config.js

@ -26,9 +26,10 @@
// See doc/COPYRIGHT.rdoc for more details.
//++
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
import {auditTime} from 'rxjs/operators';
import {wpDirectivesModule} from '../../../angular-modules';
import {scopedObservable} from '../../../helpers/angular-rx-utils';
import {BehaviorSubject} from 'rxjs';
// with courtesy of http://stackoverflow.com/a/29722694/3206935
@ -44,22 +45,24 @@ function focusWithinDirective($timeout:ng.ITimeoutService) {
let focusedObservable = new BehaviorSubject(false);
scopedObservable(
scope,
focusedObservable
scope,
focusedObservable
)
.pipe(
auditTime(50)
)
.auditTime(50)
.subscribe(focused => {
element.toggleClass('-focus', focused);
element.toggleClass('-focus', focused);
});
let focusListener = function () {
focusedObservable.next(true);
let focusListener = function() {
focusedObservable.next(true);
};
element[0].addEventListener('focus', focusListener, true);
let blurListener = function () {
focusedObservable.next(false);
let blurListener = function() {
focusedObservable.next(false);
};
element[0].addEventListener('blur', blurListener, true);

@ -26,12 +26,10 @@
// See doc/COPYRIGHT.rdoc for more details.
//++
import {wpDirectivesModule} from '../../../angular-modules';
import {scopedObservable} from '../../../helpers/angular-rx-utils';
import {BehaviorSubject} from 'rxjs';
import {Directive, ElementRef, Input, OnDestroy, OnInit} from '@angular/core';
import {componentDestroyed} from 'ng2-rx-componentdestroyed';
import {downgradeComponent} from '@angular/upgrade/static';
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
import {auditTime, takeUntil} from 'rxjs/operators';
// with courtesy of http://stackoverflow.com/a/29722694/3206935
@ -52,19 +50,21 @@ export class FocusWithinDirective implements OnInit, OnDestroy {
let focusedObservable = new BehaviorSubject(false);
focusedObservable
.auditTime(50)
.takeUntil(componentDestroyed(this))
.pipe(
auditTime(50),
takeUntil(componentDestroyed(this))
)
.subscribe(focused => {
this.$element.toggleClass('-focus', focused);
});
let focusListener = function () {
let focusListener = function() {
focusedObservable.next(true);
};
this.$element[0].addEventListener('focus', focusListener, true);
let blurListener = function () {
let blurListener = function() {
focusedObservable.next(false);
};
this.$element[0].addEventListener('blur', blurListener, true);

@ -26,13 +26,13 @@
// See doc/COPYRIGHT.rdoc for more details.
// ++
import {opUiComponentsModule} from '../../../../angular-modules';
import {Component, Inject, Input, OnDestroy, OnInit} from '@angular/core';
import {downgradeComponent} from '@angular/upgrade/static';
import {HideSectionDefinition, HideSectionService} from 'core-components/common/hide-section/hide-section.service';
import {I18nToken} from 'core-app/angular4-transition-utils';
import {HideSectionDefinition, HideSectionService} from 'core-components/common/hide-section/hide-section.service';
import {combineLatest} from 'rxjs/observable/combineLatest';
import {Subscription} from 'rxjs/Subscription';
import {Observable} from 'rxjs/Observable';
import {opUiComponentsModule} from '../../../../angular-modules';
@Component({
selector: 'add-section-dropdown',
@ -40,7 +40,7 @@ import {Observable} from 'rxjs/Observable';
})
export class AddSectionDropdownComponent implements OnInit, OnDestroy {
selectable:HideSectionDefinition[] = [];
turnedActive:HideSectionDefinition|null = null;
turnedActive:HideSectionDefinition | null = null;
texts:{ [key:string]:string } = {};
@Input()
@ -56,13 +56,12 @@ export class AddSectionDropdownComponent implements OnInit, OnDestroy {
}
ngOnInit() {
this.allSubscription = Observable.combineLatest(this.hideSections.all$,
this.hideSections.displayed$)
.subscribe(([all, displayed]) => {
this.selectable = _.filter(all, all_candidate =>
!_.some(displayed, displayed_candidate => all_candidate.key === displayed_candidate.key)
).sort((a, b) => a.label.toLowerCase().localeCompare(b.label.toLowerCase()));
});
this.allSubscription = combineLatest(this.hideSections.all$, this.hideSections.displayed$)
.subscribe(([all, displayed]) => {
this.selectable = _.filter(all, all_candidate =>
!_.some(displayed, displayed_candidate => all_candidate.key === displayed_candidate.key)
).sort((a, b) => a.label.toLowerCase().localeCompare(b.label.toLowerCase()));
});
}
ngOnDestroy() {
@ -72,12 +71,14 @@ export class AddSectionDropdownComponent implements OnInit, OnDestroy {
show() {
if (this.turnedActive) {
this.hideSections.show(this.turnedActive);
setTimeout(() => { this.turnedActive = null; } );
setTimeout(() => {
this.turnedActive = null;
});
}
}
}
opUiComponentsModule.directive(
'addSectionDropdown',
downgradeComponent({component:AddSectionDropdownComponent})
downgradeComponent({component: AddSectionDropdownComponent})
);

@ -26,12 +26,12 @@
// See doc/COPYRIGHT.rdoc for more details.
// ++
import {opUiComponentsModule} from '../../../angular-modules';
import {Component, ElementRef, OnDestroy} from '@angular/core';
import {OnInit, Input} from '@angular/core';
import {Component, ElementRef, Input, OnDestroy, OnInit} from '@angular/core';
import {downgradeComponent} from '@angular/upgrade/static';
import {HideSectionService} from 'core-components/common/hide-section/hide-section.service';
import {distinctUntilChanged, map, take} from 'rxjs/operators';
import {Subscription} from 'rxjs/Subscription';
import {opUiComponentsModule} from '../../../angular-modules';
@Component({
selector: 'hide-section',
@ -47,20 +47,27 @@ export class HideSectionComponent implements OnInit, OnDestroy {
@Input() onDisplayed:Function;
constructor(protected hideSection:HideSectionService,
private elementRef:ElementRef) { }
private elementRef:ElementRef) {
}
ngOnInit() {
let mappedDisplayed = this.hideSection.displayed$
.map(all_displayed => _.some(all_displayed, candidate => candidate.key === this.sectionName));
.pipe(
map(all_displayed => _.some(all_displayed, candidate => candidate.key === this.sectionName))
);
this.initializationSubscription = mappedDisplayed
.take(1)
.pipe(
take(1)
)
.subscribe(show => {
jQuery(this.elementRef.nativeElement).addClass('-initialized');
});
this.displayedSubscription = mappedDisplayed
.distinctUntilChanged()
.pipe(
distinctUntilChanged()
)
.subscribe(show => {
this.displayed = show;

@ -27,9 +27,13 @@
// ++
import {Component, Inject, OnDestroy, OnInit} from '@angular/core';
import {StateService, StateParams, TransitionService} from '@uirouter/core';
import {downgradeComponent} from '@angular/upgrade/static';
import {StateService, TransitionService} from '@uirouter/core';
import {$stateToken, I18nToken} from 'core-app/angular4-transition-utils';
import {AuthorisationService} from 'core-components/common/model-auth/model-auth.service';
import {TableState} from 'core-components/wp-table/table-state/table-state';
import {untilComponentDestroyed} from 'ng2-rx-componentdestroyed';
import {auditTime, distinctUntilChanged, filter, withLatestFrom} from 'rxjs/operators';
import {auditTime, distinctUntilChanged, filter, take, withLatestFrom} from 'rxjs/operators';
import {debugLog} from '../../../helpers/debug_output';
import {QueryResource} from '../../api/api-v3/hal-resources/query-resource.service';
import {LoadingIndicatorService} from '../../common/loading-indicator/loading-indicator.service';
@ -47,10 +51,6 @@ import {WorkPackagesListChecksumService} from '../../wp-list/wp-list-checksum.se
import {WorkPackagesListService} from '../../wp-list/wp-list.service';
import {WorkPackageTableRefreshService} from '../../wp-table/wp-table-refresh-request.service';
import {WorkPackageTableHierarchiesService} from './../../wp-fast-table/state/wp-table-hierarchy.service';
import {$stateToken, I18nToken} from 'core-app/angular4-transition-utils';
import {AuthorisationService} from 'core-components/common/model-auth/model-auth.service';
import {downgradeComponent} from '@angular/upgrade/static';
import {TableState} from 'core-components/wp-table/table-state/table-state';
@Component({
selector: 'wp-list',
@ -126,7 +126,7 @@ export class WorkPackagesListComponent implements OnInit, OnDestroy {
this.wpTableRefresh.clear('Table controller scope destroyed.');
}
public allowed(model:string, permission:string) {
public allowed(model:string, permission:string) {
return this.authorisationService.can(model, permission);
}
@ -144,8 +144,10 @@ export class WorkPackagesListComponent implements OnInit, OnDestroy {
}
private setupQueryObservers() {
this.states.tableRendering.onQueryUpdated.values$().pipe()
.take(1)
this.states.tableRendering.onQueryUpdated.values$()
.pipe(
take(1)
)
.subscribe(() => this.tableInformationLoaded = true);
// Update the title whenever the query changes

@ -26,16 +26,17 @@
// See doc/COPYRIGHT.rdoc for more details.
// ++
import {Component, Inject, Injector} from '@angular/core';
import {StateService} from '@uirouter/core';
import {$stateToken} from 'core-app/angular4-transition-utils';
import {FirstRouteService} from 'core-components/routing/first-route-service';
import {WorkPackageTableFocusService} from 'core-components/wp-fast-table/state/wp-table-focus.service';
import {componentDestroyed} from 'ng2-rx-componentdestroyed';
import {takeUntil} from 'rxjs/operators';
import {States} from '../../states.service';
import {WorkPackageTableSelection} from '../../wp-fast-table/state/wp-table-selection.service';
import {KeepTabService} from '../../wp-single-view-tabs/keep-tab/keep-tab.service';
import {WorkPackageViewController} from '../wp-view-base/wp-view-base.controller';
import {FirstRouteService} from 'core-components/routing/first-route-service';
import {WorkPackageTableFocusService} from 'core-components/wp-fast-table/state/wp-table-focus.service';
import {StateService} from '@uirouter/core';
import {Component, Inject, Injector} from '@angular/core';
import {componentDestroyed} from 'ng2-rx-componentdestroyed';
import {$stateToken} from 'core-app/angular4-transition-utils';
@Component({
template: require('!!raw-loader!./wp-split-view.html'),
@ -70,7 +71,9 @@ export class WorkPackageSplitViewComponent extends WorkPackageViewController {
}
this.wpTableFocus.whenChanged()
.takeUntil(componentDestroyed(this))
.pipe(
takeUntil(componentDestroyed(this))
)
.subscribe(newId => {
const idSame = wpId.toString() === newId.toString();
if (!idSame && $state.includes('work-packages.list.details')) {

@ -26,22 +26,18 @@
// See doc/COPYRIGHT.rdoc for more details.
//++
import {wpControllersModule} from '../../../angular-modules';
import {scopedObservable} from '../../../helpers/angular-rx-utils';
import {Injector, OnDestroy} from '@angular/core';
import {I18nToken} from 'core-app/angular4-transition-utils';
import {PathHelperService} from 'core-components/common/path-helper/path-helper.service';
import {WorkPackageTableFocusService} from 'core-components/wp-fast-table/state/wp-table-focus.service';
import {componentDestroyed} from 'ng2-rx-componentdestroyed';
import {takeUntil} from 'rxjs/operators';
import {WorkPackageResourceInterface} from '../../api/api-v3/hal-resources/work-package-resource.service';
import {States} from '../../states.service';
import {WorkPackageCacheService} from '../../work-packages/work-package-cache.service';
import {WorkPackageEditingService} from '../../wp-edit-form/work-package-editing-service';
import {KeepTabService} from '../../wp-single-view-tabs/keep-tab/keep-tab.service';
import {WorkPackageTableRefreshService} from '../../wp-table/wp-table-refresh-request.service';
import {$injectFields} from '../../angular/angular-injector-bridge.functions';
import {WorkPackageEditingService} from '../../wp-edit-form/work-package-editing-service';
import {WorkPackageTableFocusService} from 'core-components/wp-fast-table/state/wp-table-focus.service';
import {StateService} from '@uirouter/core';
import {Injector, OnDestroy} from '@angular/core';
import {I18nToken} from 'core-app/angular4-transition-utils';
import PathHelper = op.PathHelper;
import {PathHelperService} from 'core-components/common/path-helper/path-helper.service';
import {componentDestroyed} from 'ng2-rx-componentdestroyed';
export class WorkPackageViewController implements OnDestroy {
@ -78,7 +74,9 @@ export class WorkPackageViewController implements OnDestroy {
*/
protected observeWorkPackage() {
this.wpCacheService.loadWorkPackage(this.workPackageId).values$()
.takeUntil(componentDestroyed(this))
.pipe(
takeUntil(componentDestroyed(this))
)
.subscribe((wp:WorkPackageResourceInterface) => {
this.workPackage = wp;
this.init();
@ -109,10 +107,12 @@ export class WorkPackageViewController implements OnDestroy {
// Listen to tab changes to update the tab label
this.keepTab.observable
.takeUntil(componentDestroyed(this))
.pipe(
takeUntil(componentDestroyed(this))
)
.subscribe((tabs:any) => {
this.updateFocusAnchorLabel(tabs.active);
});
this.updateFocusAnchorLabel(tabs.active);
});
}
/**

@ -25,17 +25,12 @@
//
// See doc/COPYRIGHT.rdoc for more details.
// ++
import {opWorkPackagesModule} from "../../angular-modules";
import {State} from "reactivestates";
import {Observable, Subject} from "rxjs";
import {WorkPackageResource} from "../api/api-v3/hal-resources/work-package-resource.service";
import {ApiWorkPackagesService} from "../api/api-work-packages/api-work-packages.service";
import {States} from "../states.service";
import { WorkPackageNotificationService } from "./../wp-edit/wp-notification.service";
import { SchemaResource } from "../api/api-v3/hal-resources/schema-resource.service";
import IScope = angular.IScope;
import IPromise = angular.IPromise;
import {WorkPackageResourceInterface} from "core-components/api/api-v3/hal-resources/work-package-resource.service";
import {WorkPackageResourceInterface} from 'core-components/api/api-v3/hal-resources/work-package-resource.service';
import {State} from 'reactivestates';
import {opWorkPackagesModule} from '../../angular-modules';
import {SchemaResource} from '../api/api-v3/hal-resources/schema-resource.service';
import {States} from '../states.service';
export class SchemaCacheService {
@ -61,7 +56,7 @@ export class SchemaCacheService {
/**
* Get the associated schema state of the work package
* without initializing a new resource.
*/
*/
state(workPackage:WorkPackageResourceInterface) {
const schema = workPackage.$links.schema;
return this.states.schemas.get(schema.href!);

@ -1,6 +1,7 @@
import {WPFocusState} from 'core-components/wp-fast-table/state/wp-table-focus.service';
import {TableState} from 'core-components/wp-table/table-state/table-state';
import {combine, derive, input, multiInput, StatesGroup} from 'reactivestates';
import {mapTo} from 'rxjs/operators';
import {opServicesModule} from '../angular-modules';
import {QueryFormResource} from './api/api-v3/hal-resources/query-form-resource.service';
import {QueryGroupByResource} from './api/api-v3/hal-resources/query-group-by-resource.service';
@ -84,7 +85,7 @@ export class TableRenderingStates {
this.states.globalTable.additionalRequiredWorkPackages
);
onQueryUpdated = derive(this.combinedTableStates, ($, input) => $.mapTo(null));
onQueryUpdated = derive(this.combinedTableStates, ($, input) => $.pipe(mapTo(null)));
}

@ -1,6 +1,6 @@
// -- copyright
// OpenProject is a project management system.
// Copyright (C) 2012-2015 the OpenProject Foundation (OPF)
// 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.
@ -25,20 +25,8 @@
//
// See doc/COPYRIGHT.rdoc for more details.
// ++
import {SchemaCacheService} from './../schemas/schema-cache.service';
import {InputState, MultiInputState, State} from 'reactivestates';
import {Observable, Subject} from 'rxjs';
import {opWorkPackagesModule} from '../../angular-modules';
import {
WorkPackageResourceInterface
} from '../api/api-v3/hal-resources/work-package-resource.service';
import {ApiWorkPackagesService} from '../api/api-work-packages/api-work-packages.service';
import {States} from '../states.service';
import {WorkPackageNotificationService} from './../wp-edit/wp-notification.service';
import IScope = angular.IScope;
import IPromise = angular.IPromise;
import {WorkPackageCollectionResourceInterface} from '../api/api-v3/hal-resources/wp-collection-resource.service';
import {SchemaResource} from '../api/api-v3/hal-resources/schema-resource.service';
export abstract class StateCacheService<T> {
private cacheDurationInMs:number;

@ -1,42 +1,45 @@
import {InputState, derive, input, State, IfThen} from 'reactivestates';
import {debugLog} from "../../helpers/debug_output";
import {derive, IfThen, input, InputState, State} from 'reactivestates';
import {filter} from 'rxjs/operators';
import {debugLog} from '../../helpers/debug_output';
export class SwitchState<StateName> {
private readonly contextSwitch$: InputState<StateName> = input<StateName>();
private readonly contextSwitch$:InputState<StateName> = input<StateName>();
public transition(context: StateName) {
public transition(context:StateName) {
if (this.validTransition(context)) {
debugLog(`Switching table context to ${context}`);
this.contextSwitch$.putValue(context);
}
}
public validTransition(to: StateName) {
public validTransition(to:StateName) {
return (this.contextSwitch$.value !== to);
}
public get current():StateName|undefined {
public get current():StateName | undefined {
return this.contextSwitch$.value;
}
public reset(reason?: string) {
public reset(reason?:string) {
debugLog('Resetting table context.');
this.contextSwitch$.clear(reason);
}
public doAndTransition(context: StateName, callback:() => PromiseLike<any>) {
public doAndTransition(context:StateName, callback:() => PromiseLike<any>) {
this.reset('Clearing before transitioning to ' + context);
const promise = callback();
promise.then(() => this.transition(context));
}
public fireOnTransition<T>(cb: State<T>, ...context: StateName[]): State<T> {
public fireOnTransition<T>(cb:State<T>, ...context:StateName[]):State<T> {
return IfThen(this.contextSwitch$, s => context.indexOf(s) > -1, cb);
}
public fireOnStateChange<T>(state: State<T>, ...context: StateName[]): State<T> {
public fireOnStateChange<T>(state:State<T>, ...context:StateName[]):State<T> {
return derive(state, $ => $
.filter(() => this.contextSwitch$.hasValue() && context.indexOf(this.contextSwitch$.value!) > -1))
.pipe(
filter(() => this.contextSwitch$.hasValue() && context.indexOf(this.contextSwitch$.value!) > -1))
);
}
}

@ -25,24 +25,20 @@
//
// See doc/COPYRIGHT.rdoc for more details.
// ++
import {SchemaCacheService} from './../schemas/schema-cache.service';
import {State} from 'reactivestates';
import {Observable, Subject} from 'rxjs';
import {opWorkPackagesModule} from '../../angular-modules';
import {
WorkPackageResourceInterface
} from '../api/api-v3/hal-resources/work-package-resource.service';
import {SchemaResource} from '../api/api-v3/hal-resources/schema-resource.service';
import {WorkPackageResourceInterface} from '../api/api-v3/hal-resources/work-package-resource.service';
import {WorkPackageCollectionResourceInterface} from '../api/api-v3/hal-resources/wp-collection-resource.service';
import {ApiWorkPackagesService} from '../api/api-work-packages/api-work-packages.service';
import {States} from '../states.service';
import {WorkPackageNotificationService} from './../wp-edit/wp-notification.service';
import IScope = angular.IScope;
import IPromise = angular.IPromise;
import {WorkPackageCollectionResourceInterface} from '../api/api-v3/hal-resources/wp-collection-resource.service';
import {SchemaResource} from '../api/api-v3/hal-resources/schema-resource.service';
import {StateCacheService} from '../states/state-cache.service';
import {SchemaCacheService} from './../schemas/schema-cache.service';
import {WorkPackageNotificationService} from './../wp-edit/wp-notification.service';
function getWorkPackageId(id:number | string):string {
return (id || "__new_work_package__").toString();
return (id || '__new_work_package__').toString();
}
export class WorkPackageCacheService extends StateCacheService<WorkPackageResourceInterface> {
@ -87,7 +83,7 @@ export class WorkPackageCacheService extends StateCacheService<WorkPackageResour
return Promise.reject<any>(null);
}
return new Promise<WorkPackageResourceInterface|null>((resolve, reject) => {
return new Promise<WorkPackageResourceInterface | null>((resolve, reject) => {
return workPackage.save()
.then(() => {
this.wpNotificationsService.showSave(workPackage);

@ -1,11 +1,9 @@
import {wpControllersModule} from '../../../angular-modules';
import {
RelationsStateValue,
WorkPackageRelationsService
} from '../../wp-relations/wp-relations.service';
import {Component, Input, OnDestroy, OnInit} from '@angular/core';
import {downgradeComponent} from '@angular/upgrade/static';
import {componentDestroyed} from 'ng2-rx-componentdestroyed';
import {takeUntil} from 'rxjs/operators';
import {wpControllersModule} from '../../../angular-modules';
import {RelationsStateValue, WorkPackageRelationsService} from '../../wp-relations/wp-relations.service';
@Component({
template: require('!!raw-loader!./wp-relations-count.html'),
@ -22,7 +20,9 @@ export class WorkPackageRelationsCountComponent implements OnInit, OnDestroy {
this.wpRelations.require(this.wpId.toString());
this.wpRelations.state(this.wpId.toString()).values$()
.takeUntil(componentDestroyed(this))
.pipe(
takeUntil(componentDestroyed(this))
)
.subscribe((relations:RelationsStateValue) => {
this.count = _.size(relations);
});

@ -26,19 +26,20 @@
// See doc/COPYRIGHT.rdoc for more details.
// ++
import {Component, Inject, Input, OnDestroy, OnInit} from '@angular/core';
import {I18nToken} from 'core-app/angular4-transition-utils';
import {PathHelperService} from 'core-components/common/path-helper/path-helper.service';
import {WorkPackageEditFieldGroupComponent} from 'core-components/wp-edit/wp-edit-field/wp-edit-field-group.directive';
import {componentDestroyed} from 'ng2-rx-componentdestroyed';
import {takeUntil} from 'rxjs/operators';
import {debugLog} from '../../../helpers/debug_output';
import {WorkPackageResourceInterface} from '../../api/api-v3/hal-resources/work-package-resource.service';
import {CurrentProjectService} from '../../projects/current-project.service';
import {States} from '../../states.service';
import {DisplayField} from '../../wp-display/wp-display-field/wp-display-field.module';
import {WorkPackageDisplayFieldService} from '../../wp-display/wp-display-field/wp-display-field.service';
import {WorkPackageCacheService} from '../work-package-cache.service';
import {WorkPackageEditingService} from '../../wp-edit-form/work-package-editing-service';
import {States} from '../../states.service';
import {CurrentProjectService} from '../../projects/current-project.service';
import {Component, Inject, Input, OnDestroy, OnInit} from '@angular/core';
import {PathHelperService} from 'core-components/common/path-helper/path-helper.service';
import {I18nToken} from 'core-app/angular4-transition-utils';
import {componentDestroyed} from 'ng2-rx-componentdestroyed';
import {WorkPackageEditFieldGroupComponent} from 'core-components/wp-edit/wp-edit-field/wp-edit-field-group.directive';
import {WorkPackageCacheService} from '../work-package-cache.service';
interface FieldDescriptor {
name:string;
@ -58,14 +59,14 @@ interface GroupDescriptor {
template: require('!!raw-loader!./wp-single-view.html'),
selector: 'wp-single-view',
})
export class WorkPackageSingleViewComponent implements OnInit, OnDestroy {
export class WorkPackageSingleViewComponent implements OnInit, OnDestroy {
@Input('workPackage') public workPackage:WorkPackageResourceInterface;
// Grouped fields returned from API
public groupedFields:GroupDescriptor[] = [];
public projectContext:{
matches:boolean,
href:string|null,
href:string | null,
field?:FieldDescriptor[]
};
public text = {
@ -113,13 +114,15 @@ export class WorkPackageSingleViewComponent implements OnInit, OnDestroy {
this.wpEditing.temporaryEditResource(this.workPackage.id)
.values$()
.takeUntil(componentDestroyed(this))
.pipe(
takeUntil(componentDestroyed(this))
)
.subscribe((resource:WorkPackageResourceInterface) => {
// Prepare the fields that are required always
const isNew = this.workPackage.isNew;
if (!resource.project) {
this.projectContext = { matches: false, href: null };
this.projectContext = {matches: false, href: null};
} else {
this.projectContext = {
href: this.PathHelper.projectWorkPackagePath(resource.project.idFromLink, this.workPackage.id),
@ -176,7 +179,7 @@ export class WorkPackageSingleViewComponent implements OnInit, OnDestroy {
* @param index
* @param elem
*/
public trackByName(_index:number, elem:{ name: string }) {
public trackByName(_index:number, elem:{ name:string }) {
return elem.name;
}
@ -191,7 +194,7 @@ export class WorkPackageSingleViewComponent implements OnInit, OnDestroy {
let id = this.workPackage.project.idFromLink;
let projectPath = this.PathHelper.projectPath(id);
let project = `<a href="${projectPath}">${this.workPackage.project.name}<a>`;
return this.I18n.t('js.project.work_package_belongs_to', { projectname: project });
return this.I18n.t('js.project.work_package_belongs_to', {projectname: project});
}
/**

@ -26,13 +26,14 @@
// See doc/COPYRIGHT.rdoc for more details.
// ++
import {Component, Input, OnDestroy, OnInit} from '@angular/core';
import {downgradeComponent} from '@angular/upgrade/static';
import {UIRouterGlobals} from '@uirouter/core';
import {componentDestroyed} from 'ng2-rx-componentdestroyed';
import {takeUntil} from 'rxjs/operators';
import {opWorkPackagesModule} from '../../../angular-modules';
import {WorkPackageResourceInterface} from '../../api/api-v3/hal-resources/work-package-resource.service';
import {WorkPackageCacheService} from '../work-package-cache.service';
import {UIRouterGlobals} from '@uirouter/core';
import {Component, Input, OnDestroy, OnInit} from '@angular/core';
import {componentDestroyed} from 'ng2-rx-componentdestroyed';
import {downgradeComponent} from '@angular/upgrade/static';
@Component({
template: require('!!raw-loader!./wp-subject.html'),
@ -53,7 +54,9 @@ export class WorkPackageSubjectComponent implements OnInit, OnDestroy {
if (!this.workPackage) {
this.wpCacheService.loadWorkPackage(this.uiRouterGlobals.params['workPackageId'])
.values$()
.takeUntil(componentDestroyed(this))
.pipe(
takeUntil(componentDestroyed(this))
)
.subscribe((wp:WorkPackageResourceInterface) => {
this.workPackage = wp;
});

@ -26,19 +26,20 @@
// See doc/COPYRIGHT.rdoc for more details.
// ++
import {wpDirectivesModule} from '../../../angular-modules';
import {WorkPackageResourceInterface} from '../../api/api-v3/hal-resources/work-package-resource.service';
import {WorkPackageCacheService} from '../work-package-cache.service';
import {Component, Inject, Input, OnDestroy, OnInit} from '@angular/core';
import {downgradeComponent} from '@angular/upgrade/static';
import {I18nToken} from 'core-app/angular4-transition-utils';
import {componentDestroyed} from 'ng2-rx-componentdestroyed';
import {downgradeComponent} from '@angular/upgrade/static';
import {takeUntil} from 'rxjs/operators';
import {wpDirectivesModule} from '../../../angular-modules';
import {WorkPackageResourceInterface} from '../../api/api-v3/hal-resources/work-package-resource.service';
import {WorkPackageCacheService} from '../work-package-cache.service';
@Component({
template: require('!!raw-loader!./wp-watcher-button.html'),
selector: 'wp-watcher-button',
})
export class WorkPackageWatcherButtonComponent implements OnInit, OnDestroy {
export class WorkPackageWatcherButtonComponent implements OnInit, OnDestroy {
@Input('workPackage') public workPackage:WorkPackageResourceInterface;
@Input('showText') public showText:boolean = false;
@Input('disabled') public disabled:boolean = false;
@ -56,8 +57,10 @@ export class WorkPackageWatcherButtonComponent implements OnInit, OnDestroy {
ngOnInit() {
this.wpCacheService.loadWorkPackage(this.workPackage.id)
.values$()
.takeUntil(componentDestroyed(this))
.subscribe((wp: WorkPackageResourceInterface) => {
.pipe(
takeUntil(componentDestroyed(this))
)
.subscribe((wp:WorkPackageResourceInterface) => {
this.workPackage = wp;
this.setWatchStatus();
});

@ -26,16 +26,19 @@
// See doc/COPYRIGHT.rdoc for more details.
// ++
import {WorkPackageResourceInterface} from "../api/api-v3/hal-resources/work-package-resource.service";
import {WorkPackageCreateController} from "../wp-new/wp-create.controller";
import {take} from 'rxjs/operators';
import {WorkPackageResourceInterface} from '../api/api-v3/hal-resources/work-package-resource.service';
import {WorkPackageChangeset} from '../wp-edit-form/work-package-changeset';
import {WorkPackageCreateController} from '../wp-new/wp-create.controller';
export class WorkPackageCopyController extends WorkPackageCreateController {
protected newWorkPackageFromParams(stateParams:any) {
return new Promise<WorkPackageChangeset>((resolve, reject) => {
this.wpCacheService.loadWorkPackage(stateParams.copiedFromWorkPackageId)
.values$()
.take(1)
.pipe(
take(1)
)
.subscribe(
(wp:WorkPackageResourceInterface) => this.createCopyFrom(wp).then(resolve),
reject);

@ -26,21 +26,15 @@
// See doc/COPYRIGHT.rdoc for more details.
// ++
import {combine, deriveRaw, multiInput, State, StatesGroup} from 'reactivestates';
import {map} from 'rxjs/operators';
import {wpServicesModule} from '../../angular-modules';
import {WorkPackageEditForm} from './work-package-edit-form';
import {
WorkPackageResource,
WorkPackageResourceEmbedded,
WorkPackageResourceInterface, WorkPackageResourceLinks
} from '../api/api-v3/hal-resources/work-package-resource.service';
import {WorkPackageEditContext} from './work-package-edit-context';
import {WorkPackageChangeset} from './work-package-changeset';
import {WorkPackageResourceInterface} from '../api/api-v3/hal-resources/work-package-resource.service';
import {StateCacheService} from '../states/state-cache.service';
import {combine, deriveRaw, multiInput, State, StatesGroup} from 'reactivestates';
import {WorkPackageCacheService} from '../work-packages/work-package-cache.service';
import {Observable} from 'rxjs';
import {SchemaResource} from '../api/api-v3/hal-resources/schema-resource.service';
import {HalResource} from '../api/api-v3/hal-resources/hal-resource.service';
import {WorkPackageChangeset} from './work-package-changeset';
import {WorkPackageEditContext} from './work-package-edit-context';
import {WorkPackageEditForm} from './work-package-edit-form';
class WPChangesetStates extends StatesGroup {
name = 'WP-Changesets';
@ -100,14 +94,16 @@ export class WorkPackageEditingService extends StateCacheService<WorkPackageChan
const combined = combine(this.wpCacheService.state(id), this.state(id));
return deriveRaw(combined,
($) =>
$.map(([wp, changeset]) => {
if (wp && changeset && changeset.resource) {
return changeset.resource!;
} else {
return wp;
}
})
($) => $
.pipe(
map(([wp, changeset]) => {
if (wp && changeset && changeset.resource) {
return changeset.resource!;
} else {
return wp;
}
})
)
);
}
@ -126,7 +122,7 @@ export class WorkPackageEditingService extends StateCacheService<WorkPackageChan
return new WorkPackageEditForm(changeset.workPackage).submit();
}
return Promise.reject("No changeset present") as any;
return Promise.reject('No changeset present') as any;
}
protected load(id:string) {

@ -26,24 +26,25 @@
// See doc/COPYRIGHT.rdoc for more details.
// ++
import {States} from '../../states.service';
import {opWorkPackagesModule} from '../../../angular-modules';
import {WorkPackageEditingService} from '../../wp-edit-form/work-package-editing-service';
import {WorkPackageEditForm} from '../../wp-edit-form/work-package-edit-form';
import {SingleViewEditContext} from '../../wp-edit-form/single-view-edit-context';
import {Component, Inject, Input, OnDestroy, OnInit} from '@angular/core';
import {downgradeComponent} from '@angular/upgrade/static';
import {StateService, Transition, TransitionService} from '@uirouter/core';
import {$stateToken, I18nToken} from 'core-app/angular4-transition-utils';
import {ConfigurationService} from 'core-components/common/config/configuration.service';
import {WorkPackageEditFieldComponent} from 'core-components/wp-edit/wp-edit-field/wp-edit-field.component';
import {WorkPackageTableFocusService} from 'core-components/wp-fast-table/state/wp-table-focus.service';
import {componentDestroyed} from 'ng2-rx-componentdestroyed';
import {input} from 'reactivestates';
import {takeUntil, filter, take, map} from 'rxjs/operators';
import {opWorkPackagesModule} from '../../../angular-modules';
import {WorkPackageResourceInterface} from '../../api/api-v3/hal-resources/work-package-resource.service';
import {States} from '../../states.service';
import {SingleViewEditContext} from '../../wp-edit-form/single-view-edit-context';
import {WorkPackageEditForm} from '../../wp-edit-form/work-package-edit-form';
import {WorkPackageEditingService} from '../../wp-edit-form/work-package-editing-service';
import {WorkPackageTableSelection} from '../../wp-fast-table/state/wp-table-selection.service';
import {WorkPackageNotificationService} from '../wp-notification.service';
import {WorkPackageCreateService} from './../../wp-new/wp-create.service';
import {WorkPackageTableFocusService} from 'core-components/wp-fast-table/state/wp-table-focus.service';
import {StateService, Transition, TransitionService} from '@uirouter/core';
import {Component, Inject, Input, OnDestroy, OnInit} from '@angular/core';
import {$stateToken, I18nToken} from 'core-app/angular4-transition-utils';
import {componentDestroyed} from 'ng2-rx-componentdestroyed';
import {downgradeComponent} from '@angular/upgrade/static';
import {ConfigurationService} from 'core-components/common/config/configuration.service';
import {WorkPackageEditFieldComponent} from 'core-components/wp-edit/wp-edit-field/wp-edit-field.component';
@Component({
selector: 'wp-edit-field-group,[wp-edit-field-group]',
@ -108,16 +109,20 @@ export class WorkPackageEditFieldGroupComponent implements OnInit, OnDestroy {
// Stop editing whenever a work package was saved
if (this.inEditMode && this.workPackage.isNew) {
this.wpCreate.onNewWorkPackage()
.takeUntil(componentDestroyed(this))
.pipe(
takeUntil(componentDestroyed(this))
)
.subscribe((wp:WorkPackageResourceInterface) => {
this.form.editMode = false;
this.stopEditingAndLeave(wp, true);
});
});
}
this.states.workPackages.get(this.workPackage.id)
.values$()
.takeUntil(componentDestroyed(this))
.pipe(
takeUntil(componentDestroyed(this)),
)
.subscribe((wp) => {
_.each(this.fields, (ctrl) => this.updateDisplayField(ctrl, wp));
});
@ -148,9 +153,11 @@ export class WorkPackageEditFieldGroupComponent implements OnInit, OnDestroy {
public waitForField(name:string):Promise<WorkPackageEditFieldComponent> {
return this.registeredFields
.values$()
.filter(keys => keys.indexOf(name) >= 0)
.take(1)
.map(() => this.fields[name])
.pipe(
filter(keys => keys.indexOf(name) >= 0),
take(1),
map(() => this.fields[name])
)
.toPromise();
}
@ -219,7 +226,6 @@ export class WorkPackageEditFieldGroupComponent implements OnInit, OnDestroy {
}
opWorkPackagesModule.directive('wpEditFieldGroupNg1',
downgradeComponent({component: WorkPackageEditFieldGroupComponent})
);

@ -1,4 +1,5 @@
import {Injector} from '@angular/core';
import {filter, takeUntil} from 'rxjs/operators';
import {debugLog} from '../../../../helpers/debug_output';
import {States} from '../../../states.service';
import {WorkPackageTableColumnsService} from '../../state/wp-table-columns.service';
@ -14,8 +15,10 @@ export class ColumnsTransformer {
this.states.updates.columnsUpdates
.values$('Refreshing columns on user request')
.filter(() => this.wpTableColumns.hasRelationColumns() === false)
.takeUntil(this.states.globalTable.stopAllSubscriptions)
.pipe(
filter(() => this.wpTableColumns.hasRelationColumns() === false),
takeUntil(this.states.globalTable.stopAllSubscriptions)
)
.subscribe(() => {
if (table.originalRows.length > 0) {

@ -1,5 +1,6 @@
import {Injector} from '@angular/core';
import {scrollTableRowIntoView} from 'core-components/wp-fast-table/helpers/wp-table-row-helpers';
import {distinctUntilChanged, map, takeUntil} from 'rxjs/operators';
import {States} from '../../../states.service';
import {indicatorCollapsedClass} from '../../builders/modes/hierarchy/single-hierarchy-row-builder';
import {tableRowClassName} from '../../builders/rows/single-row-builder';
@ -17,9 +18,11 @@ export class HierarchyTransformer {
table:WorkPackageTable) {
this.states.updates.hierarchyUpdates
.values$('Refreshing hierarchies on user request')
.takeUntil(this.states.globalTable.stopAllSubscriptions)
.map((state) => state.isEnabled)
.distinctUntilChanged()
.pipe(
takeUntil(this.states.globalTable.stopAllSubscriptions),
map((state) => state.isEnabled),
distinctUntilChanged()
)
.subscribe(() => {
// We don't have to reload all results when _disabling_ the hierarchy mode.
if (!this.wpTableHierarchies.isEnabled) {

@ -1,4 +1,5 @@
import {Injector} from '@angular/core';
import {filter, takeUntil} from 'rxjs/operators';
import {debugLog} from '../../../../helpers/debug_output';
import {WorkPackageResourceInterface} from '../../../api/api-v3/hal-resources/work-package-resource.service';
import {States} from '../../../states.service';
@ -15,7 +16,9 @@ export class RowsTransformer {
// Redraw table if the current row state changed
this.states.query.context.fireOnTransition(this.states.globalTable.rows, 'Query loaded')
.values$('Initializing table after query was initialized')
.takeUntil(this.states.globalTable.stopAllSubscriptions)
.pipe(
takeUntil(this.states.globalTable.stopAllSubscriptions)
)
.subscribe((rows:WorkPackageResourceInterface[]) => {
var t0 = performance.now();
@ -27,8 +30,10 @@ export class RowsTransformer {
// Refresh a single row if it exists
this.states.workPackages.observeChange()
.takeUntil(this.states.globalTable.stopAllSubscriptions.asObservable())
.filter(() => this.states.query.context.current === 'Query loaded')
.pipe(
takeUntil(this.states.globalTable.stopAllSubscriptions.asObservable()),
filter(() => this.states.query.context.current === 'Query loaded')
)
.subscribe(([changedId, wp]) => {
if (wp === undefined) {
return;

@ -1,6 +1,7 @@
import {Injector} from '@angular/core';
import {FocusHelperToken} from 'core-app/angular4-transition-utils';
import {WorkPackageTableFocusService} from 'core-components/wp-fast-table/state/wp-table-focus.service';
import {takeUntil} from 'rxjs/operators';
import {States} from '../../../states.service';
import {tableRowClassName} from '../../builders/rows/single-row-builder';
import {checkedClassName} from '../../builders/ui-state-link-builder';
@ -23,7 +24,9 @@ export class SelectionTransformer {
// Focus a single selection when active
this.states.globalTable.rendered.values$()
.takeUntil(this.states.globalTable.stopAllSubscriptions)
.pipe(
takeUntil(this.states.globalTable.stopAllSubscriptions)
)
.subscribe(() => {
this.wpTableFocus.ifShouldFocus((wpId:string) => {
@ -38,7 +41,9 @@ export class SelectionTransformer {
// Update selection state
this.wpTableSelection.selectionState.values$()
.takeUntil(this.states.globalTable.stopAllSubscriptions)
.pipe(
takeUntil(this.states.globalTable.stopAllSubscriptions)
)
.subscribe((state:WPTableRowSelectionState) => {
this.renderSelectionState(state);
});

@ -1,4 +1,5 @@
import {Injector} from '@angular/core';
import {takeUntil} from 'rxjs/operators';
import {States} from '../../../states.service';
import {WorkPackageTable} from '../../wp-fast-table';
import {WorkPackageTableTimelineState} from '../../wp-table-timeline';
@ -11,9 +12,12 @@ export class TimelineTransformer {
table:WorkPackageTable) {
this.states.globalTable.timelineVisible.values$()
.takeUntil(this.states.globalTable.stopAllSubscriptions).subscribe((state:WorkPackageTableTimelineState) => {
this.renderVisibility(state.isVisible);
});
.pipe(
takeUntil(this.states.globalTable.stopAllSubscriptions)
)
.subscribe((state:WorkPackageTableTimelineState) => {
this.renderVisibility(state.isVisible);
});
}
/**

@ -26,15 +26,15 @@
// See doc/COPYRIGHT.rdoc for more details.
// ++
import {QuerySchemaResourceInterface} from 'core-components/api/api-v3/hal-resources/query-schema-resource.service';
import {WorkPackageCollectionResource} from 'core-components/api/api-v3/hal-resources/wp-collection-resource.service';
import {States} from 'core-components/states.service';
import {TableState} from 'core-components/wp-table/table-state/table-state';
import {InputState, State} from 'reactivestates';
import {Observable} from 'rxjs/Observable';
import {mapTo, take, takeUntil} from 'rxjs/operators';
import {scopedObservable} from '../../../helpers/angular-rx-utils';
import {Observable} from 'rxjs';
import {QueryResource} from '../../api/api-v3/hal-resources/query-resource.service';
import {TableState} from 'core-components/wp-table/table-state/table-state';
import {QuerySchemaResourceInterface} from 'core-components/api/api-v3/hal-resources/query-schema-resource.service';
import {States} from 'core-components/states.service';
import {WorkPackageCollectionResource} from 'core-components/api/api-v3/hal-resources/wp-collection-resource.service';
import {takeUntil} from 'rxjs/operators';
export abstract class WorkPackageTableBaseService<T> {
protected tableState:TableState;
@ -56,7 +56,7 @@ export abstract class WorkPackageTableBaseService<T> {
* @param {QueryResource} query
* @returns {T} Instance of the state value for this type.
*/
public abstract valueFromQuery(query:QueryResource, results:WorkPackageCollectionResource):T|undefined;
public abstract valueFromQuery(query:QueryResource, results:WorkPackageCollectionResource):T | undefined;
/**
* Initialize this table state from the given query resource,
@ -82,7 +82,12 @@ export abstract class WorkPackageTableBaseService<T> {
}
public onReady(scope:ng.IScope) {
return scopedObservable(scope, this.state.values$()).take(1).mapTo(null).toPromise();
return scopedObservable(scope, this.state.values$())
.pipe(
take(1),
mapTo(null)
)
.toPromise();
}
}

@ -1,8 +1,8 @@
import {States} from '../../states.service';
import {opServicesModule} from '../../../angular-modules';
import {WorkPackageResource} from '../../api/api-v3/hal-resources/work-package-resource.service';
import {InputState} from 'reactivestates';
import {WorkPackageTableSelection} from 'core-components/wp-fast-table/state/wp-table-selection.service';
import {InputState} from 'reactivestates';
import {distinctUntilChanged, filter, map} from 'rxjs/operators';
import {opServicesModule} from '../../../angular-modules';
import {States} from '../../states.service';
export interface WPFocusState {
workPackageId:string;
@ -33,7 +33,7 @@ export class WorkPackageTableFocusService {
}
}
public get focusedWorkPackage():string|null {
public get focusedWorkPackage():string | null {
const value = this.state.value;
if (value) {
@ -49,8 +49,10 @@ export class WorkPackageTableFocusService {
public whenChanged() {
return this.state.values$()
.map((val:WPFocusState) => val.workPackageId)
.distinctUntilChanged();
.pipe(
map((val:WPFocusState) => val.workPackageId),
distinctUntilChanged()
);
}
public updateFocus(workPackageId:string, setFocusAfterRender:boolean = false) {
@ -58,7 +60,7 @@ export class WorkPackageTableFocusService {
if (this.wpTableSelection.isEmpty) {
this.wpTableSelection.setRowState(workPackageId, true);
}
this.state.putValue({ workPackageId: workPackageId, focusAfterRender: setFocusAfterRender});
this.state.putValue({workPackageId: workPackageId, focusAfterRender: setFocusAfterRender});
}
/**
@ -69,8 +71,10 @@ export class WorkPackageTableFocusService {
this
.states.globalTable.rendered
.values$()
.map(state => _.find(state, (row:any) => row.workPackageId))
.filter(fullRow => !!fullRow && this.wpTableSelection.isEmpty)
.pipe(
map(state => _.find(state, (row:any) => row.workPackageId)),
filter(fullRow => !!fullRow && this.wpTableSelection.isEmpty)
)
.subscribe(fullRow => {
this.updateFocus(fullRow!.workPackageId!);
});

@ -26,19 +26,20 @@
// See doc/COPYRIGHT.rdoc for more details.
// ++
import {WorkPackageQueryStateService, WorkPackageTableBaseService} from './wp-table-base.service';
import {States} from 'core-components/states.service';
import {combine} from 'reactivestates';
import {Observable} from 'rxjs/Observable';
import {mapTo} from 'rxjs/operators';
import {opServicesModule} from '../../../angular-modules';
import {QueryResource} from '../../api/api-v3/hal-resources/query-resource.service';
import {
QUERY_SORT_BY_ASC,
QUERY_SORT_BY_DESC,
QuerySortByResource
} from '../../api/api-v3/hal-resources/query-sort-by-resource.service';
import {opServicesModule} from '../../../angular-modules';
import {WorkPackageTableSortBy} from '../wp-table-sort-by';
import {QueryColumn} from '../../wp-query/query-column';
import {combine} from 'reactivestates';
import {Observable} from 'rxjs';
import {States} from 'core-components/states.service';
import {WorkPackageTableSortBy} from '../wp-table-sort-by';
import {WorkPackageQueryStateService, WorkPackageTableBaseService} from './wp-table-base.service';
export class WorkPackageTableSortByService extends WorkPackageTableBaseService<WorkPackageTableSortBy> implements WorkPackageQueryStateService {
@ -58,7 +59,9 @@ export class WorkPackageTableSortByService extends WorkPackageTableBaseService<W
public onReadyWithAvailable():Observable<null> {
return combine(this.state, this.states.query.available.sortBy)
.values$()
.mapTo(null);
.pipe(
mapTo(null)
);
}
public hasChanged(query:QueryResource) {
@ -98,11 +101,11 @@ export class WorkPackageTableSortByService extends WorkPackageTableBaseService<W
}
}
public findAvailableDirection(column:QueryColumn, direction:string):QuerySortByResource|undefined {
public findAvailableDirection(column:QueryColumn, direction:string):QuerySortByResource | undefined {
return _.find(
this.available,
(candidate) => (candidate.column.$href === column.$href &&
candidate.direction.$href === direction)
candidate.direction.$href === direction)
);
}

@ -28,13 +28,14 @@
import {Directive, ElementRef, Injector, Input} from '@angular/core';
import {UpgradeComponent} from '@angular/upgrade/static';
import {AuthorisationService} from 'core-components/common/model-auth/model-auth.service';
import {WorkPackageTableFocusService} from 'core-components/wp-fast-table/state/wp-table-focus.service';
import {filter, takeUntil} from 'rxjs/operators';
import {opWorkPackagesModule} from '../../angular-modules';
import {scopeDestroyed$, scopedObservable} from '../../helpers/angular-rx-utils';
import {WorkPackageResourceInterface} from '../api/api-v3/hal-resources/work-package-resource.service';
import {States} from '../states.service';
import {WorkPackageCacheService} from '../work-packages/work-package-cache.service';
import {WorkPackageCreateService} from '../wp-new/wp-create.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';
@ -45,12 +46,12 @@ import {onClickOrEnter} from '../wp-fast-table/handlers/click-or-enter-handler';
import {WorkPackageTableColumnsService} from '../wp-fast-table/state/wp-table-columns.service';
import {WorkPackageTableFiltersService} from '../wp-fast-table/state/wp-table-filters.service';
import {WorkPackageTable} from '../wp-fast-table/wp-fast-table';
import {WorkPackageCreateService} from '../wp-new/wp-create.service';
import {
inlineCreateCancelClassName,
InlineCreateRowBuilder,
inlineCreateRowClassName
} from './inline-create-row-builder';
import {AuthorisationService} from 'core-components/common/model-auth/model-auth.service';
export class WorkPackageInlineCreateController {
@ -129,16 +130,19 @@ export class WorkPackageInlineCreateController {
// Watch on this scope when the columns change and refresh this row
this.states.globalTable.columns.values$()
.filter(() => this.isHidden) // Take only when row is inserted
.takeUntil(scopeDestroyed$(this.$scope)).subscribe(() => {
const rowElement = this.$element.find(`.${inlineCreateRowClassName}`);
if (rowElement.length && this.currentWorkPackage) {
this.rowBuilder.refreshRow(this.currentWorkPackage,
this.workPackageEditForm!.changeset,
rowElement);
}
});
.pipe(
filter(() => this.isHidden), // Take only when row is inserted
takeUntil(scopeDestroyed$(this.$scope))
)
.subscribe(() => {
const rowElement = this.$element.find(`.${inlineCreateRowClassName}`);
if (rowElement.length && this.currentWorkPackage) {
this.rowBuilder.refreshRow(this.currentWorkPackage,
this.workPackageEditForm!.changeset,
rowElement);
}
});
// Cancel edition of current new row
this.$element.on('click keydown', `.${inlineCreateCancelClassName}`, (evt) => {

@ -26,22 +26,23 @@
// See doc/COPYRIGHT.rdoc for more details.
// ++
import {WorkPackageResourceInterface} from '../api/api-v3/hal-resources/work-package-resource.service';
import {States} from '../states.service';
import {Inject, OnDestroy, OnInit} from '@angular/core';
import {StateService, Transition} from '@uirouter/core';
import {$stateToken, I18nToken, v3PathToken} from 'core-app/angular4-transition-utils';
import {PathHelperService} from 'core-components/common/path-helper/path-helper.service';
import {componentDestroyed} from 'ng2-rx-componentdestroyed';
import {takeUntil} from 'rxjs/operators';
import {RootDmService} from '../api/api-v3/hal-resource-dms/root-dm.service';
import {RootResource} from '../api/api-v3/hal-resources/root-resource.service';
import {WorkPackageResourceInterface} from '../api/api-v3/hal-resources/work-package-resource.service';
import {States} from '../states.service';
import {WorkPackageCacheService} from '../work-packages/work-package-cache.service';
import {WorkPackageNotificationService} from '../wp-edit/wp-notification.service';
import {WorkPackageCreateService} from './wp-create.service';
import {WorkPackageEditingService} from '../wp-edit-form/work-package-editing-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 {StateService, Transition} from '@uirouter/core';
import {Inject, Input, OnDestroy, OnInit} from '@angular/core';
import {$stateToken, I18nToken, v3PathToken} from 'core-app/angular4-transition-utils';
import {componentDestroyed} from 'ng2-rx-componentdestroyed';
import {PathHelperService} from 'core-components/common/path-helper/path-helper.service';
import {WorkPackageCreateService} from './wp-create.service';
export class WorkPackageCreateController implements OnInit, OnDestroy {
public successState:string;
@ -90,10 +91,12 @@ export class WorkPackageCreateController implements OnInit, OnDestroy {
if (this.stateParams['parent_id']) {
this.wpCacheService.loadWorkPackage(this.stateParams['parent_id'])
.values$()
.takeUntil(componentDestroyed(this))
.pipe(
takeUntil(componentDestroyed(this))
)
.subscribe(parent => {
this.parentWorkPackage = parent;
});
this.parentWorkPackage = parent;
});
}
})
.catch((error:any) => {
@ -101,7 +104,7 @@ export class WorkPackageCreateController implements OnInit, OnDestroy {
this.RootDm.load().then((root:RootResource) => {
if (!root.user) {
// Not logged in
let url = URI(this.PathHelper.loginPath())
let url = URI(this.PathHelper.loginPath());
url.search({back_url: url});
window.location.href = url.toString();
}

@ -26,17 +26,16 @@
// See doc/COPYRIGHT.rdoc for more details.
// ++
import {Observable} from 'rxjs/Observable';
import {Subject} from 'rxjs/Subject';
import {wpServicesModule} from '../../angular-modules';
import {ApiWorkPackagesService} from '../api/api-work-packages/api-work-packages.service';
import {HalResource} from '../api/api-v3/hal-resources/hal-resource.service';
import {WorkPackageCacheService} from '../work-packages/work-package-cache.service';
import {Observable, Subject} from 'rxjs';
import {
WorkPackageResource,
WorkPackageResourceInterface
} from '../api/api-v3/hal-resources/work-package-resource.service';
import {input, State} from 'reactivestates';
import {WorkPackageEditingService} from '../wp-edit-form/work-package-editing-service';
import {ApiWorkPackagesService} from '../api/api-work-packages/api-work-packages.service';
import {WorkPackageCacheService} from '../work-packages/work-package-cache.service';
import {WorkPackageChangeset} from '../wp-edit-form/work-package-changeset';
export class WorkPackageCreateService {

@ -26,11 +26,12 @@
// See doc/COPYRIGHT.rdoc for more details.
//++
import {wpServicesModule} from '../../angular-modules';
import {input} from 'reactivestates';
import {distinctUntilChanged, filter} from 'rxjs/operators';
import {wpServicesModule} from '../../angular-modules';
export type QueryMenuEvent = {
event:'add'|'remove'|'rename';
event:'add' | 'remove' | 'rename';
queryId:string;
path?:string;
label?:string;
@ -41,27 +42,27 @@ export class QueryMenuService {
/**
* Add a query menu item
* @param {string} queryId
* @param {string} name
*/
public add(name:string, path:string, queryId:string) {
this.events.putValue({ event: 'add', queryId: queryId, path: path, label: name });
this.events.putValue({event: 'add', queryId: queryId, path: path, label: name});
}
public rename(queryId:string, name:string) {
this.events.putValue({ event: 'rename', queryId: queryId, label: name });
this.events.putValue({event: 'rename', queryId: queryId, label: name});
}
public remove(queryId:string) {
this.events.putValue({ event: 'remove', queryId: queryId, label: queryId });
this.events.putValue({event: 'remove', queryId: queryId, label: queryId});
}
public on(type:string) {
return this.events
.values$()
.filter((e:QueryMenuEvent) => e.event === type)
.distinctUntilChanged();
.pipe(
filter((e:QueryMenuEvent) => e.event === type),
distinctUntilChanged()
);
}
}
wpServicesModule.service('queryMenu', QueryMenuService)
wpServicesModule.service('queryMenu', QueryMenuService);

@ -26,10 +26,11 @@
// See doc/COPYRIGHT.rdoc for more details.
//++
import {wpDirectivesModule} from "../../../angular-modules";
import {scopedObservable} from "../../../helpers/angular-rx-utils";
import {WorkPackageResourceInterface} from "../../api/api-v3/hal-resources/work-package-resource.service";
import {WorkPackageCacheService} from "../../work-packages/work-package-cache.service";
import {take} from 'rxjs/operators';
import {wpDirectivesModule} from '../../../angular-modules';
import {scopedObservable} from '../../../helpers/angular-rx-utils';
import {WorkPackageResourceInterface} from '../../api/api-v3/hal-resources/work-package-resource.service';
import {WorkPackageCacheService} from '../../work-packages/work-package-cache.service';
export class WorkPackageRelationsHierarchyController {
public workPackage:WorkPackageResourceInterface;
@ -60,7 +61,9 @@ export class WorkPackageRelationsHierarchyController {
scopedObservable(
this.$scope,
this.wpCacheService.loadWorkPackage(this.workPackage.parent.id).values$())
.take(1)
.pipe(
take(1)
)
.subscribe((parent:WorkPackageResourceInterface) => {
this.workPackage.parent = parent;
});

@ -26,7 +26,10 @@
// See doc/COPYRIGHT.rdoc for more details.
//++
import {Observable} from 'rxjs';
import {StateService} from '@uirouter/core';
import {Observable} from 'rxjs/Observable';
import {zip} from 'rxjs/observable/zip';
import {take} from 'rxjs/operators';
import {wpDirectivesModule} from '../../angular-modules';
import {scopedObservable} from '../../helpers/angular-rx-utils';
import {RelationResourceInterface} from '../api/api-v3/hal-resources/relation-resource.service';
@ -34,7 +37,7 @@ import {WorkPackageResourceInterface} from '../api/api-v3/hal-resources/work-pac
import {WorkPackageCacheService} from '../work-packages/work-package-cache.service';
import {RelatedWorkPackagesGroup} from './wp-relations.interfaces';
import {RelationsStateValue, WorkPackageRelationsService} from './wp-relations.service';
import {StateService} from '@uirouter/core';
export class WorkPackageRelationsController {
public relationGroups:RelatedWorkPackagesGroup;
@ -43,7 +46,7 @@ export class WorkPackageRelationsController {
// By default, group by relation type
public groupByWorkPackageType = false;
public currentRelations:RelationResourceInterface[] = [];
public currentRelations:WorkPackageResourceInterface[] = [];
constructor(protected $scope:ng.IScope,
protected $q:ng.IQService,
@ -70,18 +73,12 @@ export class WorkPackageRelationsController {
});
}
protected getRelatedWorkPackages(workPackageIds:string[]) {
let observablesToGetZipped = workPackageIds.map(wpId => {
private getRelatedWorkPackages(workPackageIds:string[]):Observable<WorkPackageResourceInterface[]> {
let observablesToGetZipped:Observable<WorkPackageResourceInterface>[] = workPackageIds.map(wpId => {
return scopedObservable(this.$scope, this.wpCacheService.loadWorkPackage(wpId).values$());
});
if (observablesToGetZipped.length > 1) {
return Observable
.zip
.apply(Observable, observablesToGetZipped);
}
return observablesToGetZipped[0];
return zip(observablesToGetZipped);
}
protected getRelatedWorkPackageId(relation:RelationResourceInterface):string {
@ -126,12 +123,10 @@ export class WorkPackageRelationsController {
});
this.getRelatedWorkPackages(relatedWpIds)
.take(1)
.subscribe((relatedWorkPackages:any) => {
if (!angular.isArray(relatedWorkPackages)) {
relatedWorkPackages = [relatedWorkPackages];
}
.pipe(
take(1)
)
.subscribe((relatedWorkPackages:WorkPackageResourceInterface[]) => {
this.currentRelations = relatedWorkPackages.map((wp:WorkPackageResourceInterface) => {
wp.relatedBy = relations[wp.id];
return wp;

@ -26,13 +26,14 @@
// See doc/COPYRIGHT.rdoc for more details.
// ++
import {WorkPackageResourceInterface} from '../../api/api-v3/hal-resources/work-package-resource.service';
import {WorkPackageCacheService} from '../../work-packages/work-package-cache.service';
import {OnDestroy, OnInit} from '@angular/core';
import {componentDestroyed} from 'ng2-rx-componentdestroyed';
import {WorkPackagesActivityService} from 'core-components/wp-single-view-tabs/activity-panel/wp-activity.service';
import {HalResource} from 'core-components/api/api-v3/hal-resources/hal-resource.service';
import {ActivityEntryInfo} from 'core-components/wp-single-view-tabs/activity-panel/activity-entry-info';
import {WorkPackagesActivityService} from 'core-components/wp-single-view-tabs/activity-panel/wp-activity.service';
import {componentDestroyed} from 'ng2-rx-componentdestroyed';
import {takeUntil} from 'rxjs/operators';
import {WorkPackageResourceInterface} from '../../api/api-v3/hal-resources/work-package-resource.service';
import {WorkPackageCacheService} from '../../work-packages/work-package-cache.service';
export class ActivityPanelBaseController implements OnInit, OnDestroy {
public workPackage:WorkPackageResourceInterface;
@ -65,7 +66,9 @@ export class ActivityPanelBaseController implements OnInit, OnDestroy {
ngOnInit() {
this.wpCacheService.loadWorkPackage(this.workPackageId)
.values$()
.takeUntil(componentDestroyed(this))
.pipe(
takeUntil(componentDestroyed(this))
)
.subscribe((wp:WorkPackageResourceInterface) => {
this.workPackage = wp;
this.wpActivity.aggregateActivities(this.workPackage).then((activities:any) => {

@ -26,12 +26,13 @@
// See doc/COPYRIGHT.rdoc for more details.
// ++
import {ReplaySubject} from "rxjs";
import {Transition, StateService, TransitionService} from '@uirouter/core';
import {StateService, Transition, TransitionService} from '@uirouter/core';
import {ReplaySubject} from 'rxjs/ReplaySubject';
export class KeepTabService {
protected currentTab:string = 'overview';
protected subject = new ReplaySubject<{ [tab: string]: string; }>(1);
protected subject = new ReplaySubject<{ [tab:string]:string; }>(1);
constructor(public $state:StateService,
protected $transitions:TransitionService) {

@ -26,12 +26,14 @@
// See doc/COPYRIGHT.rdoc for more details.
// ++
import {Component, Inject, Input, OnDestroy} from '@angular/core';
import {Component, Inject, OnDestroy} from '@angular/core';
import {Transition} from '@uirouter/core';
import {I18nToken} from '../../../angular4-transition-utils';
import {WorkPackageCacheService} from 'core-components/work-packages/work-package-cache.service';
import {WorkPackageResourceInterface} from 'core-components/api/api-v3/hal-resources/work-package-resource.service';
import {WorkPackageCacheService} from 'core-components/work-packages/work-package-cache.service';
import {componentDestroyed} from 'ng2-rx-componentdestroyed';
import {takeUntil} from 'rxjs/operators';
import {I18nToken} from '../../../angular4-transition-utils';
@Component({
template: require('!!raw-loader!./overview-tab.html'),
selector: 'wp-overview-tab',
@ -48,7 +50,9 @@ export class WorkPackageOverviewTabComponent implements OnDestroy {
this.workPackageId = this.$transition.params('to').workPackageId;
wpCacheService.loadWorkPackage(this.workPackageId)
.values$()
.takeUntil(componentDestroyed(this))
.pipe(
takeUntil(componentDestroyed(this))
)
.subscribe((wp) => this.workPackage = wp);
}

@ -26,12 +26,13 @@
// See doc/COPYRIGHT.rdoc for more details.
// ++
import {Transition} from '@uirouter/core';
import {WorkPackageCacheService} from 'core-components/work-packages/work-package-cache.service';
import {Component, Inject, OnDestroy} from '@angular/core';
import {I18nToken} from '../../../angular4-transition-utils';
import {Transition} from '@uirouter/core';
import {WorkPackageResourceInterface} from 'core-components/api/api-v3/hal-resources/work-package-resource.service';
import {WorkPackageCacheService} from 'core-components/work-packages/work-package-cache.service';
import {componentDestroyed} from 'ng2-rx-componentdestroyed';
import {takeUntil} from 'rxjs/operators';
import {I18nToken} from '../../../angular4-transition-utils';
@Component({
template: require('!!raw-loader!./relations-tab.html'),
@ -48,7 +49,9 @@ export class WorkPackageRelationsTabComponent implements OnDestroy {
this.workPackageId = this.$transition.params('to').workPackageId;
wpCacheService.loadWorkPackage(this.workPackageId)
.values$()
.takeUntil(componentDestroyed(this))
.pipe(
takeUntil(componentDestroyed(this))
)
.subscribe((wp) => this.workPackage = wp);
}

@ -26,17 +26,18 @@
// See doc/COPYRIGHT.rdoc for more details.
// ++
import {Transition} from '@uirouter/core';
import {WorkPackageCacheService} from 'core-components/work-packages/work-package-cache.service';
import {Component, ElementRef, Inject, OnDestroy, OnInit} from '@angular/core';
import {I18nToken} from '../../../angular4-transition-utils';
import {WorkPackageResourceInterface} from 'core-components/api/api-v3/hal-resources/work-package-resource.service';
import {componentDestroyed} from 'ng2-rx-componentdestroyed';
import {HalResource} from 'core-components/api/api-v3/hal-resources/hal-resource.service';
import {Transition} from '@uirouter/core';
import {CollectionResource} from 'core-components/api/api-v3/hal-resources/collection-resource.service';
import {HalResource} from 'core-components/api/api-v3/hal-resources/hal-resource.service';
import {UserResource} from 'core-components/api/api-v3/hal-resources/user-resource.service';
import {WorkPackageNotificationService} from 'core-components/wp-edit/wp-notification.service';
import {WorkPackageResourceInterface} from 'core-components/api/api-v3/hal-resources/work-package-resource.service';
import {LoadingIndicatorService} from 'core-components/common/loading-indicator/loading-indicator.service';
import {WorkPackageCacheService} from 'core-components/work-packages/work-package-cache.service';
import {WorkPackageNotificationService} from 'core-components/wp-edit/wp-notification.service';
import {componentDestroyed} from 'ng2-rx-componentdestroyed';
import {takeUntil} from 'rxjs/operators';
import {I18nToken} from '../../../angular4-transition-utils';
@Component({
template: require('!!raw-loader!./watchers-tab.html'),
@ -77,7 +78,9 @@ export class WorkPackageWatchersTabComponent implements OnInit, OnDestroy {
this.workPackageId = this.$transition.params('to').workPackageId;
this.wpCacheService.loadWorkPackage(this.workPackageId)
.values$()
.takeUntil(componentDestroyed(this))
.pipe(
takeUntil(componentDestroyed(this))
)
.subscribe((wp) => {
this.workPackage = wp;
this.loadCurrentWatchers();
@ -127,7 +130,7 @@ export class WorkPackageWatchersTabComponent implements OnInit, OnDestroy {
} as any);
input.focus(() => input.autocomplete('search', input.val()));
(input.autocomplete("instance")as any)._renderItem = (ul:any, item:any) => this.renderWatcherItem(
(input.autocomplete('instance')as any)._renderItem = (ul:any, item:any) => this.renderWatcherItem(
ul,
item);
}
@ -155,7 +158,7 @@ export class WorkPackageWatchersTabComponent implements OnInit, OnDestroy {
if (item.watcher.avatar) {
const img = document.createElement('img');
img.src = item.watcher.avatar
img.src = item.watcher.avatar;
img.alt = item.watcher.name;
img.classList.add('avatar-mini');
@ -174,7 +177,7 @@ export class WorkPackageWatchersTabComponent implements OnInit, OnDestroy {
}
public autocompleteWatchers(query:string):Promise<any> {
let payload:any = {sortBy: JSON.stringify([["name", "asc"]])}
let payload:any = {sortBy: JSON.stringify([['name', 'asc']])};
if (query && query.length > 0) {
let filter = {
@ -182,7 +185,7 @@ export class WorkPackageWatchersTabComponent implements OnInit, OnDestroy {
operator: '~',
values: query,
}
}
};
payload['filters'] = JSON.stringify([filter]);
}

@ -34,6 +34,7 @@ import {
} from 'core-components/api/api-v3/hal-resources/query-sort-by-resource.service';
import {RelationQueryColumn, TypeRelationQueryColumn} from 'core-components/wp-query/query-column';
import {componentDestroyed} from 'ng2-rx-componentdestroyed';
import {takeUntil} from 'rxjs/operators';
import {WorkPackageTableHierarchiesService} from '../../wp-fast-table/state/wp-table-hierarchy.service';
import {WorkPackageTableRelationColumnsService} from '../../wp-fast-table/state/wp-table-relation-columns.service';
import {WorkPackageTableSortByService} from '../../wp-fast-table/state/wp-table-sort-by.service';
@ -89,7 +90,9 @@ export class SortHeaderDirective implements OnDestroy, AfterViewInit {
this.element = jQuery(this.elementRef.nativeElement);
this.wpTableSortBy.onReadyWithAvailable()
.takeUntil(componentDestroyed(this))
.pipe(
takeUntil(componentDestroyed(this))
)
.subscribe(() => {
let latestSortElement = this.wpTableSortBy.currentSortBys[0];
@ -132,14 +135,18 @@ export class SortHeaderDirective implements OnDestroy, AfterViewInit {
// Disable hierarchy mode when group by is active
this.wpTableGroupBy.state.values$()
.takeUntil(componentDestroyed(this))
.pipe(
takeUntil(componentDestroyed(this))
)
.subscribe(() => {
this.isHierarchyDisabled = this.wpTableGroupBy.isEnabled;
});
// Update hierarchy icon when updated elsewhere
this.wpTableHierarchies.state.values$()
.takeUntil(componentDestroyed(this))
.pipe(
takeUntil(componentDestroyed(this))
)
.subscribe(() => {
this.setHierarchyIcon();
});

@ -26,8 +26,8 @@
// See doc/COPYRIGHT.rdoc for more details.
// ++
import {BehaviorSubject} from 'rxjs';
import {PaginationService} from 'core-components/table-pagination/pagination-service';
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
describe.skip('wpTablePagination Directive', function () {
var compile:any, element:any, rootScope:any, scope:any, paginationService:PaginationService, paginationOptions:any;

@ -15,7 +15,8 @@ import {WorkPackageTableSum} from 'app/components/wp-fast-table/wp-table-sum';
import {WorkPackageTableTimelineState} from 'app/components/wp-fast-table/wp-table-timeline';
import {WPTableRowSelectionState} from 'app/components/wp-fast-table/wp-table.interfaces';
import {derive, input, State, StatesGroup} from 'reactivestates';
import {Subject} from 'rxjs/Rx';
import {map} from 'rxjs/operators';
import {Subject} from 'rxjs/Subject';
export class TableState extends StatesGroup {
@ -49,8 +50,9 @@ export class TableState extends StatesGroup {
// State to be updated when the table is up to date
rendered = input<RenderedRow[]>();
renderedWorkPackages:State<RenderedRow[]> = derive(this.rendered, $ => $
.map(rows => rows.filter(row => !!row.workPackageId)));
renderedWorkPackages:State<RenderedRow[]> = derive(this.rendered, $ => $.pipe(
map(rows => rows.filter(row => !!row.workPackageId)))
);
// State to determine timeline visibility
timelineVisible = input<WorkPackageTableTimelineState>();

@ -30,6 +30,7 @@ import {AfterViewInit, Component, ElementRef, Inject, Injector, OnDestroy} from
import {TableStateHolder} from 'core-components/wp-table/table-state/table-state';
import {Moment} from 'moment';
import {componentDestroyed} from 'ng2-rx-componentdestroyed';
import {filter, map, take, takeUntil, withLatestFrom} from 'rxjs/operators';
import {I18nToken, NotificationsServiceToken} from '../../../../angular4-transition-utils';
import {debugLog, timeOutput} from '../../../../helpers/debug_output';
import {TypeResource} from '../../../api/api-v3/hal-resources/type-resource.service';
@ -136,8 +137,10 @@ export class WorkPackageTimelineTableController implements AfterViewInit, OnDest
// Refresh timeline view after table rendered
this.tableState.get().rendered.values$()
.takeUntil(this.tableState.get().stopAllSubscriptions)
.filter(() => this.initialized)
.pipe(
takeUntil(this.tableState.get().stopAllSubscriptions),
filter(() => this.initialized)
)
.subscribe((orderedRows) => {
// Remember all visible rows in their order of appearance.
this.workPackageIdOrder = orderedRows.filter(row => !row.hidden);
@ -145,17 +148,21 @@ export class WorkPackageTimelineTableController implements AfterViewInit, OnDest
});
this.tableState.get().timelineAutoZoom.values$()
.takeUntil(this.tableState.get().stopAllSubscriptions)
.filter(() => this.initialized)
.filter((enabled:boolean) => enabled)
.pipe(
takeUntil(this.tableState.get().stopAllSubscriptions),
filter(() => this.initialized),
filter((enabled:boolean) => enabled)
)
.subscribe(() => {
this.refreshView();
});
// Refresh timeline view when becoming visible
this.tableState.get().timelineVisible.values$()
.filter((timelineState:WorkPackageTableTimelineState) => timelineState.isVisible)
.takeUntil(componentDestroyed(this))
.pipe(
filter((timelineState:WorkPackageTableTimelineState) => timelineState.isVisible),
takeUntil(componentDestroyed(this))
)
.subscribe((timelineState:WorkPackageTableTimelineState) => {
this.viewParameters.settings.zoomLevel = timelineState.zoomLevel;
this.debouncedRefresh();
@ -164,8 +171,10 @@ export class WorkPackageTimelineTableController implements AfterViewInit, OnDest
// Load the types whenever the timeline is first visible
// TODO: Load only necessary types from API
this.tableState.get().timelineVisible.values$()
.filter((timelineState) => timelineState.isVisible)
.take(1)
.pipe(
filter((timelineState) => timelineState.isVisible),
take(1)
)
.subscribe(() => {
TypeResource.loadAll().then(() => {
this.debouncedRefresh();
@ -249,11 +258,13 @@ export class WorkPackageTimelineTableController implements AfterViewInit, OnDest
updateOnWorkPackageChanges() {
this.states.workPackages.observeChange()
.withLatestFrom(this.tableState.get().timelineVisible.values$())
.takeUntil(componentDestroyed(this))
.filter(([, timelineState]) => this.initialized && timelineState.isVisible)
.map(([[wpId]]) => wpId)
.filter((wpId) => this.cellsRenderer.hasCell(wpId))
.pipe(
withLatestFrom(this.tableState.get().timelineVisible.values$()),
takeUntil(componentDestroyed(this)),
filter(([, timelineState]) => this.initialized && timelineState.isVisible),
map(([[wpId]]) => wpId),
filter((wpId) => this.cellsRenderer.hasCell(wpId))
)
.subscribe((wpId) => {
const viewParamsChanged = this.calculateViewParams(this._viewParameters);
if (viewParamsChanged) {
@ -361,9 +372,9 @@ export class WorkPackageTimelineTableController implements AfterViewInit, OnDest
// We may still have a reference to a row that, e.g., just got deleted
const workPackage = this.states.workPackages.get(wpId).value!;
const startDate = workPackage.startDate ? moment(workPackage.startDate) :currentParams.now;
const dueDate = workPackage.dueDate ? moment(workPackage.dueDate) :currentParams.now;
const date = workPackage.date ? moment(workPackage.date) :currentParams.now;
const startDate = workPackage.startDate ? moment(workPackage.startDate) : currentParams.now;
const dueDate = workPackage.dueDate ? moment(workPackage.dueDate) : currentParams.now;
const date = workPackage.date ? moment(workPackage.date) : currentParams.now;
// start date
newParams.dateDisplayStart = moment.min(

@ -30,7 +30,8 @@ import {Component, ElementRef, Injector, OnDestroy, OnInit} from '@angular/core'
import {TableStateHolder} from 'core-components/wp-table/table-state/table-state';
import {componentDestroyed} from 'ng2-rx-componentdestroyed';
import {State} from 'reactivestates';
import {Observable} from 'rxjs/Observable';
import {combineLatest} from 'rxjs/observable/combineLatest';
import {filter, map, take, takeUntil} from 'rxjs/operators';
import {States} from '../../../states.service';
import {RelationsStateValue, WorkPackageRelationsService} from '../../../wp-relations/wp-relations.service';
import {WorkPackageTimelineCell} from '../cells/wp-timeline-cell';
@ -119,13 +120,15 @@ export class WorkPackageTableTimelineRelations implements OnInit, OnDestroy {
*/
private setupRelationSubscription() {
// for all visible WorkPackage rows...
Observable.combineLatest(
combineLatest(
this.tableState.get().renderedWorkPackages.values$(),
this.tableState.get().timelineVisible.values$()
)
.filter(([rendered, timeline]) => timeline.isVisible)
.takeUntil(componentDestroyed(this))
.map(([rendered, _]) => rendered)
.pipe(
filter(([rendered, timeline]) => timeline.isVisible),
takeUntil(componentDestroyed(this)),
map(([rendered, _]) => rendered)
)
.subscribe(list => {
// ... make sure that the corresponding relations are loaded ...
const wps = _.compact(list.map(row => row.workPackageId) as string[]);
@ -137,7 +140,9 @@ export class WorkPackageTableTimelineRelations implements OnInit, OnDestroy {
// ... once they are loaded, display them.
relationsForWorkPackage.values$()
.take(1)
.pipe(
take(1)
)
.subscribe(() => {
this.renderWorkPackagesRelations([wpId]);
});
@ -146,8 +151,10 @@ export class WorkPackageTableTimelineRelations implements OnInit, OnDestroy {
// When a WorkPackage changes, redraw the corresponding relations
this.states.workPackages.observeChange()
.takeUntil(componentDestroyed(this))
.filter(() => this.tableState.get().timelineVisible.mapOr(v => v.visible, false))
.pipe(
takeUntil(componentDestroyed(this)),
filter(() => this.tableState.get().timelineVisible.mapOr(v => v.visible, false))
)
.subscribe(([workPackageId]) => {
this.renderWorkPackagesRelations([workPackageId]);
});

@ -29,6 +29,7 @@
import {AfterViewInit, Directive, ElementRef, Inject, Injector} from '@angular/core';
import {TableStateHolder} from 'core-components/wp-table/table-state/table-state';
import {combine} from 'reactivestates';
import {takeUntil} from 'rxjs/operators';
import {I18nToken} from '../../../angular4-transition-utils';
import {SchemaResource} from '../../api/api-v3/hal-resources/schema-resource.service';
import {WorkPackageCollectionResourceInterface} from '../../api/api-v3/hal-resources/wp-collection-resource.service';
@ -69,7 +70,9 @@ export class WorkPackageTableSumsRowController implements AfterViewInit {
this.tableState.get().sum
)
.values$()
.takeUntil(this.tableState.get().stopAllSubscriptions)
.pipe(
takeUntil(this.tableState.get().stopAllSubscriptions)
)
.subscribe(([columns, resource, sum]) => {
if (sum.isEnabled && resource.sumsSchema) {
resource.sumsSchema.$load().then((schema:SchemaResource) => {

@ -1,28 +1,45 @@
import IScope = angular.IScope;
import {Observable, Observer, Subscriber} from "rxjs";
import {TeardownLogic} from "rxjs/Subscription";
// export class ScopedOperator<T, R> {
// -- 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.
//
// constructor(public readonly scope: IScope) {
// }
// 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.
//
// call(subscriber: Subscriber<R>, source: any): TeardownLogic {
// const scoped = scopedObservable(this.scope, source);
// return scoped.subscribe();
// }
// }
// 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 IScope = angular.IScope;
import {Observable} from 'rxjs/Observable';
import {Observer} from 'rxjs/Observer';
export function runInScopeDigest(scope: IScope, fn: () => void) {
if (scope.$root.$$phase !== "$apply" && scope.$root.$$phase !== "$digest") {
export function runInScopeDigest(scope:IScope, fn:() => void) {
if (scope.$root.$$phase !== '$apply' && scope.$root.$$phase !== '$digest') {
scope.$apply(fn);
} else {
fn();
}
}
export function scopedObservable<T>(scope: IScope, observable: Observable<T>): Observable<T> {
return Observable.create((observer: Observer<T>) => {
export function scopedObservable<T>(scope:IScope, observable:Observable<T>):Observable<T> {
return Observable.create((observer:Observer<T>) => {
var disposable = observable.subscribe(
value => {
runInScopeDigest(scope, () => observer.next(value));
@ -35,27 +52,27 @@ export function scopedObservable<T>(scope: IScope, observable: Observable<T>): O
}
);
scope.$on("$destroy", () => {
scope.$on('$destroy', () => {
return disposable.unsubscribe();
});
});
}
export function asyncTest<T>(done: (error?: any) => void, fn: (value: T) => any): (T:any) => any {
return (value: T) => {
export function asyncTest<T>(done:(error?:any) => void, fn:(value:T) => any):(T:any) => any {
return (value:T) => {
try {
fn(value);
done();
} catch (err) {
done(err);
}
}
};
}
export function scopeDestroyed$(scope: IScope): Observable<IScope> {
export function scopeDestroyed$(scope:IScope):Observable<IScope> {
return Observable.create((s:Observer<IScope>) => {
scope.$on("$destroy", () => {
scope.$on('$destroy', () => {
s.next(scope);
s.complete();
});

File diff suppressed because it is too large Load Diff

@ -24,6 +24,7 @@
"sinon": "^1.17.5",
"sinon-chai": "^2.8.0",
"sorted-object": "^1.0.0",
"webpack-bundle-analyzer": "2.11.1",
"webpack-dev-server": "^1.6.5"
},
"dependencies": {

@ -39,6 +39,7 @@ var ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
var HappyPack = require('happypack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var CleanWebpackPlugin = require('clean-webpack-plugin');
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
var mode = (process.env['RAILS_ENV'] || 'production').toLowerCase();
var production = (mode !== 'development');
@ -288,7 +289,8 @@ function getWebpackMainConfig() {
),
// Restrict loaded moment locales to the ones we load from translations
new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, new RegExp('(' + localeIds.join('|') + ')\.js$', 'i'))
new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, new RegExp('(' + localeIds.join('|') + ')\.js$', 'i')),
new BundleAnalyzerPlugin()
]
};

Loading…
Cancel
Save