[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

@@ -56,7 +56,7 @@ describe('AttachFileCloudWidgetComponent', () => {
}
};
const contentSourceparam = {
const contentSourceParam = {
fileSource: {
name: 'mock-alf-content',
serviceId: 'alfresco-content'
@@ -130,7 +130,7 @@ describe('AttachFileCloudWidgetComponent', () => {
value: []
});
widget.field.id = 'attach-file-alfresco';
widget.field.params = <FormFieldMetadata> contentSourceparam;
widget.field.params = <FormFieldMetadata> contentSourceParam;
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(element.querySelector('.adf-attach-widget__menu-upload')).not.toBeNull();
@@ -144,7 +144,7 @@ describe('AttachFileCloudWidgetComponent', () => {
value: []
});
widget.field.id = 'attach-file-alfresco';
widget.field.params = <FormFieldMetadata> contentSourceparam;
widget.field.params = <FormFieldMetadata> contentSourceParam;
fixture.detectChanges();
fixture.whenStable().then(() => {
const attachButton: HTMLButtonElement = element.querySelector('#attach-file-alfresco');

View File

@@ -88,8 +88,8 @@ describe('EditProcessFilterCloudComponent', () => {
});
it('should fetch process instance filter by id', async(() => {
const processFilterIDchange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIDchange });
const processFilterIdChange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIdChange });
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
@@ -103,8 +103,8 @@ describe('EditProcessFilterCloudComponent', () => {
}));
it('should display filter name as title', async(() => {
const processFilterIDchange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIDchange });
const processFilterIdChange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIdChange });
fixture.detectChanges();
const title = fixture.debugElement.nativeElement.querySelector('#adf-edit-process-filter-title-id');
const subTitle = fixture.debugElement.nativeElement.querySelector('#adf-edit-process-filter-sub-title-id');
@@ -118,8 +118,8 @@ describe('EditProcessFilterCloudComponent', () => {
}));
it('should not display mat-spinner if isloading set to false', async(() => {
const processFilterIDchange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIDchange });
const processFilterIdChange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIdChange });
fixture.detectChanges();
const title = fixture.debugElement.nativeElement.querySelector('#adf-edit-process-filter-title-id');
const subTitle = fixture.debugElement.nativeElement.querySelector('#adf-edit-process-filter-sub-title-id');
@@ -136,8 +136,8 @@ describe('EditProcessFilterCloudComponent', () => {
it('should display mat-spinner if isloading set to true', async(() => {
component.isLoading = true;
const processFilterIDchange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIDchange });
const processFilterIdChange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIdChange });
fixture.detectChanges();
const matSpinnerElement = fixture.debugElement.nativeElement.querySelector('.adf-cloud-edit-process-filter-loading-margin');
@@ -150,8 +150,8 @@ describe('EditProcessFilterCloudComponent', () => {
describe('EditProcessFilter form', () => {
beforeEach(() => {
const processFilterIDchange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIDchange });
const processFilterIdChange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIdChange });
fixture.detectChanges();
});
@@ -245,14 +245,17 @@ describe('EditProcessFilterCloudComponent', () => {
it('should display state drop down', async(() => {
fixture.detectChanges();
const expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header');
expansionPanel.click();
const stateElement = fixture.debugElement.nativeElement.querySelector('[data-automation-id="adf-cloud-edit-process-property-status"] .mat-select-trigger');
stateElement.click();
fixture.detectChanges();
fixture.whenStable().then(() => {
const statusOptions = fixture.debugElement.queryAll(By.css('.mat-option-text'));
expect(statusOptions.length).toEqual(3);
expect(statusOptions.length).toEqual(6);
});
}));
@@ -287,8 +290,8 @@ describe('EditProcessFilterCloudComponent', () => {
fixture.detectChanges();
component.filterProperties = ['appName', 'processName'];
fixture.detectChanges();
const processFilterIDchange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIDchange });
const processFilterIdChange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIdChange });
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
@@ -302,8 +305,8 @@ describe('EditProcessFilterCloudComponent', () => {
fixture.detectChanges();
component.filterProperties = [];
fixture.detectChanges();
const processFilterIDchange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIDchange });
const processFilterIdChange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIdChange });
fixture.detectChanges();
fixture.whenStable().then(() => {
const stateController = component.editProcessFilterForm.get('status');
@@ -330,8 +333,8 @@ describe('EditProcessFilterCloudComponent', () => {
fixture.detectChanges();
component.filterProperties = ['appName', 'processName'];
fixture.detectChanges();
const processFilterIDchange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIDchange });
const processFilterIdChange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIdChange });
fixture.detectChanges();
const appController = component.editProcessFilterForm.get('appName');
fixture.detectChanges();
@@ -343,8 +346,8 @@ describe('EditProcessFilterCloudComponent', () => {
}));
it('should display default sort properties', async(() => {
const processFilterIdchange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIdchange });
const processFilterIdChange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIdChange });
fixture.detectChanges();
const expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header');
expansionPanel.click();
@@ -373,8 +376,8 @@ describe('EditProcessFilterCloudComponent', () => {
}));
component.sortProperties = ['id', 'processName', 'processDefinitionId'];
fixture.detectChanges();
const processFilterIdchange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIdchange });
const processFilterIdChange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIdChange });
fixture.detectChanges();
const expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header');
expansionPanel.click();
@@ -396,8 +399,8 @@ describe('EditProcessFilterCloudComponent', () => {
describe('edit filter actions', () => {
beforeEach(() => {
const processFilterIDchange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIDchange });
const processFilterIdChange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIdChange });
getProcessFilterByIdSpy.and.returnValue(of(fakeFilter));
fixture.detectChanges();
});
@@ -425,9 +428,9 @@ describe('EditProcessFilterCloudComponent', () => {
});
}));
it('should emit delete event and delete the filter on click of delete button', async(() => {
it('should emit delete event and delete the filter on click of delete button', (done) => {
component.toggleFilterActions = true;
const deleteFilterSpy = spyOn(service, 'deleteFilter').and.returnValue(of());
const deleteFilterSpy = spyOn(service, 'deleteFilter').and.returnValue(of({}));
const deleteSpy: jasmine.Spy = spyOn(component.action, 'emit');
fixture.detectChanges();
@@ -442,9 +445,14 @@ describe('EditProcessFilterCloudComponent', () => {
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(deleteFilterSpy).toHaveBeenCalled();
expect(deleteSpy).toHaveBeenCalled();
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(deleteSpy).toHaveBeenCalled();
done();
});
});
}));
});
it('should emit saveAs event and add filter on click saveAs button', async(() => {
component.toggleFilterActions = true;
@@ -497,8 +505,8 @@ describe('EditProcessFilterCloudComponent', () => {
fixture.detectChanges();
component.actions = ['save'];
fixture.detectChanges();
const processFilterIDchange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIDchange });
const processFilterIdChange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIdChange });
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(component.processFilterActions).toBeDefined();
@@ -534,8 +542,8 @@ describe('EditProcessFilterCloudComponent', () => {
it('should set the correct lastModifiedTo date', (done) => {
component.appName = 'fake';
component.filterProperties = ['appName', 'processInstanceId', 'priority', 'lastModified'];
const taskFilterIDchange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIDchange });
const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIdChange });
fixture.detectChanges();
const lastModifiedToControl: AbstractControl = component.editProcessFilterForm.get('lastModifiedTo');

View File

@@ -18,12 +18,11 @@
import { Component, Input, Output, EventEmitter, OnInit, OnChanges, SimpleChanges, OnDestroy } from '@angular/core';
import { FormGroup, FormBuilder, AbstractControl } from '@angular/forms';
import { MatDialog, DateAdapter } from '@angular/material';
import { debounceTime, filter, takeUntil } from 'rxjs/operators';
import { debounceTime, filter, takeUntil, finalize } from 'rxjs/operators';
import { Subject } from 'rxjs';
import moment from 'moment-es6';
import { Moment } from 'moment';
import { ApplicationInstanceModel } from '../../../app/models/application-instance.model';
import { AppsProcessCloudService } from '../../../app/services/apps-process-cloud.service';
import { ProcessFilterCloudModel, ProcessFilterProperties, ProcessFilterAction, ProcessFilterOptions } from '../models/process-filter-cloud.model';
import { TranslationService, UserPreferencesService, UserPreferenceValues } from '@alfresco/adf-core';
@@ -120,9 +119,10 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes
private appsProcessCloudService: AppsProcessCloudService) { }
ngOnInit() {
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));
}
ngOnChanges(changes: SimpleChanges) {
@@ -153,16 +153,15 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes
*/
retrieveProcessFilterAndBuildForm() {
this.isLoading = true;
this.processFilterCloudService.getFilterById(this.appName, this.id)
.pipe(takeUntil(this.onDestroy$)).subscribe((response) => {
this.isLoading = false;
this.processFilter = new ProcessFilterCloudModel(response);
this.processFilterProperties = this.createAndFilterProperties();
this.processFilterActions = this.createAndFilterActions();
this.buildForm(this.processFilterProperties);
}, (error) => {
this.isLoading = false;
});
this.processFilterCloudService
.getFilterById(this.appName, this.id)
.pipe(finalize(() => this.isLoading = false))
.subscribe(response => {
this.processFilter = new ProcessFilterCloudModel(response);
this.processFilterProperties = this.createAndFilterProperties();
this.processFilterActions = this.createAndFilterActions();
this.buildForm(this.processFilterProperties);
});
}
/**
@@ -170,7 +169,11 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes
*/
onFilterChange() {
this.editProcessFilterForm.valueChanges
.pipe(debounceTime(500), filter(() => this.isFormValid()))
.pipe(
debounceTime(500),
filter(() => this.isFormValid()),
takeUntil(this.onDestroy$)
)
.subscribe((formValues: ProcessFilterCloudModel) => {
this.setLastModifiedToFilter(formValues);
this.changedProcessFilter = new ProcessFilterCloudModel(Object.assign({}, this.processFilter, formValues));
@@ -292,8 +295,9 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes
}
getRunningApplications() {
this.appsProcessCloudService.getDeployedApplicationsByStatus(EditProcessFilterCloudComponent.APP_RUNNING_STATUS)
.pipe(takeUntil(this.onDestroy$)).subscribe((applications: ApplicationInstanceModel[]) => {
this.appsProcessCloudService
.getDeployedApplicationsByStatus(EditProcessFilterCloudComponent.APP_RUNNING_STATUS)
.subscribe(applications => {
if (applications && applications.length > 0) {
applications.map((application) => {
this.applicationNames.push({ label: application.name, value: application.name });
@@ -316,23 +320,25 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes
* Save a process instance filter
*/
save(saveAction: ProcessFilterAction) {
this.processFilterCloudService.updateFilter(this.changedProcessFilter)
.pipe(takeUntil(this.onDestroy$)).subscribe((res) => {
saveAction.filter = this.changedProcessFilter;
this.action.emit(saveAction);
this.formHasBeenChanged = this.compareFilters(this.changedProcessFilter, this.processFilter);
});
this.processFilterCloudService
.updateFilter(this.changedProcessFilter)
.subscribe(() => {
saveAction.filter = this.changedProcessFilter;
this.action.emit(saveAction);
this.formHasBeenChanged = this.compareFilters(this.changedProcessFilter, this.processFilter);
});
}
/**
* Delete a process instance filter
*/
delete(deleteAction: ProcessFilterAction) {
this.processFilterCloudService.deleteFilter(this.processFilter)
.pipe(takeUntil(this.onDestroy$)).subscribe((res) => {
deleteAction.filter = this.processFilter;
this.action.emit(deleteAction);
});
this.processFilterCloudService
.deleteFilter(this.processFilter)
.subscribe(() => {
deleteAction.filter = this.processFilter;
this.action.emit(deleteAction);
});
}
/**
@@ -357,11 +363,12 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes
key: 'custom-' + filterKey
};
const resultFilter: ProcessFilterCloudModel = Object.assign({}, this.changedProcessFilter, newFilter);
this.processFilterCloudService.addFilter(resultFilter)
.pipe(takeUntil(this.onDestroy$)).subscribe((res) => {
saveAsAction.filter = resultFilter;
this.action.emit(saveAsAction);
});
this.processFilterCloudService
.addFilter(resultFilter)
.subscribe(() => {
saveAsAction.filter = resultFilter;
this.action.emit(saveAsAction);
});
}
});
}

View File

@@ -50,7 +50,7 @@ export class ProcessFilterCloudService {
} else if (!this.hasProcessFilters(preferences, key)) {
return this.createProcessFilters(appName, key, this.defaultProcessFilters(appName));
} else {
return of(this.findFiltersByKeyInPrefrences(preferences, key));
return of(this.findFiltersByKeyInPreferences(preferences, key));
}
}),
catchError((err) => this.handleProcessError(err))
@@ -97,7 +97,7 @@ export class ProcessFilterCloudService {
/**
* Adds a new process instance filter
* @param filter The new filter to add
* @returns Obervable of process instance filters with newly added filter
* @returns Observable of process instance filters with newly added filter
*/
addFilter(newFilter: ProcessFilterCloudModel): Observable<ProcessFilterCloudModel[]> {
const key: string = this.prepareKey(newFilter.appName);
@@ -233,7 +233,7 @@ export class ProcessFilterCloudService {
* @param appName Name of the target app
* @returns Array of ProcessFilterCloudModel
*/
private findFiltersByKeyInPrefrences(preferences: any, key: string): ProcessFilterCloudModel[] {
private findFiltersByKeyInPreferences(preferences: any, key: string): ProcessFilterCloudModel[] {
const result = preferences.find((filter: any) => { return filter.entry.key === key; });
return result && result.entry ? JSON.parse(result.entry.value) : [];
}

View File

@@ -25,7 +25,7 @@ describe('Activiti ProcessList Cloud Service', () => {
let service: ProcessListCloudService;
let alfrescoApiMock: AlfrescoApiServiceMock;
function returFakeProcessListResults() {
function returnFakeProcessListResults() {
return {
oauth2Auth: {
callCustomApi: () => {
@@ -70,7 +70,7 @@ describe('Activiti ProcessList Cloud Service', () => {
it('should return the processes', (done) => {
const processRequest: ProcessQueryCloudRequestModel = <ProcessQueryCloudRequestModel> { appName: 'fakeName' };
spyOn(alfrescoApiMock, 'getInstance').and.callFake(returFakeProcessListResults);
spyOn(alfrescoApiMock, 'getInstance').and.callFake(returnFakeProcessListResults);
service.getProcessByRequest(processRequest).subscribe((res) => {
expect(res).toBeDefined();
expect(res).not.toBeNull();

View File

@@ -82,10 +82,10 @@ export class ProcessListCloudService extends BaseCloudService {
return property === 'appName' || property === 'sorting';
}
private buildSortingParam(sortings: ProcessListCloudSortingModel[]): string {
private buildSortingParam(models: ProcessListCloudSortingModel[]): string {
let finalSorting: string = '';
if (sortings) {
for (const sort of sortings) {
if (models) {
for (const sort of models) {
if (!finalSorting) {
finalSorting = `${sort.orderBy},${sort.direction}`;
} else {

View File

@@ -16,9 +16,9 @@
*/
import { FormControl } from '@angular/forms';
import { Component, OnInit, Output, EventEmitter, ViewEncapsulation, Input, ViewChild, ElementRef, SimpleChanges, OnChanges } from '@angular/core';
import { Observable, of, BehaviorSubject } from 'rxjs';
import { switchMap, debounceTime, distinctUntilChanged, mergeMap, tap, filter, map } from 'rxjs/operators';
import { Component, OnInit, Output, EventEmitter, ViewEncapsulation, Input, ViewChild, ElementRef, SimpleChanges, OnChanges, OnDestroy } from '@angular/core';
import { Observable, of, BehaviorSubject, Subject } from 'rxjs';
import { switchMap, debounceTime, distinctUntilChanged, mergeMap, tap, filter, map, takeUntil } from 'rxjs/operators';
import { FullNamePipe, IdentityUserModel, IdentityUserService, LogService } from '@alfresco/adf-core';
import { trigger, state, style, transition, animate } from '@angular/animations';
@@ -39,7 +39,7 @@ import { trigger, state, style, transition, animate } from '@angular/animations'
encapsulation: ViewEncapsulation.None
})
export class PeopleCloudComponent implements OnInit, OnChanges {
export class PeopleCloudComponent implements OnInit, OnChanges, OnDestroy {
static MODE_SINGLE = 'single';
static MODE_MULTIPLE = 'multiple';
@@ -98,15 +98,13 @@ export class PeopleCloudComponent implements OnInit, OnChanges {
private _searchUsers: IdentityUserModel[] = [];
private selectedUsersSubject: BehaviorSubject<IdentityUserModel[]>;
private searchUsersSubject: BehaviorSubject<IdentityUserModel[]>;
private onDestroy$ = new Subject<boolean>();
selectedUsers$: Observable<IdentityUserModel[]>;
searchUsers$: Observable<IdentityUserModel[]>;
_subscriptAnimationState: string = 'enter';
clientId: string;
isFocused: boolean;
invalidUsers: IdentityUserModel[] = [];
constructor(private identityUserService: IdentityUserService, private logService: LogService) {
@@ -141,6 +139,11 @@ export class PeopleCloudComponent implements OnInit, OnChanges {
}
}
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
initSubjects() {
if (this.selectedUsersSubject === undefined) {
this.selectedUsersSubject = new BehaviorSubject<IdentityUserModel[]>(this.preSelectUsers);
@@ -239,11 +242,11 @@ export class PeopleCloudComponent implements OnInit, OnChanges {
});
}
public userExists(result: any): boolean {
public userExists(result: IdentityUserModel): boolean {
return result
&& (result.id !== undefined
|| result.username !== undefined
|| result.amil !== undefined);
|| result.email !== undefined);
}
private initSearch() {
@@ -285,8 +288,9 @@ export class PeopleCloudComponent implements OnInit, OnChanges {
} else {
return of(user);
}
})
).subscribe((user) => {
}),
takeUntil(this.onDestroy$)
).subscribe((user: any) => {
this._searchUsers.push(user);
this.searchUsersSubject.next(this._searchUsers);
});

View File

@@ -19,7 +19,7 @@ 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, Subscription } from 'rxjs';
import { Observable, Subject } from 'rxjs';
import { FormBuilder, AbstractControl, Validators, FormGroup, FormControl } from '@angular/forms';
import {
LogService,
@@ -32,6 +32,7 @@ import { PeopleCloudComponent } from './people-cloud/people-cloud.component';
import { GroupCloudComponent } from '../../../../lib/group/components/group-cloud.component';
import { TaskCloudService } from '../../services/task-cloud.service';
import { StartTaskCloudRequestModel } from '../models/start-task-cloud-request.model';
import { takeUntil } from 'rxjs/operators';
@Component({
selector: 'adf-cloud-start-task',
@@ -101,9 +102,7 @@ export class StartTaskCloudComponent implements OnInit, OnDestroy {
private assigneeForm: AbstractControl = new FormControl('');
private groupForm: AbstractControl = new FormControl('');
private localeSub: Subscription;
private createTaskSub: Subscription;
private onDestroy$ = new Subject<boolean>();
constructor(private taskService: TaskCloudService,
private dateAdapter: DateAdapter<Moment>,
@@ -114,21 +113,17 @@ export class StartTaskCloudComponent implements OnInit, OnDestroy {
}
ngOnInit() {
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.loadCurrentUser();
this.buildForm();
}
ngOnDestroy() {
if (this.localeSub) {
this.localeSub.unsubscribe();
}
if (this.createTaskSub) {
this.createTaskSub.unsubscribe();
}
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
buildForm() {
@@ -162,7 +157,7 @@ export class StartTaskCloudComponent implements OnInit, OnDestroy {
}
private createNewTask(newTask: StartTaskCloudRequestModel) {
this.createTaskSub = this.taskService.createNewTask(newTask, this.appName)
this.taskService.createNewTask(newTask, this.appName)
.subscribe(
(res: any) => {
this.submitted = false;

View File

@@ -70,8 +70,8 @@ describe('EditTaskFilterCloudComponent', () => {
});
it('should fetch task filter by taskId', () => {
const taskFilterIDchange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIDchange});
const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIdChange});
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(getTaskFilterSpy).toHaveBeenCalled();
@@ -84,8 +84,8 @@ describe('EditTaskFilterCloudComponent', () => {
});
it('should display filter name as title', async(() => {
const taskFilterIDchange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIDchange});
const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIdChange});
fixture.detectChanges();
const title = fixture.debugElement.nativeElement.querySelector('#adf-edit-task-filter-title-id');
const subTitle = fixture.debugElement.nativeElement.querySelector('#adf-edit-task-filter-sub-title-id');
@@ -96,8 +96,8 @@ describe('EditTaskFilterCloudComponent', () => {
}));
it('should not display mat-spinner if isloading set to false', async(() => {
const taskFilterIDchange = new SimpleChange(null, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIDchange });
const taskFilterIdChange = new SimpleChange(null, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIdChange });
fixture.detectChanges();
const title = fixture.debugElement.nativeElement.querySelector('#adf-edit-task-filter-title-id');
const subTitle = fixture.debugElement.nativeElement.querySelector('#adf-edit-task-filter-sub-title-id');
@@ -114,8 +114,8 @@ describe('EditTaskFilterCloudComponent', () => {
it('should display mat-spinner if isloading set to true', async(() => {
component.isLoading = true;
const taskFilterIDchange = new SimpleChange(null, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIDchange });
const taskFilterIdChange = new SimpleChange(null, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIdChange });
fixture.detectChanges();
const matSpinnerElement = fixture.debugElement.nativeElement.querySelector('.adf-cloud-edit-task-filter-loading-margin');
@@ -128,8 +128,8 @@ describe('EditTaskFilterCloudComponent', () => {
describe('EditTaskFilter form', () => {
beforeEach(() => {
const taskFilterIDchange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({'id': taskFilterIDchange});
const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({'id': taskFilterIdChange});
fixture.detectChanges();
});
@@ -229,8 +229,8 @@ describe('EditTaskFilterCloudComponent', () => {
getTaskFilterSpy.and.returnValue(of(fakeAllTaskFilter));
const taskFilterIDchange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIDchange});
const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIdChange});
fixture.detectChanges();
const expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header');
@@ -275,8 +275,8 @@ describe('EditTaskFilterCloudComponent', () => {
}));
it('should able to build a editTaskFilter form with default properties if input is empty', async(() => {
const taskFilterIDchange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIDchange});
const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIdChange});
component.filterProperties = [];
fixture.detectChanges();
const stateController = component.editTaskFilterForm.get('status');
@@ -299,8 +299,8 @@ describe('EditTaskFilterCloudComponent', () => {
it('should able to fetch running applications when appName property defined in the input', async(() => {
component.filterProperties = ['appName', 'processInstanceId', 'priority'];
fixture.detectChanges();
const taskFilterIDchange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIDchange});
const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIdChange});
const appController = component.editTaskFilterForm.get('appName');
fixture.detectChanges();
fixture.whenStable().then(() => {
@@ -314,8 +314,8 @@ describe('EditTaskFilterCloudComponent', () => {
describe('sort properties', () => {
it('should display default sort properties', async(() => {
const taskFilterIDchange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIDchange});
const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIdChange});
fixture.detectChanges();
const expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header');
expansionPanel.click();
@@ -340,8 +340,8 @@ describe('EditTaskFilterCloudComponent', () => {
priority: '12'
}));
fixture.detectChanges();
const taskFilterIDchange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIDchange});
const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIdChange});
fixture.detectChanges();
const expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header');
expansionPanel.click();
@@ -361,8 +361,8 @@ describe('EditTaskFilterCloudComponent', () => {
}));
it('should display default sort properties if input is empty', async(() => {
const taskFilterIDchange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIDchange});
const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIdChange});
fixture.detectChanges();
component.sortProperties = [];
fixture.detectChanges();
@@ -386,8 +386,8 @@ describe('EditTaskFilterCloudComponent', () => {
it('should display default filter actions', async(() => {
component.toggleFilterActions = true;
const taskFilterIDchange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIDchange});
const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIdChange});
fixture.detectChanges();
const expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header');
expansionPanel.click();
@@ -410,8 +410,8 @@ describe('EditTaskFilterCloudComponent', () => {
it('should display filter actions when input actions are specified', async(() => {
component.actions = ['save'];
fixture.detectChanges();
const taskFilterIDchange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIDchange});
const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIdChange});
fixture.detectChanges();
component.toggleFilterActions = true;
fixture.detectChanges();
@@ -430,8 +430,8 @@ describe('EditTaskFilterCloudComponent', () => {
it('should display default filter actions if input is empty', async(() => {
component.toggleFilterActions = true;
component.actions = [];
const taskFilterIDchange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIDchange});
const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIdChange});
fixture.detectChanges();
const expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header');
expansionPanel.click();
@@ -454,8 +454,8 @@ describe('EditTaskFilterCloudComponent', () => {
it('should set the correct lastModifiedTo date', (done) => {
component.appName = 'fake';
component.filterProperties = ['appName', 'processInstanceId', 'priority', 'lastModified'];
const taskFilterIDchange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIDchange});
const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIdChange});
fixture.detectChanges();
const lastModifiedToControl: AbstractControl = component.editTaskFilterForm.get('lastModifiedTo');
@@ -478,8 +478,8 @@ describe('EditTaskFilterCloudComponent', () => {
describe('edit filter actions', () => {
beforeEach(() => {
const taskFilterIDchange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIDchange});
const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIdChange});
fixture.detectChanges();
});

View File

@@ -124,9 +124,10 @@ export class EditTaskFilterCloudComponent implements OnInit, OnChanges, OnDestro
}
ngOnInit() {
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));
}
ngOnChanges(changes: SimpleChanges) {
@@ -159,8 +160,11 @@ export class EditTaskFilterCloudComponent implements OnInit, OnChanges, OnDestro
*/
onFilterChange() {
this.editTaskFilterForm.valueChanges
.pipe(debounceTime(500),
filter(() => this.isFormValid()))
.pipe(
debounceTime(500),
filter(() => this.isFormValid()),
takeUntil(this.onDestroy$)
)
.subscribe((formValues: TaskFilterCloudModel) => {
this.setLastModifiedToFilter(formValues);
this.changedTaskFilter = new TaskFilterCloudModel(Object.assign({}, this.taskFilter, formValues));
@@ -334,7 +338,7 @@ export class EditTaskFilterCloudComponent implements OnInit, OnChanges, OnDestro
save(saveAction: TaskFilterAction) {
this.taskFilterCloudService.updateFilter(this.changedTaskFilter)
.pipe(takeUntil(this.onDestroy$)).subscribe((res) => {
.pipe(takeUntil(this.onDestroy$)).subscribe(() => {
saveAction.filter = this.changedTaskFilter;
this.action.emit(saveAction);
this.formHasBeenChanged = this.compareFilters(this.changedTaskFilter, this.taskFilter);
@@ -343,7 +347,7 @@ export class EditTaskFilterCloudComponent implements OnInit, OnChanges, OnDestro
delete(deleteAction: TaskFilterAction) {
this.taskFilterCloudService.deleteFilter(this.taskFilter)
.pipe(takeUntil(this.onDestroy$)).subscribe((res) => {
.pipe(takeUntil(this.onDestroy$)).subscribe(() => {
deleteAction.filter = this.taskFilter;
this.action.emit(deleteAction);
});
@@ -369,7 +373,7 @@ export class EditTaskFilterCloudComponent implements OnInit, OnChanges, OnDestro
};
const resultFilter: TaskFilterCloudModel = Object.assign({}, this.changedTaskFilter, newFilter);
this.taskFilterCloudService.addFilter(resultFilter)
.pipe(takeUntil(this.onDestroy$)).subscribe((res) => {
.pipe(takeUntil(this.onDestroy$)).subscribe(() => {
saveAsAction.filter = resultFilter;
this.action.emit(saveAsAction);
});

View File

@@ -49,7 +49,7 @@ export class TaskFilterCloudService {
} else if (!this.hasTaskFilters(preferences, key)) {
return this.createTaskFilters(appName, key, this.defaultTaskFilters(appName));
} else {
return of(this.findFiltersByKeyInPrefrences(preferences, key));
return of(this.findFiltersByKeyInPreferences(preferences, key));
}
}),
catchError((err) => this.handleTaskError(err))
@@ -138,7 +138,7 @@ export class TaskFilterCloudService {
/**
* Adds a new task filter.
* @param filter The new filter to add
* @returns Obervable of task instance filters with newly added filter
* @returns Observable of task instance filters with newly added filter
*/
addFilter(newFilter: TaskFilterCloudModel) {
const key: string = this.prepareKey(newFilter.appName);
@@ -244,7 +244,7 @@ export class TaskFilterCloudService {
* @param appName Name of the target app
* @returns Array of TaskFilterCloudModel
*/
private findFiltersByKeyInPrefrences(preferences: any, key: string): TaskFilterCloudModel[] {
private findFiltersByKeyInPreferences(preferences: any, key: string): TaskFilterCloudModel[] {
const result = preferences.find((filter: any) => { return filter.entry.key === key; });
return result && result.entry ? JSON.parse(result.entry.value) : [];
}

View File

@@ -29,8 +29,9 @@ import {
import { TaskDetailsCloudModel, TaskStatusEnum } from '../../start-task/models/task-details-cloud.model';
import { Router } from '@angular/router';
import { TaskCloudService } from '../../services/task-cloud.service';
import { Subscription } from 'rxjs';
import { Subject } from 'rxjs';
import { NumericFieldValidator } from '../../../validators/numeric-field.validator';
import { takeUntil } from 'rxjs/operators';
@Component({
selector: 'adf-cloud-task-header',
@@ -62,7 +63,7 @@ export class TaskHeaderCloudComponent implements OnInit, OnDestroy {
dateFormat: string;
dateLocale: string;
private subscriptions: Subscription[] = [];
private onDestroy$ = new Subject<boolean>();
constructor(
private taskCloudService: TaskCloudService,
@@ -80,19 +81,21 @@ export class TaskHeaderCloudComponent implements OnInit, OnDestroy {
this.loadTaskDetailsById(this.appName, this.taskId);
}
this.subscriptions.push(this.cardViewUpdateService.itemUpdated$.subscribe(this.updateTaskDetails.bind(this)));
this.cardViewUpdateService.itemUpdated$
.pipe(takeUntil(this.onDestroy$))
.subscribe(this.updateTaskDetails.bind(this));
}
loadTaskDetailsById(appName: string, taskId: string): any {
this.subscriptions.push(this.taskCloudService.getTaskById(appName, taskId).subscribe(
this.taskCloudService.getTaskById(appName, taskId).subscribe(
(taskDetails) => {
this.taskDetails = taskDetails;
if (this.taskDetails.parentTaskId) {
this.loadParentName(this.taskDetails.parentTaskId);
this.loadParentName(`${this.taskDetails.parentTaskId}`);
} else {
this.refreshData();
}
}));
});
}
private initDefaultProperties() {
@@ -220,7 +223,7 @@ export class TaskHeaderCloudComponent implements OnInit, OnDestroy {
);
}
private loadParentName(taskId) {
private loadParentName(taskId: string) {
this.taskCloudService.getTaskById(this.appName, taskId)
.subscribe(
(taskDetails) => {
@@ -263,7 +266,7 @@ export class TaskHeaderCloudComponent implements OnInit, OnDestroy {
}
ngOnDestroy() {
this.subscriptions.forEach((subscription) => subscription.unsubscribe());
this.subscriptions = [];
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
}

View File

@@ -15,16 +15,17 @@
* limitations under the License.
*/
import { Component, ViewEncapsulation, OnChanges, Input, SimpleChanges, Output, EventEmitter, ContentChild, AfterContentInit } from '@angular/core';
import { Component, ViewEncapsulation, OnChanges, Input, SimpleChanges, Output, EventEmitter, ContentChild, AfterContentInit, OnDestroy, OnInit } from '@angular/core';
import { AppConfigService, UserPreferencesService,
DataTableSchema, UserPreferenceValues,
PaginatedComponent, PaginationModel,
DataRowEvent, CustomEmptyContentTemplateDirective } from '@alfresco/adf-core';
import { taskPresetsCloudDefaultModel } from '../models/task-preset-cloud.model';
import { TaskQueryCloudRequestModel } from '../models/filter-cloud-model';
import { BehaviorSubject } from 'rxjs';
import { BehaviorSubject, Subject } from 'rxjs';
import { TaskListCloudService } from '../services/task-list-cloud.service';
import { TaskListCloudSortingModel } from '../models/task-list-sorting.model';
import { takeUntil } from 'rxjs/operators';
@Component({
selector: 'adf-cloud-task-list',
@@ -33,7 +34,7 @@ import { TaskListCloudSortingModel } from '../models/task-list-sorting.model';
encapsulation: ViewEncapsulation.None
})
export class TaskListCloudComponent extends DataTableSchema implements OnChanges, AfterContentInit, PaginatedComponent {
export class TaskListCloudComponent extends DataTableSchema implements OnChanges, AfterContentInit, PaginatedComponent, OnDestroy, OnInit {
static PRESET_KEY = 'adf-cloud-task-list.presets';
@@ -148,14 +149,13 @@ export class TaskListCloudComponent extends DataTableSchema implements OnChanges
isLoading = false;
selectedInstances: any[];
private onDestroy$ = new Subject<boolean>();
constructor(private taskListCloudService: TaskListCloudService,
appConfigService: AppConfigService,
private userPreferences: UserPreferencesService) {
super(appConfigService, TaskListCloudComponent.PRESET_KEY, taskPresetsCloudDefaultModel);
this.size = userPreferences.paginationSize;
this.userPreferences.select(UserPreferenceValues.PaginationSize).subscribe((pageSize) => {
this.size = pageSize;
});
this.pagination = new BehaviorSubject<PaginationModel>(<PaginationModel> {
maxItems: this.size,
@@ -165,12 +165,24 @@ export class TaskListCloudComponent extends DataTableSchema implements OnChanges
}
ngOnInit() {
this.userPreferences
.select(UserPreferenceValues.PaginationSize)
.pipe(takeUntil(this.onDestroy$))
.subscribe(pageSize => this.size = pageSize);
}
ngOnChanges(changes: SimpleChanges) {
if (this.isPropertyChanged(changes)) {
this.reload();
}
}
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
ngAfterContentInit() {
this.createDatatableSchema();
}

View File

@@ -85,10 +85,10 @@ export class TaskListCloudService extends BaseCloudService {
return requestNode[property] !== '' && requestNode[property] !== null && requestNode[property] !== undefined;
}
private buildSortingParam(sortings: TaskListCloudSortingModel[]): string {
private buildSortingParam(models: TaskListCloudSortingModel[]): string {
let finalSorting: string = '';
if (sortings) {
for (const sort of sortings) {
if (models) {
for (const sort of models) {
if (!finalSorting) {
finalSorting = `${sort.orderBy},${sort.direction}`;
} else {