[ADF-4745] memory leak fixes (#4931)

* fix app-layout component

* fix card-view component

* fix cloud-layout service

* code fixes

* code fixes

* even more fixes

* even more fixes

* lint fixes

* test fixes

* fix code

* remove useless pipes

* fix code owners

* enable spellcheck for cloud components

* update test

* update test
This commit is contained in:
Denys Vuika
2019-07-16 15:56:00 +01:00
committed by Eugenio Romano
parent e2311ab045
commit 1abb9bfc89
98 changed files with 1581 additions and 1066 deletions

View File

@@ -16,16 +16,16 @@
*/
import { LogService, UserPreferencesService, UserPreferenceValues, UserProcessModel, FormFieldModel, FormModel } from '@alfresco/adf-core';
import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core';
import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation, OnDestroy } from '@angular/core';
import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core';
import { MOMENT_DATE_FORMATS, MomentDateAdapter } from '@alfresco/adf-core';
import moment from 'moment-es6';
import { Moment } from 'moment';
import { Observable, of } from 'rxjs';
import { Observable, of, Subject } from 'rxjs';
import { Form } from '../models/form.model';
import { TaskDetailsModel } from '../models/task-details.model';
import { TaskListService } from './../services/tasklist.service';
import { switchMap, defaultIfEmpty } from 'rxjs/operators';
import { switchMap, defaultIfEmpty, takeUntil } from 'rxjs/operators';
import { FormBuilder, AbstractControl, Validators, FormGroup, FormControl } from '@angular/forms';
@Component({
@@ -37,7 +37,7 @@ import { FormBuilder, AbstractControl, Validators, FormGroup, FormControl } from
{ provide: MAT_DATE_FORMATS, useValue: MOMENT_DATE_FORMATS }],
encapsulation: ViewEncapsulation.None
})
export class StartTaskComponent implements OnInit {
export class StartTaskComponent implements OnInit, OnDestroy {
public FORMAT_DATE: string = 'DD/MM/YYYY';
MAX_LENGTH: number = 255;
@@ -71,6 +71,8 @@ export class StartTaskComponent implements OnInit {
maxTaskNameLength: number = this.MAX_LENGTH;
loading = false;
private onDestroy$ = new Subject<boolean>();
/**
* Constructor
* @param auth
@@ -92,14 +94,21 @@ export class StartTaskComponent implements OnInit {
this.validateMaxTaskNameLength();
this.field = new FormFieldModel(new FormModel(), { id: this.assigneeId, value: this.assigneeId, placeholder: 'Assignee' });
this.userPreferencesService.select(UserPreferenceValues.Locale).subscribe((locale) => {
this.dateAdapter.setLocale(locale);
});
this.userPreferencesService
.select(UserPreferenceValues.Locale)
.pipe(takeUntil(this.onDestroy$))
.subscribe(locale => this.dateAdapter.setLocale(locale));
this.loadFormsTask();
this.buildForm();
}
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
buildForm() {
this.taskForm = this.formBuilder.group({
name: new FormControl(this.taskDetailsModel.name, [Validators.required, Validators.maxLength(this.maxTaskNameLength), this.whitespaceValidator]),
@@ -107,7 +116,9 @@ export class StartTaskComponent implements OnInit {
formKey: new FormControl('')
});
this.taskForm.valueChanges.subscribe((taskFormValues) => this.setTaskDetails(taskFormValues));
this.taskForm.valueChanges
.pipe(takeUntil(this.onDestroy$))
.subscribe(taskFormValues => this.setTaskDetails(taskFormValues));
}
public whitespaceValidator(control: FormControl) {

View File

@@ -33,23 +33,24 @@ import {
Output,
SimpleChanges,
TemplateRef,
ViewChild
ViewChild,
OnDestroy
} from '@angular/core';
import { MatDialog, MatDialogRef } from '@angular/material';
import { Observable, Observer } from 'rxjs';
import { Observable, Observer, Subject } from 'rxjs';
import { ContentLinkModel, FormFieldValidator, FormModel, FormOutcomeEvent } from '@alfresco/adf-core';
import { TaskQueryRequestRepresentationModel } from '../models/filter.model';
import { TaskDetailsModel } from '../models/task-details.model';
import { TaskListService } from './../services/tasklist.service';
import { UserRepresentation } from '@alfresco/js-api';
import { share } from 'rxjs/operators';
import { share, takeUntil } from 'rxjs/operators';
@Component({
selector: 'adf-task-details',
templateUrl: './task-details.component.html',
styleUrls: ['./task-details.component.scss']
})
export class TaskDetailsComponent implements OnInit, OnChanges {
export class TaskDetailsComponent implements OnInit, OnChanges, OnDestroy {
@ViewChild('activitiComments')
activitiComments: CommentsComponent;
@@ -166,17 +167,15 @@ export class TaskDetailsComponent implements OnInit, OnChanges {
taskDetails: TaskDetailsModel;
taskFormName: string = null;
taskPeople: UserProcessModel[] = [];
noTaskDetailsTemplateComponent: TemplateRef<any>;
showAssignee: boolean = false;
showAttachForm: boolean = false;
internalReadOnlyForm: boolean = false;
private peopleSearchObserver: Observer<UserProcessModel[]>;
public errorDialogRef: MatDialogRef<TemplateRef<any>>;
private onDestroy$ = new Subject<boolean>();
peopleSearch: Observable<UserProcessModel[]>;
@@ -189,21 +188,30 @@ export class TaskDetailsComponent implements OnInit, OnChanges {
private logService: LogService,
private cardViewUpdateService: CardViewUpdateService,
private dialog: MatDialog) {
this.peopleSearch = new Observable<UserProcessModel[]>((observer) => this.peopleSearchObserver = observer)
.pipe(share());
this.authService.getBpmLoggedUser().subscribe((user: UserRepresentation) => {
this.currentLoggedUser = user;
});
}
ngOnInit() {
this.peopleSearch = new Observable<UserProcessModel[]>((observer) => this.peopleSearchObserver = observer).pipe(share());
this.authService.getBpmLoggedUser().subscribe(user => {
this.currentLoggedUser = user;
});
if (this.taskId) {
this.loadDetails(this.taskId);
}
this.cardViewUpdateService.itemUpdated$.subscribe(this.updateTaskDetails.bind(this));
this.cardViewUpdateService.itemClicked$.subscribe(this.clickTaskDetails.bind(this));
this.cardViewUpdateService.itemUpdated$
.pipe(takeUntil(this.onDestroy$))
.subscribe(this.updateTaskDetails.bind(this));
this.cardViewUpdateService.itemClicked$
.pipe(takeUntil(this.onDestroy$))
.subscribe(this.clickTaskDetails.bind(this));
}
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
ngOnChanges(changes: SimpleChanges): void {
@@ -265,12 +273,9 @@ export class TaskDetailsComponent implements OnInit, OnChanges {
* @param updateNotification
*/
private updateTaskDetails(updateNotification: UpdateNotification) {
this.taskListService.updateTask(this.taskId, updateNotification.changed)
.subscribe(
() => {
this.loadDetails(this.taskId);
}
);
this.taskListService
.updateTask(this.taskId, updateNotification.changed)
.subscribe(() => this.loadDetails(this.taskId));
}
private clickTaskDetails(clickNotification: ClickNotification) {
@@ -386,9 +391,9 @@ export class TaskDetailsComponent implements OnInit, OnChanges {
* Complete button clicked
*/
onComplete(): void {
this.taskListService.completeTask(this.taskId).subscribe(
(res) => this.onFormCompleted(null)
);
this.taskListService
.completeTask(this.taskId)
.subscribe(() => this.onFormCompleted(null));
}
onShowAttachForm() {
@@ -461,10 +466,13 @@ export class TaskDetailsComponent implements OnInit, OnChanges {
searchUser(searchedWord: string) {
this.peopleProcessService.getWorkflowUsers(null, searchedWord)
.subscribe((users) => {
users = users.filter((user) => user.id !== this.taskDetails.assignee.id);
this.peopleSearchObserver.next(users);
}, (error) => this.logService.error('Could not load users'));
.subscribe(
users => {
users = users.filter((user) => user.id !== this.taskDetails.assignee.id);
this.peopleSearchObserver.next(users);
},
() => this.logService.error('Could not load users')
);
}
onCloseSearch() {
@@ -472,8 +480,9 @@ export class TaskDetailsComponent implements OnInit, OnChanges {
}
assignTaskToUser(selectedUser: UserProcessModel) {
this.taskListService.assignTask(this.taskDetails.id, selectedUser).subscribe(
(res: any) => {
this.taskListService
.assignTask(this.taskDetails.id, selectedUser)
.subscribe(() => {
this.logService.info('Task Assigned to ' + selectedUser.email);
this.assignTask.emit();
});

View File

@@ -285,11 +285,10 @@ export class TaskHeaderComponent implements OnChanges, OnInit {
* @param taskId
*/
claimTask(taskId: string) {
this.activitiTaskService.claimTask(taskId).subscribe(
(res: any) => {
this.logService.info('Task claimed');
this.claim.emit(taskId);
});
this.activitiTaskService.claimTask(taskId).subscribe(() => {
this.logService.info('Task claimed');
this.claim.emit(taskId);
});
}
/**
@@ -298,11 +297,10 @@ export class TaskHeaderComponent implements OnChanges, OnInit {
* @param taskId
*/
unclaimTask(taskId: string) {
this.activitiTaskService.unclaimTask(taskId).subscribe(
(res: any) => {
this.logService.info('Task unclaimed');
this.unclaim.emit(taskId);
});
this.activitiTaskService.unclaimTask(taskId).subscribe(() => {
this.logService.info('Task unclaimed');
this.unclaim.emit(taskId);
});
}
/**

View File

@@ -21,21 +21,22 @@ import {
UserPreferencesService, UserPreferenceValues, PaginationModel } from '@alfresco/adf-core';
import {
AfterContentInit, Component, ContentChild, EventEmitter,
Input, OnChanges, Output, SimpleChanges } from '@angular/core';
Input, OnChanges, Output, SimpleChanges, OnDestroy, OnInit } from '@angular/core';
import { Observable, BehaviorSubject } from 'rxjs';
import { Observable, BehaviorSubject, Subject } from 'rxjs';
import { TaskQueryRequestRepresentationModel } from '../models/filter.model';
import { TaskListModel } from '../models/task-list.model';
import { taskPresetsDefaultModel } from '../models/task-preset.model';
import { TaskListService } from './../services/tasklist.service';
import moment from 'moment-es6';
import { takeUntil } from 'rxjs/operators';
@Component({
selector: 'adf-tasklist',
templateUrl: './task-list.component.html',
styleUrls: ['./task-list.component.css']
})
export class TaskListComponent extends DataTableSchema implements OnChanges, AfterContentInit, PaginatedComponent {
export class TaskListComponent extends DataTableSchema implements OnChanges, AfterContentInit, PaginatedComponent, OnDestroy, OnInit {
static PRESET_KEY = 'adf-task-list.presets';
@@ -170,13 +171,12 @@ export class TaskListComponent extends DataTableSchema implements OnChanges, Aft
*/
hasCustomDataSource: boolean = false;
private onDestroy$ = new Subject<boolean>();
constructor(private taskListService: TaskListService,
appConfigService: AppConfigService,
private userPreferences: UserPreferencesService) {
super(appConfigService, TaskListComponent.PRESET_KEY, taskPresetsDefaultModel);
this.userPreferences.select(UserPreferenceValues.PaginationSize).subscribe((pageSize) => {
this.size = pageSize;
});
this.pagination = new BehaviorSubject<PaginationModel>(<PaginationModel> {
maxItems: this.size,
@@ -196,6 +196,18 @@ export class TaskListComponent extends DataTableSchema implements OnChanges, Aft
}
}
ngOnInit() {
this.userPreferences
.select(UserPreferenceValues.PaginationSize)
.pipe(takeUntil(this.onDestroy$))
.subscribe(pageSize => this.size = pageSize);
}
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
setCustomDataSource(rows: any[]): void {
if (rows) {
this.rows = rows;