[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

@@ -1,4 +1,3 @@
# This is a comment. # This is a comment.
# Each line is a file pattern followed by one or more owners. # Each line is a file pattern followed by one or more owners.

View File

@@ -15,9 +15,11 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, ViewEncapsulation, OnInit } from '@angular/core'; import { Component, ViewEncapsulation, OnInit, OnDestroy } from '@angular/core';
import { UserPreferencesService, AppConfigService, AlfrescoApiService, UserPreferenceValues } from '@alfresco/adf-core'; import { UserPreferencesService, AppConfigService, AlfrescoApiService, UserPreferenceValues } from '@alfresco/adf-core';
import { HeaderDataService } from '../header-data/header-data.service'; import { HeaderDataService } from '../header-data/header-data.service';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
templateUrl: 'app-layout.component.html', templateUrl: 'app-layout.component.html',
@@ -27,8 +29,8 @@ import { HeaderDataService } from '../header-data/header-data.service';
}, },
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class AppLayoutComponent implements OnInit, OnDestroy {
export class AppLayoutComponent implements OnInit { private onDestroy$ = new Subject<boolean>();
links: Array<any> = [ links: Array<any> = [
{ href: '/home', icon: 'home', title: 'APP_LAYOUT.HOME' }, { href: '/home', icon: 'home', title: 'APP_LAYOUT.HOME' },
@@ -108,14 +110,42 @@ export class AppLayoutComponent implements OnInit {
this.expandedSidenav = expand; this.expandedSidenav = expand;
} }
this.headerService.hideMenu.subscribe((show) => this.showMenu = show); this.headerService.hideMenu
this.headerService.color.subscribe((color) => this.color = color); .pipe(takeUntil(this.onDestroy$))
this.headerService.title.subscribe((title) => this.title = title); .subscribe(show => this.showMenu = show);
this.headerService.logo.subscribe((path) => this.logo = path);
this.headerService.redirectUrl.subscribe((redirectUrl) => this.redirectUrl = redirectUrl); this.headerService.color
this.headerService.tooltip.subscribe((tooltip) => this.tooltip = tooltip); .pipe(takeUntil(this.onDestroy$))
this.headerService.position.subscribe((position) => this.position = position); .subscribe(color => this.color = color);
this.headerService.hideSidenav.subscribe((hideSidenav) => this.hideSidenav = hideSidenav);
this.headerService.title
.pipe(takeUntil(this.onDestroy$))
.subscribe(title => this.title = title);
this.headerService.logo
.pipe(takeUntil(this.onDestroy$))
.subscribe(path => this.logo = path);
this.headerService.redirectUrl
.pipe(takeUntil(this.onDestroy$))
.subscribe(redirectUrl => this.redirectUrl = redirectUrl);
this.headerService.tooltip
.pipe(takeUntil(this.onDestroy$))
.subscribe(tooltip => this.tooltip = tooltip);
this.headerService.position
.pipe(takeUntil(this.onDestroy$))
.subscribe(position => this.position = position);
this.headerService.hideSidenav
.pipe(takeUntil(this.onDestroy$))
.subscribe(hideSidenav => this.hideSidenav = hideSidenav);
}
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
} }
constructor( constructor(

View File

@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, OnInit, ElementRef, ViewChild } from '@angular/core'; import { Component, OnInit, ElementRef, ViewChild, OnDestroy } from '@angular/core';
import { import {
CardViewTextItemModel, CardViewTextItemModel,
CardViewDateItemModel, CardViewDateItemModel,
@@ -29,13 +29,14 @@ import {
CardViewMapItemModel, CardViewMapItemModel,
UpdateNotification UpdateNotification
} from '@alfresco/adf-core'; } from '@alfresco/adf-core';
import { of } from 'rxjs'; import { of, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
templateUrl: './card-view.component.html', templateUrl: './card-view.component.html',
styleUrls: ['./card-view.component.scss'] styleUrls: ['./card-view.component.scss']
}) })
export class CardViewComponent implements OnInit { export class CardViewComponent implements OnInit, OnDestroy {
@ViewChild('console') console: ElementRef; @ViewChild('console') console: ElementRef;
@@ -43,6 +44,8 @@ export class CardViewComponent implements OnInit {
properties: any; properties: any;
logs: string[]; logs: string[];
private onDestroy$ = new Subject<boolean>();
constructor(private cardViewUpdateService: CardViewUpdateService) { constructor(private cardViewUpdateService: CardViewUpdateService) {
this.logs = []; this.logs = [];
this.createCard(); this.createCard();
@@ -53,7 +56,14 @@ export class CardViewComponent implements OnInit {
} }
ngOnInit() { ngOnInit() {
this.cardViewUpdateService.itemUpdated$.subscribe(this.onItemChange.bind(this)); this.cardViewUpdateService.itemUpdated$
.pipe(takeUntil(this.onDestroy$))
.subscribe(this.onItemChange.bind(this));
}
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
} }
createCard() { createCard() {

View File

@@ -24,18 +24,16 @@ import { ActivatedRoute } from '@angular/router';
styleUrls: ['cloud-breadcrumb-component.scss'] styleUrls: ['cloud-breadcrumb-component.scss']
}) })
export class CloudBreadcrumbsComponent implements OnInit { export class CloudBreadcrumbsComponent implements OnInit {
appName: string; appName: string;
filterName: string; filterName: string;
constructor(private route: ActivatedRoute) {} constructor(private route: ActivatedRoute) {}
ngOnInit() { ngOnInit() {
this.route.parent.params.subscribe(( this.route.parent.params.subscribe(params => {
params) => {
this.appName = params.appName; this.appName = params.appName;
}); });
this.route.queryParams.subscribe((params) => { this.route.queryParams.subscribe(params => {
if (params.filterName) { if (params.filterName) {
this.filterName = params.filterName; this.filterName = params.filterName;
} }

View File

@@ -46,8 +46,9 @@ export class CloudFiltersDemoComponent implements OnInit {
) {} ) {}
ngOnInit() { ngOnInit() {
this.currentTaskFilter$ = this.cloudLayoutService.getCurrentTaskFilterParam(); this.currentTaskFilter$ = this.cloudLayoutService.taskFilter$;
this.currentProcessFilter$ = this.cloudLayoutService.getCurrentProcessFilterParam(); this.currentProcessFilter$ = this.cloudLayoutService.processFilter$;
let root = ''; let root = '';
if (this.route.snapshot && this.route.snapshot.firstChild) { if (this.route.snapshot && this.route.snapshot.firstChild) {
root = this.route.snapshot.firstChild.url[0].path; root = this.route.snapshot.firstChild.url[0].path;

View File

@@ -15,15 +15,18 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, OnInit } from '@angular/core'; import { Component, OnInit, OnDestroy } from '@angular/core';
import { CloudLayoutService } from './services/cloud-layout.service'; import { CloudLayoutService } from './services/cloud-layout.service';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'app-cloud-settings', selector: 'app-cloud-settings',
templateUrl: './cloud-settings.component.html', templateUrl: './cloud-settings.component.html',
styleUrls: ['./cloud-settings.component.scss'] styleUrls: ['./cloud-settings.component.scss']
}) })
export class CloudSettingsComponent implements OnInit { export class CloudSettingsComponent implements OnInit, OnDestroy {
private onDestroy$ = new Subject<boolean>();
multiselect: boolean; multiselect: boolean;
selectionMode: string; selectionMode: string;
@@ -40,8 +43,15 @@ export class CloudSettingsComponent implements OnInit {
constructor(private cloudLayoutService: CloudLayoutService) { } constructor(private cloudLayoutService: CloudLayoutService) { }
ngOnInit() { ngOnInit() {
this.cloudLayoutService.getCurrentSettings() this.cloudLayoutService
.subscribe((settings) => this.setCurrentSettings(settings)); .settings$
.pipe(takeUntil(this.onDestroy$))
.subscribe(settings => this.setCurrentSettings(settings));
}
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
} }
setCurrentSettings(settings) { setCurrentSettings(settings) {

View File

@@ -15,32 +15,24 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, OnDestroy, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';
import { Params } from '@angular/router/src/shared'; import { Params } from '@angular/router/src/shared';
@Component({ @Component({
selector: 'app-cloud-viewer', selector: 'app-cloud-viewer',
templateUrl: './cloud-viewer.component.html' templateUrl: './cloud-viewer.component.html'
}) })
export class CloudViewerComponent implements OnInit, OnDestroy { export class CloudViewerComponent implements OnInit {
nodeId: string; nodeId: string;
private sub: Subscription;
constructor(private route: ActivatedRoute) { constructor(private route: ActivatedRoute) {
} }
ngOnInit() { ngOnInit() {
this.sub = this.route.params.subscribe((params: Params) => { this.route.params.subscribe((params: Params) => {
this.nodeId = params['nodeId']; this.nodeId = params['nodeId'];
}); });
} }
ngOnDestroy() {
this.sub.unsubscribe();
}
} }

View File

@@ -45,8 +45,9 @@ export class CommunityCloudFiltersDemoComponent implements OnInit {
) {} ) {}
ngOnInit() { ngOnInit() {
this.currentTaskFilter$ = this.cloudLayoutService.getCurrentTaskFilterParam(); this.currentTaskFilter$ = this.cloudLayoutService.taskFilter$;
this.currentProcessFilter$ = this.cloudLayoutService.getCurrentProcessFilterParam(); this.currentProcessFilter$ = this.cloudLayoutService.processFilter$;
let root = ''; let root = '';
if (this.route.snapshot && this.route.snapshot.firstChild) { if (this.route.snapshot && this.route.snapshot.firstChild) {
root = this.route.snapshot.firstChild.url[0].path; root = this.route.snapshot.firstChild.url[0].path;

View File

@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, ViewChild, OnInit } from '@angular/core'; import { Component, ViewChild, OnInit, OnDestroy } from '@angular/core';
import { import {
ProcessListCloudComponent, ProcessListCloudComponent,
ProcessFilterCloudModel, ProcessFilterCloudModel,
@@ -27,12 +27,14 @@ import {
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { UserPreferencesService, AppConfigService } from '@alfresco/adf-core'; import { UserPreferencesService, AppConfigService } from '@alfresco/adf-core';
import { CloudLayoutService } from '../services/cloud-layout.service'; import { CloudLayoutService } from '../services/cloud-layout.service';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { Pagination } from '@alfresco/js-api';
@Component({ @Component({
templateUrl: './community-processes-cloud.component.html' templateUrl: './community-processes-cloud.component.html'
}) })
export class CommunityProcessesCloudDemoComponent implements OnInit { export class CommunityProcessesCloudDemoComponent implements OnInit, OnDestroy {
public static ACTION_SAVE_AS = 'saveAs'; public static ACTION_SAVE_AS = 'saveAs';
static PROCESS_FILTER_PROPERTY_KEYS = 'adf-edit-process-filter'; static PROCESS_FILTER_PROPERTY_KEYS = 'adf-edit-process-filter';
@@ -56,6 +58,8 @@ export class CommunityProcessesCloudDemoComponent implements OnInit {
editedFilter: ProcessFilterCloudModel; editedFilter: ProcessFilterCloudModel;
private onDestroy$ = new Subject<boolean>();
constructor( constructor(
private route: ActivatedRoute, private route: ActivatedRoute,
private router: Router, private router: Router,
@@ -63,7 +67,10 @@ export class CommunityProcessesCloudDemoComponent implements OnInit {
private userPreference: UserPreferencesService, private userPreference: UserPreferencesService,
private processFilterCloudService: ProcessFilterCloudService, private processFilterCloudService: ProcessFilterCloudService,
private appConfig: AppConfigService) { private appConfig: AppConfigService) {
const properties = this.appConfig.get<Array<any>>(CommunityProcessesCloudDemoComponent.PROCESS_FILTER_PROPERTY_KEYS); const properties = this.appConfig.get<Array<any>>(
CommunityProcessesCloudDemoComponent.PROCESS_FILTER_PROPERTY_KEYS
);
if (properties) { if (properties) {
this.processFilterProperties = properties; this.processFilterProperties = properties;
} }
@@ -71,6 +78,7 @@ export class CommunityProcessesCloudDemoComponent implements OnInit {
ngOnInit() { ngOnInit() {
this.isFilterLoaded = false; this.isFilterLoaded = false;
this.route.parent.params.subscribe((params) => { this.route.parent.params.subscribe((params) => {
this.appName = params.appName; this.appName = params.appName;
}); });
@@ -85,12 +93,21 @@ export class CommunityProcessesCloudDemoComponent implements OnInit {
} }
}); });
this.cloudLayoutService.getCurrentSettings() this.cloudLayoutService
.subscribe((settings) => this.setCurrentSettings(settings)); .settings$
.pipe(takeUntil(this.onDestroy$))
.subscribe(settings => this.setCurrentSettings(settings));
}
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
} }
loadDefaultFilters() { loadDefaultFilters() {
this.processFilterCloudService.getProcessFilters('community').subscribe( (filters: ProcessFilterCloudModel[]) => { this.processFilterCloudService
.getProcessFilters('community')
.subscribe((filters: ProcessFilterCloudModel[]) => {
this.onFilterChange(filters[0]); this.onFilterChange(filters[0]);
}); });
} }
@@ -103,7 +120,7 @@ export class CommunityProcessesCloudDemoComponent implements OnInit {
} }
} }
onChangePageSize(event) { onChangePageSize(event: Pagination) {
this.userPreference.paginationSize = event.maxItems; this.userPreference.paginationSize = event.maxItems;
} }
@@ -111,13 +128,18 @@ export class CommunityProcessesCloudDemoComponent implements OnInit {
this.selectedRows = []; this.selectedRows = [];
} }
onRowClick(processInstanceId) { onRowClick(processInstanceId: string) {
this.router.navigate([`/cloud/community/process-details/${processInstanceId}`]); this.router.navigate([`/cloud/community/process-details/${processInstanceId}`]);
} }
onFilterChange(query: any) { onFilterChange(query: any) {
this.editedFilter = Object.assign({}, query); this.editedFilter = Object.assign({}, query);
this.sortArray = [new ProcessListCloudSortingModel({ orderBy: this.editedFilter.sort, direction: this.editedFilter.order })]; this.sortArray = [
new ProcessListCloudSortingModel({
orderBy: this.editedFilter.sort,
direction: this.editedFilter.order
})
];
} }
onProcessFilterAction(filterAction: any) { onProcessFilterAction(filterAction: any) {

View File

@@ -15,11 +15,14 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, ViewChild, OnInit } from '@angular/core'; import { Component, ViewChild, OnInit, OnDestroy } from '@angular/core';
import { TaskListCloudComponent, TaskListCloudSortingModel, TaskFilterCloudModel, TaskFilterCloudService } from '@alfresco/adf-process-services-cloud'; import { TaskListCloudComponent, TaskListCloudSortingModel, TaskFilterCloudModel, TaskFilterCloudService } from '@alfresco/adf-process-services-cloud';
import { UserPreferencesService, AppConfigService } from '@alfresco/adf-core'; import { UserPreferencesService, AppConfigService } from '@alfresco/adf-core';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { CloudLayoutService } from '../services/cloud-layout.service'; import { CloudLayoutService } from '../services/cloud-layout.service';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { Pagination } from '@alfresco/js-api';
@Component({ @Component({
templateUrl: './community-task-cloud.component.html', templateUrl: './community-task-cloud.component.html',
@@ -28,8 +31,7 @@ import { CloudLayoutService } from '../services/cloud-layout.service';
} }
`] `]
}) })
export class CommunityTasksCloudDemoComponent implements OnInit { export class CommunityTasksCloudDemoComponent implements OnInit, OnDestroy {
public static ACTION_SAVE_AS = 'saveAs'; public static ACTION_SAVE_AS = 'saveAs';
static TASK_FILTER_PROPERTY_KEYS = 'adf-edit-task-filter'; static TASK_FILTER_PROPERTY_KEYS = 'adf-edit-task-filter';
@@ -51,6 +53,8 @@ export class CommunityTasksCloudDemoComponent implements OnInit {
selectionMode: string; selectionMode: string;
taskDetailsRedirection: boolean; taskDetailsRedirection: boolean;
private onDestroy$ = new Subject<boolean>();
constructor( constructor(
private cloudLayoutService: CloudLayoutService, private cloudLayoutService: CloudLayoutService,
private route: ActivatedRoute, private route: ActivatedRoute,
@@ -79,12 +83,21 @@ export class CommunityTasksCloudDemoComponent implements OnInit {
} }
}); });
this.cloudLayoutService.getCurrentSettings() this.cloudLayoutService
.subscribe((settings) => this.setCurrentSettings(settings)); .settings$
.pipe(takeUntil(this.onDestroy$))
.subscribe(settings => this.setCurrentSettings(settings));
}
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
} }
loadDefaultFilters() { loadDefaultFilters() {
this.taskFilterCloudService.getTaskListFilters('community').subscribe( (filters: TaskFilterCloudModel[]) => { this.taskFilterCloudService
.getTaskListFilters('community')
.subscribe((filters: TaskFilterCloudModel[]) => {
this.onFilterChange(filters[0]); this.onFilterChange(filters[0]);
}); });
} }
@@ -98,7 +111,7 @@ export class CommunityTasksCloudDemoComponent implements OnInit {
} }
} }
onChangePageSize(event) { onChangePageSize(event: Pagination) {
this.userPreference.paginationSize = event.maxItems; this.userPreference.paginationSize = event.maxItems;
} }
@@ -106,7 +119,7 @@ export class CommunityTasksCloudDemoComponent implements OnInit {
this.selectedRows = []; this.selectedRows = [];
} }
onRowClick(taskId) { onRowClick(taskId: string) {
if (!this.multiselect && this.selectionMode !== 'multiple' && this.taskDetailsRedirection) { if (!this.multiselect && this.selectionMode !== 'multiple' && this.taskDetailsRedirection) {
this.router.navigate([`/cloud/community/task-details/${taskId}`]); this.router.navigate([`/cloud/community/task-details/${taskId}`]);
} }

View File

@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, ViewChild, OnInit } from '@angular/core'; import { Component, ViewChild, OnInit, OnDestroy } from '@angular/core';
import { import {
ProcessListCloudComponent, ProcessListCloudComponent,
ProcessFilterCloudModel, ProcessFilterCloudModel,
@@ -25,13 +25,16 @@ import {
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { UserPreferencesService, AppConfigService } from '@alfresco/adf-core'; import { UserPreferencesService, AppConfigService } from '@alfresco/adf-core';
import { CloudLayoutService } from './services/cloud-layout.service'; import { CloudLayoutService, CloudServiceSettings } from './services/cloud-layout.service';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { Pagination } from '@alfresco/js-api';
@Component({ @Component({
templateUrl: './processes-cloud-demo.component.html', templateUrl: './processes-cloud-demo.component.html',
styleUrls: ['./processes-cloud-demo.component.scss'] styleUrls: ['./processes-cloud-demo.component.scss']
}) })
export class ProcessesCloudDemoComponent implements OnInit { export class ProcessesCloudDemoComponent implements OnInit, OnDestroy {
public static ACTION_SAVE_AS = 'saveAs'; public static ACTION_SAVE_AS = 'saveAs';
static PROCESS_FILTER_PROPERTY_KEYS = 'adf-edit-process-filter'; static PROCESS_FILTER_PROPERTY_KEYS = 'adf-edit-process-filter';
@@ -57,6 +60,8 @@ export class ProcessesCloudDemoComponent implements OnInit {
editedFilter: ProcessFilterCloudModel; editedFilter: ProcessFilterCloudModel;
private onDestroy$ = new Subject<boolean>();
constructor( constructor(
private route: ActivatedRoute, private route: ActivatedRoute,
private router: Router, private router: Router,
@@ -81,11 +86,17 @@ export class ProcessesCloudDemoComponent implements OnInit {
this.filterId = params.id; this.filterId = params.id;
}); });
this.cloudLayoutService.getCurrentSettings() this.cloudLayoutService.settings$
.subscribe((settings) => this.setCurrentSettings(settings)); .pipe(takeUntil(this.onDestroy$))
.subscribe(settings => this.setCurrentSettings(settings));
} }
setCurrentSettings(settings) { ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
setCurrentSettings(settings: CloudServiceSettings) {
if (settings) { if (settings) {
this.multiselect = settings.multiselect; this.multiselect = settings.multiselect;
this.testingMode = settings.testingMode; this.testingMode = settings.testingMode;
@@ -94,7 +105,7 @@ export class ProcessesCloudDemoComponent implements OnInit {
} }
} }
onChangePageSize(event) { onChangePageSize(event: Pagination) {
this.userPreference.paginationSize = event.maxItems; this.userPreference.paginationSize = event.maxItems;
} }
@@ -102,7 +113,7 @@ export class ProcessesCloudDemoComponent implements OnInit {
this.selectedRows = []; this.selectedRows = [];
} }
onRowClick(processInstanceId) { onRowClick(processInstanceId: string) {
if (!this.multiselect && this.selectionMode !== 'multiple' && this.processDetailsRedirection) { if (!this.multiselect && this.selectionMode !== 'multiple' && this.processDetailsRedirection) {
this.router.navigate([`/cloud/${this.appName}/process-details/${processInstanceId}`]); this.router.navigate([`/cloud/${this.appName}/process-details/${processInstanceId}`]);
} }
@@ -110,7 +121,12 @@ export class ProcessesCloudDemoComponent implements OnInit {
onFilterChange(query: any) { onFilterChange(query: any) {
this.editedFilter = Object.assign({}, query); this.editedFilter = Object.assign({}, query);
this.sortArray = [new ProcessListCloudSortingModel({ orderBy: this.editedFilter.sort, direction: this.editedFilter.order })]; this.sortArray = [
new ProcessListCloudSortingModel({
orderBy: this.editedFilter.sort,
direction: this.editedFilter.order
})
];
} }
onProcessFilterAction(filterAction: any) { onProcessFilterAction(filterAction: any) {

View File

@@ -16,14 +16,28 @@
*/ */
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Observable, BehaviorSubject } from 'rxjs'; import { BehaviorSubject } from 'rxjs';
export interface CloudServiceSettings {
multiselect: boolean;
testingMode: boolean;
taskDetailsRedirection: boolean;
processDetailsRedirection: boolean;
selectionMode: string;
}
export interface FilterSettings {
id?: string;
index?: number;
key?: string;
}
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
export class CloudLayoutService { export class CloudLayoutService {
private settings = { private settings: CloudServiceSettings = {
multiselect: false, multiselect: false,
testingMode: false, testingMode: false,
taskDetailsRedirection: true, taskDetailsRedirection: true,
@@ -31,40 +45,19 @@ export class CloudLayoutService {
selectionMode: 'single' selectionMode: 'single'
}; };
private filterTaskSubject: BehaviorSubject<any> = new BehaviorSubject({index: 0}); taskFilter$ = new BehaviorSubject<FilterSettings>({index: 0});
private filterTask$: Observable<any>; processFilter$ = new BehaviorSubject<FilterSettings>({index: 0});
private filterProcessSubject: BehaviorSubject<any> = new BehaviorSubject({index: 0}); settings$ = new BehaviorSubject<CloudServiceSettings>(this.settings);
private filterProcess$: Observable<any>;
private settingsSubject: BehaviorSubject<any> = new BehaviorSubject(this.settings);
private settings$: Observable<any>;
constructor() { setCurrentTaskFilterParam(param: FilterSettings) {
this.filterTask$ = this.filterTaskSubject.asObservable(); this.taskFilter$.next(param);
this.filterProcess$ = this.filterProcessSubject.asObservable();
this.settings$ = this.settingsSubject.asObservable();
} }
getCurrentTaskFilterParam() { setCurrentProcessFilterParam(param: FilterSettings) {
return this.filterTask$; this.processFilter$.next(param);
} }
setCurrentTaskFilterParam(param) { setCurrentSettings(param: CloudServiceSettings) {
this.filterTaskSubject.next(param); this.settings$.next(param);
}
getCurrentProcessFilterParam() {
return this.filterProcess$;
}
setCurrentProcessFilterParam(param) {
this.filterProcessSubject.next(param);
}
getCurrentSettings() {
return this.settings$;
}
setCurrentSettings(param) {
this.settingsSubject.next(param);
} }
} }

View File

@@ -15,17 +15,19 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, ViewChild, OnInit } from '@angular/core'; import { Component, ViewChild, OnInit, OnDestroy } from '@angular/core';
import { TaskListCloudComponent, TaskListCloudSortingModel, TaskFilterCloudModel } from '@alfresco/adf-process-services-cloud'; import { TaskListCloudComponent, TaskListCloudSortingModel, TaskFilterCloudModel } from '@alfresco/adf-process-services-cloud';
import { UserPreferencesService, AppConfigService } from '@alfresco/adf-core'; import { UserPreferencesService, AppConfigService } from '@alfresco/adf-core';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { CloudLayoutService } from './services/cloud-layout.service'; import { CloudLayoutService } from './services/cloud-layout.service';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
templateUrl: 'tasks-cloud-demo.component.html', templateUrl: 'tasks-cloud-demo.component.html',
styleUrls: ['tasks-cloud-demo.component.scss'] styleUrls: ['tasks-cloud-demo.component.scss']
}) })
export class TasksCloudDemoComponent implements OnInit { export class TasksCloudDemoComponent implements OnInit, OnDestroy {
public static ACTION_SAVE_AS = 'saveAs'; public static ACTION_SAVE_AS = 'saveAs';
static TASK_FILTER_PROPERTY_KEYS = 'adf-edit-task-filter'; static TASK_FILTER_PROPERTY_KEYS = 'adf-edit-task-filter';
@@ -50,6 +52,8 @@ export class TasksCloudDemoComponent implements OnInit {
selectionMode: string; selectionMode: string;
taskDetailsRedirection: boolean; taskDetailsRedirection: boolean;
private onDestroy$ = new Subject<boolean>();
constructor( constructor(
private cloudLayoutService: CloudLayoutService, private cloudLayoutService: CloudLayoutService,
private route: ActivatedRoute, private route: ActivatedRoute,
@@ -75,8 +79,14 @@ export class TasksCloudDemoComponent implements OnInit {
this.filterId = params.id; this.filterId = params.id;
}); });
this.cloudLayoutService.getCurrentSettings() this.cloudLayoutService.settings$
.subscribe((settings) => this.setCurrentSettings(settings)); .pipe(takeUntil(this.onDestroy$))
.subscribe(settings => this.setCurrentSettings(settings));
}
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
} }
setCurrentSettings(settings) { setCurrentSettings(settings) {

View File

@@ -15,20 +15,24 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component } from '@angular/core'; import { Component, OnDestroy } from '@angular/core';
import { import {
AppConfigService, AppConfigService,
NotificationService, NotificationService,
UserPreferencesService, UserPreferencesService,
UserPreferenceValues UserPreferenceValues
} from '@alfresco/adf-core'; } from '@alfresco/adf-core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'app-config-editor', selector: 'app-config-editor',
templateUrl: 'config-editor.component.html', templateUrl: 'config-editor.component.html',
styleUrls: ['./config-editor.component.scss'] styleUrls: ['./config-editor.component.scss']
}) })
export class ConfigEditorComponent { export class ConfigEditorComponent implements OnDestroy {
private onDestroy$ = new Subject<boolean>();
editor: any; editor: any;
code: any; code: any;
@@ -83,11 +87,19 @@ export class ConfigEditorComponent {
this.indentCode(); this.indentCode();
} }
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
textOrientationClick() { textOrientationClick() {
this.isUserPreference = true; this.isUserPreference = true;
this.userPreferenceProperty = 'textOrientation'; this.userPreferenceProperty = 'textOrientation';
this.userPreferencesService.select(this.userPreferenceProperty).subscribe((textOrientation: number) => { this.userPreferencesService
.select(this.userPreferenceProperty)
.pipe(takeUntil(this.onDestroy$))
.subscribe((textOrientation: number) => {
this.code = JSON.stringify(textOrientation); this.code = JSON.stringify(textOrientation);
this.field = 'textOrientation'; this.field = 'textOrientation';
this.indentCode(); this.indentCode();
@@ -99,7 +111,10 @@ export class ConfigEditorComponent {
infinitePaginationConfClick() { infinitePaginationConfClick() {
this.isUserPreference = true; this.isUserPreference = true;
this.userPreferenceProperty = UserPreferenceValues.PaginationSize; this.userPreferenceProperty = UserPreferenceValues.PaginationSize;
this.userPreferencesService.select(this.userPreferenceProperty).subscribe((pageSize: number) => { this.userPreferencesService
.select(this.userPreferenceProperty)
.pipe(takeUntil(this.onDestroy$))
.subscribe((pageSize: number) => {
this.code = JSON.stringify(pageSize); this.code = JSON.stringify(pageSize);
this.field = 'adf-infinite-pagination'; this.field = 'adf-infinite-pagination';
this.indentCode(); this.indentCode();
@@ -109,7 +124,10 @@ export class ConfigEditorComponent {
supportedPageSizesClick() { supportedPageSizesClick() {
this.isUserPreference = true; this.isUserPreference = true;
this.userPreferenceProperty = UserPreferenceValues.SupportedPageSizes; this.userPreferenceProperty = UserPreferenceValues.SupportedPageSizes;
this.userPreferencesService.select(this.userPreferenceProperty).subscribe((supportedPageSizes: number) => { this.userPreferencesService
.select(this.userPreferenceProperty)
.pipe(takeUntil(this.onDestroy$))
.subscribe((supportedPageSizes: number) => {
this.code = JSON.stringify(supportedPageSizes); this.code = JSON.stringify(supportedPageSizes);
this.field = 'adf-supported-page-size'; this.field = 'adf-supported-page-size';
this.indentCode(); this.indentCode();

View File

@@ -25,9 +25,10 @@ import {
OnDestroy OnDestroy
} from '@angular/core'; } from '@angular/core';
import { NodeEntry } from '@alfresco/js-api'; import { NodeEntry } from '@alfresco/js-api';
import { BehaviorSubject, Subscription } from 'rxjs'; import { BehaviorSubject, Subject } from 'rxjs';
import { AlfrescoApiService } from '@alfresco/adf-core'; import { AlfrescoApiService } from '@alfresco/adf-core';
import { Node } from '@alfresco/js-api'; import { Node } from '@alfresco/js-api';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'app-name-column', selector: 'app-name-column',
@@ -47,14 +48,16 @@ export class NameColumnComponent implements OnInit, OnDestroy {
displayText$ = new BehaviorSubject<string>(''); displayText$ = new BehaviorSubject<string>('');
node: NodeEntry; node: NodeEntry;
private sub: Subscription; private onDestroy$ = new Subject<boolean>();
constructor(private element: ElementRef, private alfrescoApiService: AlfrescoApiService) {} constructor(private element: ElementRef, private alfrescoApiService: AlfrescoApiService) {}
ngOnInit() { ngOnInit() {
this.updateValue(); this.updateValue();
this.sub = this.alfrescoApiService.nodeUpdated.subscribe((node: Node) => { this.alfrescoApiService.nodeUpdated
.pipe(takeUntil(this.onDestroy$))
.subscribe((node: Node) => {
const row = this.context.row; const row = this.context.row;
if (row) { if (row) {
const { entry } = row.node; const { entry } = row.node;
@@ -87,9 +90,7 @@ export class NameColumnComponent implements OnInit, OnDestroy {
} }
ngOnDestroy() { ngOnDestroy() {
if (this.sub) { this.onDestroy$.next(true);
this.sub.unsubscribe(); this.onDestroy$.complete();
this.sub = null;
}
} }
} }

View File

@@ -45,7 +45,7 @@ import { SelectAppsDialogComponent } from '@alfresco/adf-process-services';
import { VersionManagerDialogAdapterComponent } from './version-manager-dialog-adapter.component'; import { VersionManagerDialogAdapterComponent } from './version-manager-dialog-adapter.component';
import { MetadataDialogAdapterComponent } from './metadata-dialog-adapter.component'; import { MetadataDialogAdapterComponent } from './metadata-dialog-adapter.component';
import { Subscription, Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { PreviewService } from '../../services/preview.service'; import { PreviewService } from '../../services/preview.service';
import { debounceTime, takeUntil } from 'rxjs/operators'; import { debounceTime, takeUntil } from 'rxjs/operators';
import { SearchEntry } from '@alfresco/js-api'; import { SearchEntry } from '@alfresco/js-api';
@@ -201,9 +201,6 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
displayEmptyMetadata = false; displayEmptyMetadata = false;
hyperlinkNavigation = false; hyperlinkNavigation = false;
private onCreateFolder: Subscription;
private onEditFolder: Subscription;
constructor(private notificationService: NotificationService, constructor(private notificationService: NotificationService,
private uploadService: UploadService, private uploadService: UploadService,
private contentService: ContentService, private contentService: ContentService,
@@ -264,13 +261,28 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
}); });
} }
this.uploadService.fileUploadComplete.asObservable() this.uploadService.fileUploadComplete
.pipe(debounceTime(300)) .pipe(
.subscribe((value) => this.onFileUploadEvent(value)); debounceTime(300),
this.uploadService.fileUploadDeleted.subscribe((value) => this.onFileUploadEvent(value)); takeUntil(this.onDestroy$)
this.contentService.folderCreated.subscribe((value) => this.onFolderCreated(value)); )
this.onCreateFolder = this.contentService.folderCreate.subscribe((value) => this.onFolderAction(value)); .subscribe(value => this.onFileUploadEvent(value));
this.onEditFolder = this.contentService.folderEdit.subscribe((value) => this.onFolderAction(value));
this.uploadService.fileUploadDeleted
.pipe(takeUntil(this.onDestroy$))
.subscribe(value => this.onFileUploadEvent(value));
this.contentService.folderCreated
.pipe(takeUntil(this.onDestroy$))
.subscribe(value => this.onFolderCreated(value));
this.contentService.folderCreate
.pipe(takeUntil(this.onDestroy$))
.subscribe(value => this.onFolderAction(value));
this.contentService.folderEdit
.pipe(takeUntil(this.onDestroy$))
.subscribe(value => this.onFolderAction(value));
this.contentMetadataService.error this.contentMetadataService.error
.pipe(takeUntil(this.onDestroy$)) .pipe(takeUntil(this.onDestroy$))
@@ -286,9 +298,6 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
} }
ngOnDestroy() { ngOnDestroy() {
this.onCreateFolder.unsubscribe();
this.onEditFolder.unsubscribe();
this.onDestroy$.next(true); this.onDestroy$.next(true);
this.onDestroy$.complete(); this.onDestroy$.complete();
} }
@@ -592,7 +601,7 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
width: '400px' width: '400px'
}); });
dialogInstance.componentInstance.error.subscribe((message) => { dialogInstance.componentInstance.error.subscribe((message: string) => {
this.notificationService.openSnackMessage(message); this.notificationService.openSnackMessage(message);
}); });
} }

View File

@@ -15,16 +15,18 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, ViewChild } from '@angular/core'; import { Component, ViewChild, OnDestroy, OnInit } from '@angular/core';
import { FormModel, FormService, LogService, FormOutcomeEvent } from '@alfresco/adf-core'; import { FormModel, FormService, LogService, FormOutcomeEvent } from '@alfresco/adf-core';
import { FormComponent } from '@alfresco/adf-process-services'; import { FormComponent } from '@alfresco/adf-process-services';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'app-form-list', selector: 'app-form-list',
templateUrl: 'form-list.component.html', templateUrl: 'form-list.component.html',
styleUrls: ['form-list.component.scss'] styleUrls: ['form-list.component.scss']
}) })
export class FormListComponent { export class FormListComponent implements OnInit, OnDestroy {
@ViewChild('adfForm') @ViewChild('adfForm')
activitiForm: FormComponent; activitiForm: FormComponent;
@@ -38,15 +40,26 @@ export class FormListComponent {
restoredData: any = {}; restoredData: any = {};
showValidationIcon = false; showValidationIcon = false;
private onDestroy$ = new Subject<boolean>();
constructor(private formService: FormService, private logService: LogService) { constructor(private formService: FormService, private logService: LogService) {
}
ngOnInit() {
// Prevent default outcome actions // Prevent default outcome actions
formService.executeOutcome.subscribe((formOutcomeEvent: FormOutcomeEvent) => { this.formService.executeOutcome
.pipe(takeUntil(this.onDestroy$))
.subscribe((formOutcomeEvent: FormOutcomeEvent) => {
formOutcomeEvent.preventDefault(); formOutcomeEvent.preventDefault();
this.logService.log(formOutcomeEvent.outcome); this.logService.log(formOutcomeEvent.outcome);
}); });
} }
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
onRowDblClick(event: CustomEvent) { onRowDblClick(event: CustomEvent) {
const rowForm = event.detail.value.obj; const rowForm = event.detail.value.obj;

View File

@@ -15,46 +15,60 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, Inject, OnInit } from '@angular/core'; import { Component, Inject, OnInit, OnDestroy } from '@angular/core';
import { FormModel, FormService, FormOutcomeEvent, CoreAutomationService } from '@alfresco/adf-core'; import {
FormModel,
FormService,
FormOutcomeEvent,
CoreAutomationService
} from '@alfresco/adf-core';
import { InMemoryFormService } from '../../services/in-memory-form.service'; import { InMemoryFormService } from '../../services/in-memory-form.service';
import { FakeFormService } from './fake-form.service'; import { FakeFormService } from './fake-form.service';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'app-form-loading', selector: 'app-form-loading',
templateUrl: 'form-loading.component.html', templateUrl: 'form-loading.component.html',
styleUrls: ['form-loading.component.scss'], styleUrls: ['form-loading.component.scss'],
providers: [ providers: [{ provide: FormService, useClass: FakeFormService }]
{ provide: FormService, useClass: FakeFormService }
]
}) })
export class FormLoadingComponent implements OnInit { export class FormLoadingComponent implements OnInit, OnDestroy {
form: FormModel; form: FormModel;
typeaheadFieldValue = ''; typeaheadFieldValue = '';
selectFieldValue = ''; selectFieldValue = '';
radioButtonFieldValue = ''; radioButtonFieldValue = '';
formattedData = {}; formattedData = {};
constructor(@Inject(FormService) private formService: InMemoryFormService, private onDestroy$ = new Subject<boolean>();
private automationService: CoreAutomationService) {
formService.executeOutcome.subscribe((formOutcomeEvent: FormOutcomeEvent) => { constructor(
formOutcomeEvent.preventDefault(); @Inject(FormService) private formService: InMemoryFormService,
}); private automationService: CoreAutomationService
} ) {}
ngOnInit() { ngOnInit() {
this.formService.executeOutcome
.pipe(takeUntil(this.onDestroy$))
.subscribe((formOutcomeEvent: FormOutcomeEvent) => {
formOutcomeEvent.preventDefault();
});
this.formattedData = {}; this.formattedData = {};
const formDefinitionJSON: any = this.automationService.forms.getSimpleFormDefinition(); const formDefinitionJSON: any = this.automationService.forms.getSimpleFormDefinition();
this.form = this.formService.parseForm(formDefinitionJSON); this.form = this.formService.parseForm(formDefinitionJSON);
} }
onLoadButtonClicked() { ngOnDestroy() {
this.formattedData = { this.onDestroy$.next(true);
'typeaheadField': this.typeaheadFieldValue, this.onDestroy$.complete();
'selectBox': this.selectFieldValue,
'radioButton': this.radioButtonFieldValue
};
} }
onLoadButtonClicked() {
this.formattedData = {
typeaheadField: this.typeaheadFieldValue,
selectBox: this.selectFieldValue,
radioButton: this.radioButtonFieldValue
};
}
} }

View File

@@ -18,7 +18,8 @@
import { Component, Inject, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; import { Component, Inject, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
import { FormModel, FormFieldModel, FormService, FormOutcomeEvent, NotificationService, CoreAutomationService } from '@alfresco/adf-core'; import { FormModel, FormFieldModel, FormService, FormOutcomeEvent, NotificationService, CoreAutomationService } from '@alfresco/adf-core';
import { InMemoryFormService } from '../../services/in-memory-form.service'; import { InMemoryFormService } from '../../services/in-memory-form.service';
import { Subscription } from 'rxjs'; import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'app-form', selector: 'app-form',
@@ -35,7 +36,6 @@ export class FormComponent implements OnInit, OnDestroy {
errorFields: FormFieldModel[] = []; errorFields: FormFieldModel[] = [];
formConfig: string; formConfig: string;
editor: any; editor: any;
private subscriptions: Subscription[] = [];
editorOptions = { editorOptions = {
theme: 'vs-dark', theme: 'vs-dark',
@@ -46,15 +46,11 @@ export class FormComponent implements OnInit, OnDestroy {
automaticLayout: true automaticLayout: true
}; };
private onDestroy$ = new Subject<boolean>();
constructor(@Inject(FormService) private formService: InMemoryFormService, constructor(@Inject(FormService) private formService: InMemoryFormService,
private notificationService: NotificationService, private notificationService: NotificationService,
private automationService: CoreAutomationService) { private automationService: CoreAutomationService) {
this.subscriptions.push(
formService.executeOutcome.subscribe((formOutcomeEvent: FormOutcomeEvent) => {
formOutcomeEvent.preventDefault();
})
);
} }
logErrors(errorFields: FormFieldModel[]) { logErrors(errorFields: FormFieldModel[]) {
@@ -62,13 +58,21 @@ export class FormComponent implements OnInit, OnDestroy {
} }
ngOnInit() { ngOnInit() {
this.formConfig = JSON.stringify(this.automationService.forms.getFormDefinition()); this.formService.executeOutcome
.pipe(takeUntil(this.onDestroy$))
.subscribe((formOutcomeEvent: FormOutcomeEvent) => {
formOutcomeEvent.preventDefault();
});
this.formConfig = JSON.stringify(
this.automationService.forms.getFormDefinition()
);
this.parseForm(); this.parseForm();
} }
ngOnDestroy() { ngOnDestroy() {
this.subscriptions.forEach((subscription) => subscription.unsubscribe()); this.onDestroy$.next(true);
this.subscriptions = []; this.onDestroy$.complete();
} }
onInitFormEditor(editor) { onInitFormEditor(editor) {

View File

@@ -24,14 +24,14 @@ export class HeaderDataService {
show = true; show = true;
@Output() hideMenu: EventEmitter<boolean> = new EventEmitter(); @Output() hideMenu = new EventEmitter<boolean>();
@Output() color: EventEmitter<string> = new EventEmitter(); @Output() color = new EventEmitter<string>();
@Output() title: EventEmitter<string> = new EventEmitter(); @Output() title = new EventEmitter<string>();
@Output() logo: EventEmitter<string> = new EventEmitter(); @Output() logo = new EventEmitter<string>();
@Output() redirectUrl: EventEmitter<string | any[]> = new EventEmitter(); @Output() redirectUrl = new EventEmitter<string | any[]>();
@Output() tooltip: EventEmitter<string> = new EventEmitter(); @Output() tooltip = new EventEmitter<string>();
@Output() position: EventEmitter<string> = new EventEmitter(); @Output() position = new EventEmitter<string>();
@Output() hideSidenav: EventEmitter<string> = new EventEmitter(); @Output() hideSidenav = new EventEmitter<boolean>();
hideMenuButton() { hideMenuButton() {
this.show = !this.show; this.show = !this.show;
@@ -59,11 +59,11 @@ export class HeaderDataService {
this.tooltip.emit(tooltip); this.tooltip.emit(tooltip);
} }
changePosition(position) { changePosition(position: string) {
this.position.emit(position); this.position.emit(position);
} }
changeSidenavVisibility(hideSidenav) { changeSidenavVisibility(hideSidenav: boolean) {
this.hideSidenav.emit(hideSidenav); this.hideSidenav.emit(hideSidenav);
} }
} }

View File

@@ -15,23 +15,30 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, HostListener } from '@angular/core'; import { Component, HostListener, OnDestroy, OnInit } from '@angular/core';
import { LogService, ObjectDataTableAdapter } from '@alfresco/adf-core'; import { LogService, ObjectDataTableAdapter } from '@alfresco/adf-core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'app-log', selector: 'app-log',
templateUrl: './log.component.html', templateUrl: './log.component.html',
styleUrls: ['./log.component.css'] styleUrls: ['./log.component.css']
}) })
export class LogComponent { export class LogComponent implements OnInit, OnDestroy {
logs: any[] = []; logs: any[] = [];
show = false; show = false;
ctrlLKey = 12; ctrlLKey = 12;
logsData: ObjectDataTableAdapter; logsData: ObjectDataTableAdapter;
constructor(public logService: LogService) { private onDestroy$ = new Subject<boolean>();
logService.onMessage.subscribe((message) => { constructor(public logService: LogService) {}
ngOnInit() {
this.logService.onMessage
.pipe(takeUntil(this.onDestroy$))
.subscribe(message => {
let contentMessage = ''; let contentMessage = '';
try { try {
contentMessage = JSON.stringify(message.text); contentMessage = JSON.stringify(message.text);
@@ -40,13 +47,27 @@ export class LogComponent {
} }
this.logs.push({ type: message.type, text: contentMessage }); this.logs.push({ type: message.type, text: contentMessage });
this.logsData = new ObjectDataTableAdapter(this.logs, [ this.logsData = new ObjectDataTableAdapter(this.logs, [
{ type: 'text', key: 'type', title: 'Log level', sortable: true }, {
{ type: 'text', key: 'text', title: 'Message', sortable: false } type: 'text',
key: 'type',
title: 'Log level',
sortable: true
},
{
type: 'text',
key: 'text',
title: 'Message',
sortable: false
}
]); ]);
}); });
} }
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
@HostListener('document:keypress', ['$event']) @HostListener('document:keypress', ['$event'])
handleKeyboardEvent(event: KeyboardEvent) { handleKeyboardEvent(event: KeyboardEvent) {
const key = event.keyCode; const key = event.keyCode;
@@ -54,6 +75,5 @@ export class LogComponent {
if (key === this.ctrlLKey) { if (key === this.ctrlLKey) {
this.show = !this.show; this.show = !this.show;
} }
} }
} }

View File

@@ -15,16 +15,18 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, OnInit } from '@angular/core'; import { Component, OnInit, OnDestroy } from '@angular/core';
import { NotificationService } from '@alfresco/adf-core'; import { NotificationService } from '@alfresco/adf-core';
import { MatSnackBarConfig } from '@angular/material'; import { MatSnackBarConfig } from '@angular/material';
import { FormBuilder, FormGroup, FormControl } from '@angular/forms'; import { FormBuilder, FormGroup, FormControl } from '@angular/forms';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
templateUrl: './notifications.component.html', templateUrl: './notifications.component.html',
styleUrls: ['./notifications.component.scss'] styleUrls: ['./notifications.component.scss']
}) })
export class NotificationsComponent implements OnInit { export class NotificationsComponent implements OnInit, OnDestroy {
message = 'I ♥️ ADF'; message = 'I ♥️ ADF';
withAction = false; withAction = false;
@@ -55,6 +57,8 @@ export class NotificationsComponent implements OnInit {
defaultDuration = 20000; defaultDuration = 20000;
private onDestroy$ = new Subject<boolean>();
constructor(private notificationService: NotificationService, constructor(private notificationService: NotificationService,
private formBuilder: FormBuilder) { private formBuilder: FormBuilder) {
this.snackBarConfig.duration = this.defaultDuration; this.snackBarConfig.duration = this.defaultDuration;
@@ -69,10 +73,15 @@ export class NotificationsComponent implements OnInit {
}); });
this.configForm.valueChanges this.configForm.valueChanges
.subscribe((configFormValues) => .pipe(takeUntil(this.onDestroy$))
.subscribe(configFormValues =>
this.setSnackBarConfig(configFormValues) this.setSnackBarConfig(configFormValues)
); );
}
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
} }
setSnackBarConfig(configFormValues: any) { setSnackBarConfig(configFormValues: any) {

View File

@@ -48,7 +48,9 @@ export class DemoPermissionComponent implements OnInit {
} }
}); });
} }
this.nodeService.getNode(this.nodeId, {include: ['permissions'] }).subscribe( (currentNode: MinimalNodeEntryEntity) => { this.nodeService
.getNode(this.nodeId, {include: ['permissions'] })
.subscribe( (currentNode: MinimalNodeEntryEntity) => {
this.toggleStatus = currentNode.permissions.isInheritanceEnabled; this.toggleStatus = currentNode.permissions.isInheritanceEnabled;
}); });
} }
@@ -63,9 +65,12 @@ export class DemoPermissionComponent implements OnInit {
} }
openAddPermissionDialog(event: Event) { openAddPermissionDialog(event: Event) {
this.nodePermissionDialogService.updateNodePermissionByDialog(this.nodeId).subscribe( this.nodePermissionDialogService
.updateNodePermissionByDialog(this.nodeId)
.subscribe(
() => this.displayPermissionComponent.reload(), () => this.displayPermissionComponent.reload(),
(error) => this.showErrorMessage(error)); (error) => this.showErrorMessage(error)
);
} }
showErrorMessage(error) { showErrorMessage(error) {

View File

@@ -15,17 +15,18 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, OnInit } from '@angular/core'; import { Component, OnInit, OnDestroy } from '@angular/core';
import { FormGroup, FormBuilder, Validators, FormControl, AbstractControl } from '@angular/forms'; import { FormGroup, FormBuilder, Validators, FormControl, AbstractControl } from '@angular/forms';
import { ActivatedRoute, Params } from '@angular/router'; import { ActivatedRoute, Params } from '@angular/router';
import { debounceTime } from 'rxjs/operators'; import { debounceTime, takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs';
@Component({ @Component({
templateUrl: './process-list-demo.component.html', templateUrl: './process-list-demo.component.html',
styleUrls: [`./process-list-demo.component.scss`] styleUrls: [`./process-list-demo.component.scss`]
}) })
export class ProcessListDemoComponent implements OnInit { export class ProcessListDemoComponent implements OnInit, OnDestroy {
DEFAULT_SIZE = 20; DEFAULT_SIZE = 20;
@@ -54,6 +55,8 @@ export class ProcessListDemoComponent implements OnInit {
{value: 'created-desc', title: 'Created (desc)'} {value: 'created-desc', title: 'Created (desc)'}
]; ];
private onDestroy$ = new Subject<boolean>();
constructor(private route: ActivatedRoute, constructor(private route: ActivatedRoute,
private formBuilder: FormBuilder) { private formBuilder: FormBuilder) {
} }
@@ -72,6 +75,11 @@ export class ProcessListDemoComponent implements OnInit {
this.buildForm(); this.buildForm();
} }
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
buildForm() { buildForm() {
this.processListForm = this.formBuilder.group({ this.processListForm = this.formBuilder.group({
processAppId: new FormControl(this.appId, [Validators.pattern('^[0-9]*$'), Validators.min(this.minValue)]), processAppId: new FormControl(this.appId, [Validators.pattern('^[0-9]*$'), Validators.min(this.minValue)]),
@@ -84,10 +92,9 @@ export class ProcessListDemoComponent implements OnInit {
}); });
this.processListForm.valueChanges this.processListForm.valueChanges
.pipe( .pipe(takeUntil(this.onDestroy$))
debounceTime(500) .pipe(debounceTime(500))
) .subscribe(processFilter => {
.subscribe((processFilter) => {
if (this.isFormValid()) { if (this.isFormValid()) {
this.filterProcesses(processFilter); this.filterProcesses(processFilter);
} }

View File

@@ -15,32 +15,25 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, OnDestroy, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';
@Component({ @Component({
selector: 'app-form-node-viewer', selector: 'app-form-node-viewer',
templateUrl: './form-node-viewer.component.html', templateUrl: './form-node-viewer.component.html',
styleUrls: ['./form-node-viewer.component.css'] styleUrls: ['./form-node-viewer.component.css']
}) })
export class FormNodeViewerComponent implements OnInit, OnDestroy { export class FormNodeViewerComponent implements OnInit {
nodeId: string; nodeId: string;
private sub: Subscription;
constructor(private route: ActivatedRoute) { constructor(private route: ActivatedRoute) {
} }
ngOnInit() { ngOnInit() {
this.sub = this.route.params.subscribe((params) => { this.route.params.subscribe((params) => {
this.nodeId = params['id']; this.nodeId = params['id'];
}); });
} }
ngOnDestroy() {
this.sub.unsubscribe();
}
} }

View File

@@ -15,9 +15,8 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, OnDestroy, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';
import { Params } from '@angular/router/src/shared'; import { Params } from '@angular/router/src/shared';
@Component({ @Component({
@@ -25,23 +24,16 @@ import { Params } from '@angular/router/src/shared';
templateUrl: './form-viewer.component.html', templateUrl: './form-viewer.component.html',
styleUrls: ['./form-viewer.component.css'] styleUrls: ['./form-viewer.component.css']
}) })
export class FormViewerComponent implements OnInit, OnDestroy { export class FormViewerComponent implements OnInit {
taskId: string; taskId: string;
private sub: Subscription;
constructor(private route: ActivatedRoute) { constructor(private route: ActivatedRoute) {
} }
ngOnInit() { ngOnInit() {
this.sub = this.route.params.subscribe((params: Params) => { this.route.params.subscribe((params: Params) => {
this.taskId = params['id']; this.taskId = params['id'];
}); });
} }
ngOnDestroy() {
this.sub.unsubscribe();
}
} }

View File

@@ -22,7 +22,8 @@ import { UploadService } from '@alfresco/adf-core';
import { AlfrescoApiService } from '@alfresco/adf-core'; import { AlfrescoApiService } from '@alfresco/adf-core';
import { AppConfigService } from '@alfresco/adf-core'; import { AppConfigService } from '@alfresco/adf-core';
import { PreviewService } from '../../services/preview.service'; import { PreviewService } from '../../services/preview.service';
import { Subscription } from 'rxjs'; import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
export function processUploadServiceFactory(api: AlfrescoApiService, config: AppConfigService) { export function processUploadServiceFactory(api: AlfrescoApiService, config: AppConfigService) {
return new ProcessUploadService(api, config); return new ProcessUploadService(api, config);
@@ -51,7 +52,7 @@ export class ProcessAttachmentsComponent implements OnInit, OnChanges, OnDestroy
processInstance: ProcessInstance; processInstance: ProcessInstance;
private subscriptions: Subscription[] = []; private onDestroy$ = new Subject<boolean>();
constructor( constructor(
private uploadService: UploadService, private uploadService: UploadService,
@@ -60,11 +61,9 @@ export class ProcessAttachmentsComponent implements OnInit, OnChanges, OnDestroy
) {} ) {}
ngOnInit() { ngOnInit() {
this.subscriptions.push( this.uploadService.fileUploadComplete
this.uploadService.fileUploadComplete.subscribe( .pipe(takeUntil(this.onDestroy$))
(value) => this.onFileUploadComplete(value.data) .subscribe(value => this.onFileUploadComplete(value.data));
)
);
} }
ngOnChanges() { ngOnChanges() {
@@ -77,8 +76,8 @@ export class ProcessAttachmentsComponent implements OnInit, OnChanges, OnDestroy
} }
ngOnDestroy() { ngOnDestroy() {
this.subscriptions.forEach((subscription) => subscription.unsubscribe()); this.onDestroy$.next(true);
this.subscriptions = []; this.onDestroy$.complete();
} }
onFileUploadComplete(content: any) { onFileUploadComplete(content: any) {

View File

@@ -35,7 +35,7 @@ import {
UserProcessInstanceFilterRepresentation UserProcessInstanceFilterRepresentation
} from '@alfresco/js-api'; } from '@alfresco/js-api';
import { import {
FORM_FIELD_VALIDATORS, FormEvent, FormFieldEvent, FormRenderingService, FormService, FORM_FIELD_VALIDATORS, FormRenderingService, FormService,
DynamicTableRow, ValidateDynamicTableRowEvent, AppConfigService, PaginationComponent, UserPreferenceValues DynamicTableRow, ValidateDynamicTableRowEvent, AppConfigService, PaginationComponent, UserPreferenceValues
} from '@alfresco/adf-core'; } from '@alfresco/adf-core';
@@ -57,12 +57,13 @@ import {
TaskListComponent TaskListComponent
} from '@alfresco/adf-process-services'; } from '@alfresco/adf-process-services';
import { LogService } from '@alfresco/adf-core'; import { LogService } from '@alfresco/adf-core';
import { AlfrescoApiService, UserPreferencesService, ValidateFormEvent } from '@alfresco/adf-core'; import { AlfrescoApiService, UserPreferencesService } from '@alfresco/adf-core';
import { Subscription } from 'rxjs'; import { Subject } from 'rxjs';
import { /*CustomEditorComponent*/ CustomStencil01 } from './custom-editor/custom-editor.component'; import { /*CustomEditorComponent*/ CustomStencil01 } from './custom-editor/custom-editor.component';
import { DemoFieldValidator } from './demo-field-validator'; import { DemoFieldValidator } from './demo-field-validator';
import { PreviewService } from '../../services/preview.service'; import { PreviewService } from '../../services/preview.service';
import { Location } from '@angular/common'; import { Location } from '@angular/common';
import { takeUntil } from 'rxjs/operators';
const currentProcessIdNew = '__NEW__'; const currentProcessIdNew = '__NEW__';
const currentTaskIdNew = '__NEW__'; const currentTaskIdNew = '__NEW__';
@@ -160,7 +161,7 @@ export class ProcessServiceComponent implements AfterViewInit, OnDestroy, OnInit
new DemoFieldValidator() new DemoFieldValidator()
]; ];
private subscriptions: Subscription[] = []; private onDestroy$ = new Subject<boolean>();
constructor(private elementRef: ElementRef, constructor(private elementRef: ElementRef,
private route: ActivatedRoute, private route: ActivatedRoute,
@@ -184,17 +185,28 @@ export class ProcessServiceComponent implements AfterViewInit, OnDestroy, OnInit
// Uncomment this line to map 'custom_stencil_01' to local editor component // Uncomment this line to map 'custom_stencil_01' to local editor component
formRenderingService.setComponentTypeResolver('custom_stencil_01', () => CustomStencil01, true); formRenderingService.setComponentTypeResolver('custom_stencil_01', () => CustomStencil01, true);
this.subscriptions.push( formService.formLoaded
formService.formLoaded.subscribe((formEvent: FormEvent) => { .pipe(takeUntil(this.onDestroy$))
.subscribe(formEvent => {
this.logService.log(`Form loaded: ${formEvent.form.id}`); this.logService.log(`Form loaded: ${formEvent.form.id}`);
}), });
formService.formFieldValueChanged.subscribe((formFieldEvent: FormFieldEvent) => {
formService.formFieldValueChanged
.pipe(takeUntil(this.onDestroy$))
.subscribe(formFieldEvent => {
this.logService.log(`Field value changed. Form: ${formFieldEvent.form.id}, Field: ${formFieldEvent.field.id}, Value: ${formFieldEvent.field.value}`); this.logService.log(`Field value changed. Form: ${formFieldEvent.form.id}, Field: ${formFieldEvent.field.id}, Value: ${formFieldEvent.field.value}`);
}), });
this.preferenceService.select(UserPreferenceValues.PaginationSize).subscribe((pageSize) => {
this.preferenceService
.select(UserPreferenceValues.PaginationSize)
.pipe(takeUntil(this.onDestroy$))
.subscribe((pageSize) => {
this.paginationPageSize = pageSize; this.paginationPageSize = pageSize;
}), });
formService.validateDynamicTableRow.subscribe(
formService.validateDynamicTableRow
.pipe(takeUntil(this.onDestroy$))
.subscribe(
(validateDynamicTableRowEvent: ValidateDynamicTableRowEvent) => { (validateDynamicTableRowEvent: ValidateDynamicTableRowEvent) => {
const row: DynamicTableRow = validateDynamicTableRowEvent.row; const row: DynamicTableRow = validateDynamicTableRowEvent.row;
if (row && row.value && row.value.name === 'admin') { if (row && row.value && row.value.name === 'admin') {
@@ -203,20 +215,25 @@ export class ProcessServiceComponent implements AfterViewInit, OnDestroy, OnInit
validateDynamicTableRowEvent.preventDefault(); validateDynamicTableRowEvent.preventDefault();
} }
} }
),
formService.formContentClicked.subscribe((content) => {
this.showContentPreview(content);
}),
formService.validateForm.subscribe((validateFormEvent: ValidateFormEvent) => {
this.logService.log('Error form:' + validateFormEvent.errorsField);
})
); );
formService.formContentClicked
.pipe(takeUntil(this.onDestroy$))
.subscribe((content) => {
this.showContentPreview(content);
});
formService.validateForm
.pipe(takeUntil(this.onDestroy$))
.subscribe(validateFormEvent => {
this.logService.log('Error form:' + validateFormEvent.errorsField);
});
// Uncomment this block to see form event handling in action // Uncomment this block to see form event handling in action
/* /*
formService.formEvents.subscribe((event: Event) => { formService.formEvents
.pipe(takeUntil(this.onDestroy$))
.subscribe((event: Event) => {
this.logService.log('Event fired:' + event.type); this.logService.log('Event fired:' + event.type);
this.logService.log('Event Target:' + event.target); this.logService.log('Event Target:' + event.target);
}); });
@@ -247,8 +264,8 @@ export class ProcessServiceComponent implements AfterViewInit, OnDestroy, OnInit
} }
ngOnDestroy() { ngOnDestroy() {
this.subscriptions.forEach((subscription) => subscription.unsubscribe()); this.onDestroy$.next(true);
this.subscriptions = []; this.onDestroy$.complete();
} }
onTaskFilterClick(filter: FilterRepresentationModel): void { onTaskFilterClick(filter: FilterRepresentationModel): void {

View File

@@ -19,12 +19,13 @@ import { Component, Input, OnChanges, OnInit, ViewChild, OnDestroy } from '@angu
import { import {
TaskListService, TaskListService,
TaskAttachmentListComponent, TaskAttachmentListComponent,
TaskDetailsModel, TaskUploadService,
TaskUploadService TaskDetailsModel
} from '@alfresco/adf-process-services'; } from '@alfresco/adf-process-services';
import { UploadService, AlfrescoApiService, AppConfigService, FileUploadCompleteEvent } from '@alfresco/adf-core'; import { UploadService, AlfrescoApiService, AppConfigService } from '@alfresco/adf-core';
import { PreviewService } from '../../services/preview.service'; import { PreviewService } from '../../services/preview.service';
import { Subscription } from 'rxjs'; import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
export function taskUploadServiceFactory(api: AlfrescoApiService, config: AppConfigService) { export function taskUploadServiceFactory(api: AlfrescoApiService, config: AppConfigService) {
return new TaskUploadService(api, config); return new TaskUploadService(api, config);
@@ -51,9 +52,9 @@ export class TaskAttachmentsComponent implements OnInit, OnChanges, OnDestroy {
@Input() @Input()
taskId: string; taskId: string;
taskDetails: any; taskDetails: TaskDetailsModel;
private subscriptions: Subscription[] = []; private onDestroy$ = new Subject<boolean>();
constructor( constructor(
private uploadService: UploadService, private uploadService: UploadService,
@@ -62,25 +63,22 @@ export class TaskAttachmentsComponent implements OnInit, OnChanges, OnDestroy {
} }
ngOnInit() { ngOnInit() {
this.subscriptions.push( this.uploadService.fileUploadComplete
this.uploadService.fileUploadComplete.subscribe( .pipe(takeUntil(this.onDestroy$))
(fileUploadCompleteEvent: FileUploadCompleteEvent) => this.onFileUploadComplete(fileUploadCompleteEvent.data) .subscribe(event => this.onFileUploadComplete(event.data));
)
);
} }
ngOnChanges() { ngOnChanges() {
if (this.taskId) { if (this.taskId) {
this.activitiTaskList.getTaskDetails(this.taskId) this.activitiTaskList
.subscribe((taskDetails: TaskDetailsModel) => { .getTaskDetails(this.taskId)
this.taskDetails = taskDetails; .subscribe(taskDetails => this.taskDetails = taskDetails);
});
} }
} }
ngOnDestroy() { ngOnDestroy() {
this.subscriptions.forEach((subscription) => subscription.unsubscribe()); this.onDestroy$.next(true);
this.subscriptions = []; this.onDestroy$.complete();
} }
onFileUploadComplete(content: any) { onFileUploadComplete(content: any) {

View File

@@ -20,7 +20,8 @@ import { Router, ActivatedRoute, Params } from '@angular/router';
import { NodePaging, Pagination, ResultSetPaging } from '@alfresco/js-api'; import { NodePaging, Pagination, ResultSetPaging } from '@alfresco/js-api';
import { SearchQueryBuilderService } from '@alfresco/adf-content-services'; import { SearchQueryBuilderService } from '@alfresco/adf-content-services';
import { UserPreferencesService, SearchService, AppConfigService } from '@alfresco/adf-core'; import { UserPreferencesService, SearchService, AppConfigService } from '@alfresco/adf-core';
import { Subscription } from 'rxjs'; import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'app-search-result-component', selector: 'app-search-result-component',
@@ -38,7 +39,7 @@ export class SearchResultComponent implements OnInit, OnDestroy {
sorting = ['name', 'asc']; sorting = ['name', 'asc'];
private subscriptions: Subscription[] = []; private onDestroy$ = new Subject<boolean>();
constructor(public router: Router, constructor(public router: Router,
private config: AppConfigService, private config: AppConfigService,
@@ -55,19 +56,21 @@ export class SearchResultComponent implements OnInit, OnDestroy {
this.sorting = this.getSorting(); this.sorting = this.getSorting();
this.subscriptions.push( this.queryBuilder.updated
this.queryBuilder.updated.subscribe(() => { .pipe(takeUntil(this.onDestroy$))
.subscribe(() => {
this.sorting = this.getSorting(); this.sorting = this.getSorting();
this.isLoading = true; this.isLoading = true;
}), });
this.queryBuilder.executed.subscribe((resultSetPaging: ResultSetPaging) => { this.queryBuilder.executed
.pipe(takeUntil(this.onDestroy$))
.subscribe((resultSetPaging: ResultSetPaging) => {
this.queryBuilder.paging.skipCount = 0; this.queryBuilder.paging.skipCount = 0;
this.onSearchResultLoaded(resultSetPaging); this.onSearchResultLoaded(resultSetPaging);
this.isLoading = false; this.isLoading = false;
}) });
);
if (this.route) { if (this.route) {
this.route.params.forEach((params: Params) => { this.route.params.forEach((params: Params) => {
@@ -102,8 +105,8 @@ export class SearchResultComponent implements OnInit, OnDestroy {
} }
ngOnDestroy() { ngOnDestroy() {
this.subscriptions.forEach((subscription) => subscription.unsubscribe()); this.onDestroy$.next(true);
this.subscriptions = []; this.onDestroy$.complete();
} }
onSearchResultLoaded(resultSetPaging: ResultSetPaging) { onSearchResultLoaded(resultSetPaging: ResultSetPaging) {

View File

@@ -15,11 +15,12 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, OnInit } from '@angular/core'; import { Component, OnInit, OnDestroy } from '@angular/core';
import { FormGroup, FormBuilder, Validators, FormControl, AbstractControl } from '@angular/forms'; import { FormGroup, FormBuilder, Validators, FormControl, AbstractControl } from '@angular/forms';
import { ActivatedRoute, Params } from '@angular/router'; import { ActivatedRoute, Params } from '@angular/router';
import { debounceTime } from 'rxjs/operators'; import { debounceTime, takeUntil } from 'rxjs/operators';
import moment from 'moment-es6'; import moment from 'moment-es6';
import { Subject } from 'rxjs';
@Component({ @Component({
selector: 'app-task-list-demo', selector: 'app-task-list-demo',
@@ -27,7 +28,7 @@ import moment from 'moment-es6';
styleUrls: [`./task-list-demo.component.scss`] styleUrls: [`./task-list-demo.component.scss`]
}) })
export class TaskListDemoComponent implements OnInit { export class TaskListDemoComponent implements OnInit, OnDestroy {
DEFAULT_SIZE = 20; DEFAULT_SIZE = 20;
taskListForm: FormGroup; taskListForm: FormGroup;
@@ -75,6 +76,8 @@ export class TaskListDemoComponent implements OnInit {
{value: 'due-desc', title: 'Due (desc)'} {value: 'due-desc', title: 'Due (desc)'}
]; ];
private onDestroy$ = new Subject<boolean>();
constructor(private route: ActivatedRoute, constructor(private route: ActivatedRoute,
private formBuilder: FormBuilder) { private formBuilder: FormBuilder) {
} }
@@ -94,6 +97,11 @@ export class TaskListDemoComponent implements OnInit {
this.buildForm(); this.buildForm();
} }
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
buildForm() { buildForm() {
this.taskListForm = this.formBuilder.group({ this.taskListForm = this.formBuilder.group({
taskAppId: new FormControl(this.defaultAppId, [Validators.pattern('^[0-9]*$')]), taskAppId: new FormControl(this.defaultAppId, [Validators.pattern('^[0-9]*$')]),
@@ -114,9 +122,10 @@ export class TaskListDemoComponent implements OnInit {
this.taskListForm.valueChanges this.taskListForm.valueChanges
.pipe( .pipe(
debounceTime(500) debounceTime(500),
takeUntil(this.onDestroy$)
) )
.subscribe((taskFilter) => { .subscribe(taskFilter => {
if (this.isFormValid()) { if (this.isFormValid()) {
this.filterTasks(taskFilter); this.filterTasks(taskFilter);
} }

View File

@@ -15,32 +15,42 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, ViewChild } from '@angular/core'; import { Component, ViewChild, OnInit, OnDestroy } from '@angular/core';
import { DocumentListComponent } from '@alfresco/adf-content-services'; import { DocumentListComponent } from '@alfresco/adf-content-services';
import { UserPreferencesService, UserPreferenceValues, RestoreMessageModel, NotificationService } from '@alfresco/adf-core'; import { UserPreferencesService, UserPreferenceValues, RestoreMessageModel, NotificationService } from '@alfresco/adf-core';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { PathInfoEntity } from '@alfresco/js-api'; import { PathInfoEntity } from '@alfresco/js-api';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
templateUrl: './trashcan.component.html', templateUrl: './trashcan.component.html',
styleUrls: ['trashcan.component.scss'] styleUrls: ['trashcan.component.scss']
}) })
export class TrashcanComponent { export class TrashcanComponent implements OnInit, OnDestroy {
@ViewChild('documentList') @ViewChild('documentList')
documentList: DocumentListComponent; documentList: DocumentListComponent;
currentLocale; currentLocale;
private onDestroy$ = new Subject<boolean>();
constructor( constructor(
private preference: UserPreferencesService, private preference: UserPreferencesService,
private router: Router, private router: Router,
private notificationService: NotificationService private notificationService: NotificationService) {
) { }
ngOnInit() {
this.preference this.preference
.select(UserPreferenceValues.Locale) .select(UserPreferenceValues.Locale)
.subscribe((locale) => { .pipe(takeUntil(this.onDestroy$))
this.currentLocale = locale; .subscribe(locale => this.currentLocale = locale);
}); }
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
} }
onRestore(restoreMessage: RestoreMessageModel) { onRestore(restoreMessage: RestoreMessageModel) {

View File

@@ -58,7 +58,7 @@ describe('Breadcrumb', () => {
it('should root be present as default node if the path is null', () => { it('should root be present as default node if the path is null', () => {
component.root = 'default'; component.root = 'default';
component.folderNode = fakeNodeWithCreatePermission; component.folderNode = fakeNodeWithCreatePermission;
component.ngOnChanges(null); component.ngOnChanges();
expect(component.route[0].name).toBe('default'); expect(component.route[0].name).toBe('default');
}); });
@@ -215,7 +215,7 @@ describe('Breadcrumb', () => {
return transformNode; return transformNode;
}); });
component.folderNode = node; component.folderNode = node;
component.ngOnChanges(null); component.ngOnChanges();
expect(component.route.length).toBe(4); expect(component.route.length).toBe(4);
expect(component.route[3].id).toBe('test-id'); expect(component.route[3].id).toBe('test-id');
expect(component.route[3].name).toBe('test-name'); expect(component.route[3].name).toBe('test-name');

View File

@@ -22,13 +22,15 @@ import {
OnChanges, OnChanges,
OnInit, OnInit,
Output, Output,
SimpleChanges,
ViewChild, ViewChild,
ViewEncapsulation ViewEncapsulation,
OnDestroy
} from '@angular/core'; } from '@angular/core';
import { MatSelect } from '@angular/material'; import { MatSelect } from '@angular/material';
import { Node, PathElementEntity } from '@alfresco/js-api'; import { Node, PathElementEntity } from '@alfresco/js-api';
import { DocumentListComponent } from '../document-list'; import { DocumentListComponent } from '../document-list';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'adf-breadcrumb', selector: 'adf-breadcrumb',
@@ -39,7 +41,7 @@ import { DocumentListComponent } from '../document-list';
'class': 'adf-breadcrumb' 'class': 'adf-breadcrumb'
} }
}) })
export class BreadcrumbComponent implements OnInit, OnChanges { export class BreadcrumbComponent implements OnInit, OnChanges, OnDestroy {
/** Active node, builds UI based on folderNode.path.elements collection. */ /** Active node, builds UI based on folderNode.path.elements collection. */
@Input() @Input()
@@ -84,6 +86,8 @@ export class BreadcrumbComponent implements OnInit, OnChanges {
route: PathElementEntity[] = []; route: PathElementEntity[] = [];
private onDestroy$ = new Subject<boolean>();
get hasRoot(): boolean { get hasRoot(): boolean {
return !!this.root; return !!this.root;
} }
@@ -96,14 +100,16 @@ export class BreadcrumbComponent implements OnInit, OnChanges {
this.transform = this.transform ? this.transform : null; this.transform = this.transform ? this.transform : null;
if (this.target) { if (this.target) {
this.target.$folderNode.subscribe((folderNode: Node) => { this.target.$folderNode
.pipe(takeUntil(this.onDestroy$))
.subscribe((folderNode: Node) => {
this.folderNode = folderNode; this.folderNode = folderNode;
this.recalculateNodes(); this.recalculateNodes();
}); });
} }
} }
ngOnChanges(changes: SimpleChanges): void { ngOnChanges(): void {
this.recalculateNodes(); this.recalculateNodes();
} }
@@ -184,4 +190,9 @@ export class BreadcrumbComponent implements OnInit, OnChanges {
} }
} }
} }
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
} }

View File

@@ -57,7 +57,7 @@ describe('DropdownBreadcrumb', () => {
function triggerComponentChange(fakeNodeData) { function triggerComponentChange(fakeNodeData) {
component.folderNode = fakeNodeData; component.folderNode = fakeNodeData;
component.ngOnChanges(null); component.ngOnChanges();
fixture.detectChanges(); fixture.detectChanges();
} }

View File

@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, EventEmitter, Input, OnInit, Output, ViewChild, ViewEncapsulation } from '@angular/core'; import { Component, EventEmitter, Input, OnInit, Output, ViewChild, ViewEncapsulation, OnDestroy } from '@angular/core';
import { import {
HighlightDirective, HighlightDirective,
UserPreferencesService, UserPreferencesService,
@@ -29,9 +29,10 @@ import { DocumentListComponent } from '../document-list/components/document-list
import { RowFilter } from '../document-list/data/row-filter.model'; import { RowFilter } from '../document-list/data/row-filter.model';
import { ImageResolver } from '../document-list/data/image-resolver.model'; import { ImageResolver } from '../document-list/data/image-resolver.model';
import { ContentNodeSelectorService } from './content-node-selector.service'; import { ContentNodeSelectorService } from './content-node-selector.service';
import { debounceTime } from 'rxjs/operators'; import { debounceTime, takeUntil } from 'rxjs/operators';
import { CustomResourcesService } from '../document-list/services/custom-resources.service'; import { CustomResourcesService } from '../document-list/services/custom-resources.service';
import { ShareDataRow } from '../document-list'; import { ShareDataRow } from '../document-list';
import { Subject } from 'rxjs';
export type ValidationFunction = (entry: Node) => boolean; export type ValidationFunction = (entry: Node) => boolean;
@@ -44,7 +45,7 @@ const defaultValidation = () => true;
encapsulation: ViewEncapsulation.None, encapsulation: ViewEncapsulation.None,
host: { 'class': 'adf-content-node-selector-panel' } host: { 'class': 'adf-content-node-selector-panel' }
}) })
export class ContentNodeSelectorPanelComponent implements OnInit { export class ContentNodeSelectorPanelComponent implements OnInit, OnDestroy {
DEFAULT_PAGINATION: Pagination = new Pagination({ DEFAULT_PAGINATION: Pagination = new Pagination({
maxItems: 25, maxItems: 25,
@@ -166,21 +167,11 @@ export class ContentNodeSelectorPanelComponent implements OnInit {
target: PaginatedComponent; target: PaginatedComponent;
private onDestroy$ = new Subject<boolean>();
constructor(private contentNodeSelectorService: ContentNodeSelectorService, constructor(private contentNodeSelectorService: ContentNodeSelectorService,
private customResourcesService: CustomResourcesService, private customResourcesService: CustomResourcesService,
private userPreferencesService: UserPreferencesService) { private userPreferencesService: UserPreferencesService) {
this.searchInput.valueChanges
.pipe(
debounceTime(this.debounceSearch)
)
.subscribe((searchValue) => {
this.search(searchValue);
});
this.userPreferencesService.select(UserPreferenceValues.PaginationSize).subscribe((pagSize) => {
this.pageSize = pagSize;
});
} }
set chosenNode(value: Node) { set chosenNode(value: Node) {
@@ -197,6 +188,18 @@ export class ContentNodeSelectorPanelComponent implements OnInit {
} }
ngOnInit() { ngOnInit() {
this.searchInput.valueChanges
.pipe(
debounceTime(this.debounceSearch),
takeUntil(this.onDestroy$)
)
.subscribe(searchValue => this.search(searchValue));
this.userPreferencesService
.select(UserPreferenceValues.PaginationSize)
.pipe(takeUntil(this.onDestroy$))
.subscribe(pagSize => this.pageSize = pagSize);
this.target = this.documentList; this.target = this.documentList;
this.folderIdToShow = this.currentFolderId; this.folderIdToShow = this.currentFolderId;
@@ -204,6 +207,11 @@ export class ContentNodeSelectorPanelComponent implements OnInit {
this.isSelectionValid = this.isSelectionValid ? this.isSelectionValid : defaultValidation; this.isSelectionValid = this.isSelectionValid ? this.isSelectionValid : defaultValidation;
} }
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
private createRowFilter(filter?: RowFilter) { private createRowFilter(filter?: RowFilter) {
if (!filter) { if (!filter) {
filter = () => true; filter = () => true;

View File

@@ -25,12 +25,13 @@ import {
} from '@angular/core'; } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef, MatDialog, MatSlideToggleChange } from '@angular/material'; import { MAT_DIALOG_DATA, MatDialogRef, MatDialog, MatSlideToggleChange } from '@angular/material';
import { FormGroup, FormControl } from '@angular/forms'; import { FormGroup, FormControl } from '@angular/forms';
import { Subscription, Observable, throwError } from 'rxjs'; import { Observable, throwError, Subject } from 'rxjs';
import { import {
skip, skip,
distinctUntilChanged, distinctUntilChanged,
mergeMap, mergeMap,
catchError catchError,
takeUntil
} from 'rxjs/operators'; } from 'rxjs/operators';
import { import {
SharedLinksApiService, SharedLinksApiService,
@@ -52,7 +53,6 @@ import { ContentNodeShareSettings } from './content-node-share.settings';
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class ShareDialogComponent implements OnInit, OnDestroy { export class ShareDialogComponent implements OnInit, OnDestroy {
private subscriptions: Subscription[] = [];
minDate = moment().add(1, 'd'); minDate = moment().add(1, 'd');
sharedId: string; sharedId: string;
@@ -75,6 +75,8 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
@ViewChild('dateTimePickerInput') @ViewChild('dateTimePickerInput')
dateTimePickerInput; dateTimePickerInput;
private onDestroy$ = new Subject<boolean>();
constructor( constructor(
private appConfigService: AppConfigService, private appConfigService: AppConfigService,
private sharedLinksApiService: SharedLinksApiService, private sharedLinksApiService: SharedLinksApiService,
@@ -93,7 +95,6 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
this.form.controls['time'].disable(); this.form.controls['time'].disable();
} }
this.subscriptions.push(
this.form.controls.time.valueChanges this.form.controls.time.valueChanges
.pipe( .pipe(
skip(1), skip(1),
@@ -104,10 +105,10 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
), ),
catchError((error) => { catchError((error) => {
return throwError(error); return throwError(error);
}) }),
takeUntil(this.onDestroy$)
) )
.subscribe((updates) => this.updateEntryExpiryDate(updates)) .subscribe(updates => this.updateEntryExpiryDate(updates));
);
if (this.data.node && this.data.node.entry) { if (this.data.node && this.data.node.entry) {
this.fileName = this.data.node.entry.name; this.fileName = this.data.node.entry.name;
@@ -126,7 +127,8 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
} }
ngOnDestroy() { ngOnDestroy() {
this.subscriptions.forEach((subscription) => subscription.unsubscribe); this.onDestroy$.next(true);
this.onDestroy$.complete();
} }
removeShare() { removeShare() {

View File

@@ -15,19 +15,20 @@
* limitations under the License. * limitations under the License.
*/ */
import { Directive, Input, HostListener, OnChanges, NgZone } from '@angular/core'; import { Directive, Input, HostListener, OnChanges, NgZone, OnDestroy } from '@angular/core';
import { MatDialog } from '@angular/material'; import { MatDialog } from '@angular/material';
import { NodeEntry, Node } from '@alfresco/js-api'; import { NodeEntry, Node } from '@alfresco/js-api';
import { ShareDialogComponent } from './content-node-share.dialog'; import { ShareDialogComponent } from './content-node-share.dialog';
import { Observable, from } from 'rxjs'; import { Observable, from, Subject } from 'rxjs';
import { AlfrescoApiService } from '@alfresco/adf-core'; import { AlfrescoApiService } from '@alfresco/adf-core';
import { takeUntil } from 'rxjs/operators';
@Directive({ @Directive({
selector: '[adf-share]', selector: '[adf-share]',
exportAs: 'adfShare' exportAs: 'adfShare'
}) })
export class NodeSharedDirective implements OnChanges { export class NodeSharedDirective implements OnChanges, OnDestroy {
isFile: boolean = false; isFile: boolean = false;
isShared: boolean = false; isShared: boolean = false;
@@ -41,12 +42,7 @@ export class NodeSharedDirective implements OnChanges {
@Input() @Input()
baseShareUrl: string; baseShareUrl: string;
@HostListener('click') private onDestroy$ = new Subject<boolean>();
onClick() {
if (this.node) {
this.shareNode(this.node);
}
}
constructor( constructor(
private dialog: MatDialog, private dialog: MatDialog,
@@ -54,6 +50,11 @@ export class NodeSharedDirective implements OnChanges {
private alfrescoApiService: AlfrescoApiService) { private alfrescoApiService: AlfrescoApiService) {
} }
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
shareNode(nodeEntry: NodeEntry) { shareNode(nodeEntry: NodeEntry) {
if (nodeEntry && nodeEntry.entry && nodeEntry.entry.isFile) { if (nodeEntry && nodeEntry.entry && nodeEntry.entry.isFile) {
// shared and favorite // shared and favorite
@@ -89,11 +90,20 @@ export class NodeSharedDirective implements OnChanges {
} }
ngOnChanges() { ngOnChanges() {
this.zone.onStable.subscribe(() => { this.zone.onStable
.pipe(takeUntil(this.onDestroy$))
.subscribe(() => {
if (this.node && this.node.entry) { if (this.node && this.node.entry) {
this.isFile = this.node.entry.isFile; this.isFile = this.node.entry.isFile;
this.isShared = this.node.entry.properties ? this.node.entry.properties['qshare:sharedId'] : false; this.isShared = this.node.entry.properties ? this.node.entry.properties['qshare:sharedId'] : false;
} }
}); });
} }
@HostListener('click')
onClick() {
if (this.node) {
this.shareNode(this.node);
}
}
} }

View File

@@ -47,7 +47,7 @@ import {
} from '@alfresco/adf-core'; } from '@alfresco/adf-core';
import { Node, NodeEntry, NodePaging, Pagination } from '@alfresco/js-api'; import { Node, NodeEntry, NodePaging, Pagination } from '@alfresco/js-api';
import { Subject, BehaviorSubject, Subscription, of } from 'rxjs'; import { Subject, BehaviorSubject, of } from 'rxjs';
import { ShareDataRow } from './../data/share-data-row.model'; import { ShareDataRow } from './../data/share-data-row.model';
import { ShareDataTableAdapter } from './../data/share-datatable-adapter'; import { ShareDataTableAdapter } from './../data/share-datatable-adapter';
import { presetsDefaultModel } from '../models/preset.model'; import { presetsDefaultModel } from '../models/preset.model';
@@ -58,6 +58,7 @@ import { NavigableComponentInterface } from '../../breadcrumb/navigable-componen
import { RowFilter } from '../data/row-filter.model'; import { RowFilter } from '../data/row-filter.model';
import { DocumentListService } from '../services/document-list.service'; import { DocumentListService } from '../services/document-list.service';
import { DocumentLoaderNode } from '../models/document-folder.model'; import { DocumentLoaderNode } from '../models/document-folder.model';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'adf-document-list', selector: 'adf-document-list',
@@ -314,9 +315,9 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
pagination: BehaviorSubject<PaginationModel> = new BehaviorSubject<PaginationModel>(this.DEFAULT_PAGINATION); pagination: BehaviorSubject<PaginationModel> = new BehaviorSubject<PaginationModel>(this.DEFAULT_PAGINATION);
private layoutPresets = {}; private layoutPresets = {};
private subscriptions: Subscription[] = [];
private rowMenuCache: { [key: string]: ContentActionModel[] } = {}; private rowMenuCache: { [key: string]: ContentActionModel[] } = {};
private loadingTimeout; private loadingTimeout;
private onDestroy$ = new Subject<boolean>();
constructor(private documentListService: DocumentListService, constructor(private documentListService: DocumentListService,
private ngZone: NgZone, private ngZone: NgZone,
@@ -327,10 +328,6 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
private thumbnailService: ThumbnailService, private thumbnailService: ThumbnailService,
private alfrescoApiService: AlfrescoApiService, private alfrescoApiService: AlfrescoApiService,
private lockService: LockService) { private lockService: LockService) {
this.userPreferencesService.select(UserPreferenceValues.PaginationSize).subscribe((pagSize) => {
this.maxItems = this._pagination.maxItems = pagSize;
});
} }
getContextActions(node: NodeEntry) { getContextActions(node: NodeEntry) {
@@ -375,6 +372,13 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
} }
ngOnInit() { ngOnInit() {
this.userPreferencesService
.select(UserPreferenceValues.PaginationSize)
.pipe(takeUntil(this.onDestroy$))
.subscribe(pagSize => {
this.maxItems = this._pagination.maxItems = pagSize;
});
this.rowMenuCache = {}; this.rowMenuCache = {};
this.loadLayoutPresets(); this.loadLayoutPresets();
this.data = new ShareDataTableAdapter(this.thumbnailService, this.contentService, null, this.getDefaultSorting(), this.sortingMode); this.data = new ShareDataTableAdapter(this.thumbnailService, this.contentService, null, this.getDefaultSorting(), this.sortingMode);
@@ -389,20 +393,18 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
this.data.setImageResolver(this.imageResolver); this.data.setImageResolver(this.imageResolver);
} }
this.subscriptions.push( this.contextActionHandler
this.contextActionHandler.subscribe((val) => this.contextActionCallback(val)) .pipe(takeUntil(this.onDestroy$))
); .subscribe(val => this.contextActionCallback(val));
this.enforceSingleClickNavigationForMobile(); this.enforceSingleClickNavigationForMobile();
} }
ngAfterContentInit() { ngAfterContentInit() {
if (this.columnList) { if (this.columnList) {
this.subscriptions.push( this.columnList.columns.changes
this.columnList.columns.changes.subscribe(() => { .pipe(takeUntil(this.onDestroy$))
this.setTableSchema(); .subscribe(() => this.setTableSchema());
})
);
} }
this.setTableSchema(); this.setTableSchema();
} }
@@ -598,9 +600,9 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
} }
if (typeof action.execute === 'function' && handlerSub) { if (typeof action.execute === 'function' && handlerSub) {
handlerSub.subscribe(() => { handlerSub
action.execute(node); .pipe(takeUntil(this.onDestroy$))
}); .subscribe(() => action.execute(node));
} }
} }
} }
@@ -834,8 +836,8 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
} }
ngOnDestroy() { ngOnDestroy() {
this.subscriptions.forEach((s) => s.unsubscribe()); this.onDestroy$.next(true);
this.subscriptions = []; this.onDestroy$.complete();
} }
private handleError(err: any) { private handleError(err: any) {

View File

@@ -24,10 +24,11 @@ import {
ElementRef, ElementRef,
OnDestroy OnDestroy
} from '@angular/core'; } from '@angular/core';
import { NodeEntry, Node, Site } from '@alfresco/js-api'; import { NodeEntry, Site } from '@alfresco/js-api';
import { ShareDataRow } from '../../data/share-data-row.model'; import { ShareDataRow } from '../../data/share-data-row.model';
import { AlfrescoApiService } from '@alfresco/adf-core'; import { AlfrescoApiService } from '@alfresco/adf-core';
import { BehaviorSubject, Subscription } from 'rxjs'; import { BehaviorSubject, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'adf-library-name-column', selector: 'adf-library-name-column',
@@ -50,7 +51,7 @@ export class LibraryNameColumnComponent implements OnInit, OnDestroy {
displayText$ = new BehaviorSubject<string>(''); displayText$ = new BehaviorSubject<string>('');
node: NodeEntry; node: NodeEntry;
private sub: Subscription; private onDestroy$ = new Subject<boolean>();
constructor( constructor(
private element: ElementRef, private element: ElementRef,
@@ -60,8 +61,9 @@ export class LibraryNameColumnComponent implements OnInit, OnDestroy {
ngOnInit() { ngOnInit() {
this.updateValue(); this.updateValue();
this.sub = this.alfrescoApiService.nodeUpdated.subscribe( this.alfrescoApiService.nodeUpdated
(node: Node) => { .pipe(takeUntil(this.onDestroy$))
.subscribe(node => {
const row: ShareDataRow = this.context.row; const row: ShareDataRow = this.context.row;
if (row) { if (row) {
const { entry } = row.node; const { entry } = row.node;
@@ -71,8 +73,7 @@ export class LibraryNameColumnComponent implements OnInit, OnDestroy {
this.updateValue(); this.updateValue();
} }
} }
} });
);
} }
protected updateValue() { protected updateValue() {
@@ -119,9 +120,7 @@ export class LibraryNameColumnComponent implements OnInit, OnDestroy {
} }
ngOnDestroy() { ngOnDestroy() {
if (this.sub) { this.onDestroy$.next(true);
this.sub.unsubscribe(); this.onDestroy$.complete();
this.sub = null;
}
} }
} }

View File

@@ -23,10 +23,11 @@ import {
ViewEncapsulation, ViewEncapsulation,
OnDestroy OnDestroy
} from '@angular/core'; } from '@angular/core';
import { Subscription, BehaviorSubject } from 'rxjs'; import { BehaviorSubject, Subject } from 'rxjs';
import { AlfrescoApiService } from '@alfresco/adf-core'; import { AlfrescoApiService } from '@alfresco/adf-core';
import { Node, SiteEntry, Site } from '@alfresco/js-api'; import { SiteEntry, Site } from '@alfresco/js-api';
import { ShareDataRow } from '../../data/share-data-row.model'; import { ShareDataRow } from '../../data/share-data-row.model';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'adf-library-role-column', selector: 'adf-library-role-column',
@@ -45,14 +46,16 @@ export class LibraryRoleColumnComponent implements OnInit, OnDestroy {
displayText$ = new BehaviorSubject<string>(''); displayText$ = new BehaviorSubject<string>('');
private sub: Subscription; private onDestroy$ = new Subject<boolean>();
constructor(private api: AlfrescoApiService) {} constructor(private api: AlfrescoApiService) {}
ngOnInit() { ngOnInit() {
this.updateValue(); this.updateValue();
this.sub = this.api.nodeUpdated.subscribe((node: Node) => { this.api.nodeUpdated
.pipe(takeUntil(this.onDestroy$))
.subscribe(node => {
const row: ShareDataRow = this.context.row; const row: ShareDataRow = this.context.row;
if (row) { if (row) {
const { entry } = row.node; const { entry } = row.node;
@@ -90,9 +93,7 @@ export class LibraryRoleColumnComponent implements OnInit, OnDestroy {
} }
ngOnDestroy() { ngOnDestroy() {
if (this.sub) { this.onDestroy$.next(true);
this.sub.unsubscribe(); this.onDestroy$.complete();
this.sub = null;
}
} }
} }

View File

@@ -17,9 +17,10 @@
import { Component, Input, OnInit, OnDestroy } from '@angular/core'; import { Component, Input, OnInit, OnDestroy } from '@angular/core';
import { AlfrescoApiService } from '@alfresco/adf-core'; import { AlfrescoApiService } from '@alfresco/adf-core';
import { Subscription, BehaviorSubject } from 'rxjs'; import { BehaviorSubject, Subject } from 'rxjs';
import { Node, Site, SiteEntry } from '@alfresco/js-api'; import { Site, SiteEntry } from '@alfresco/js-api';
import { ShareDataRow } from '../../data/share-data-row.model'; import { ShareDataRow } from '../../data/share-data-row.model';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'adf-library-status-column', selector: 'adf-library-status-column',
@@ -36,14 +37,16 @@ export class LibraryStatusColumnComponent implements OnInit, OnDestroy {
displayText$ = new BehaviorSubject<string>(''); displayText$ = new BehaviorSubject<string>('');
private sub: Subscription; private onDestroy$ = new Subject<boolean>();
constructor(private api: AlfrescoApiService) {} constructor(private api: AlfrescoApiService) {}
ngOnInit() { ngOnInit() {
this.updateValue(); this.updateValue();
this.sub = this.api.nodeUpdated.subscribe((node: Node) => { this.api.nodeUpdated
.pipe(takeUntil(this.onDestroy$))
.subscribe(node => {
const row: ShareDataRow = this.context.row; const row: ShareDataRow = this.context.row;
if (row) { if (row) {
const { entry } = row.node; const { entry } = row.node;
@@ -79,9 +82,7 @@ export class LibraryStatusColumnComponent implements OnInit, OnDestroy {
} }
ngOnDestroy() { ngOnDestroy() {
if (this.sub) { this.onDestroy$.next(true);
this.sub.unsubscribe(); this.onDestroy$.complete();
this.sub = null;
}
} }
} }

View File

@@ -25,10 +25,10 @@ import {
OnDestroy OnDestroy
} from '@angular/core'; } from '@angular/core';
import { NodeEntry } from '@alfresco/js-api'; import { NodeEntry } from '@alfresco/js-api';
import { BehaviorSubject, Subscription } from 'rxjs'; import { BehaviorSubject, Subject } from 'rxjs';
import { AlfrescoApiService } from '@alfresco/adf-core'; import { AlfrescoApiService } from '@alfresco/adf-core';
import { Node } from '@alfresco/js-api';
import { ShareDataRow } from '../../data/share-data-row.model'; import { ShareDataRow } from '../../data/share-data-row.model';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'adf-name-column', selector: 'adf-name-column',
@@ -48,14 +48,16 @@ export class NameColumnComponent implements OnInit, OnDestroy {
displayText$ = new BehaviorSubject<string>(''); displayText$ = new BehaviorSubject<string>('');
node: NodeEntry; node: NodeEntry;
private sub: Subscription; private onDestroy$ = new Subject<boolean>();
constructor(private element: ElementRef, private alfrescoApiService: AlfrescoApiService) {} constructor(private element: ElementRef, private alfrescoApiService: AlfrescoApiService) {}
ngOnInit() { ngOnInit() {
this.updateValue(); this.updateValue();
this.sub = this.alfrescoApiService.nodeUpdated.subscribe((node: Node) => { this.alfrescoApiService.nodeUpdated
.pipe(takeUntil(this.onDestroy$))
.subscribe(node => {
const row: ShareDataRow = this.context.row; const row: ShareDataRow = this.context.row;
if (row) { if (row) {
const { entry } = row.node; const { entry } = row.node;
@@ -88,9 +90,7 @@ export class NameColumnComponent implements OnInit, OnDestroy {
} }
ngOnDestroy() { ngOnDestroy() {
if (this.sub) { this.onDestroy$.next(true);
this.sub.unsubscribe(); this.onDestroy$.complete();
this.sub = null;
}
} }
} }

View File

@@ -89,7 +89,7 @@ export class PermissionListComponent implements OnInit {
saveNewRole(event: any, permissionRow: PermissionDisplayModel) { saveNewRole(event: any, permissionRow: PermissionDisplayModel) {
const updatedPermissionRole: PermissionElement = this.buildUpdatedPermission(event.value, permissionRow); const updatedPermissionRole: PermissionElement = this.buildUpdatedPermission(event.value, permissionRow);
this.nodePermissionService.updatePermissionRole(this.actualNode, updatedPermissionRole) this.nodePermissionService.updatePermissionRole(this.actualNode, updatedPermissionRole)
.subscribe((node: Node) => { .subscribe(() => {
this.update.emit(updatedPermissionRole); this.update.emit(updatedPermissionRole);
}); });
} }
@@ -103,9 +103,12 @@ export class PermissionListComponent implements OnInit {
} }
removePermission(permissionRow: PermissionDisplayModel) { removePermission(permissionRow: PermissionDisplayModel) {
this.nodePermissionService.removePermission(this.actualNode, permissionRow).subscribe((node) => { this.nodePermissionService
this.update.emit(node); .removePermission(this.actualNode, permissionRow)
}, (error) => this.error.emit(error)); .subscribe(
node => this.update.emit(node),
error => this.error.emit(error)
);
} }
} }

View File

@@ -108,7 +108,12 @@ export class SearchControlComponent implements OnInit, OnDestroy {
private userPreferencesService: UserPreferencesService private userPreferencesService: UserPreferencesService
) { ) {
this.toggleSearch.asObservable().pipe(debounceTime(200)).subscribe(() => { this.toggleSearch
.pipe(
debounceTime(200),
takeUntil(this.onDestroy$)
)
.subscribe(() => {
if (this.expandable) { if (this.expandable) {
this.subscriptAnimationState = this.toggleAnimation(); this.subscriptAnimationState = this.toggleAnimation();
@@ -252,12 +257,12 @@ export class SearchControlComponent implements OnInit, OnDestroy {
private setupFocusEventHandlers() { private setupFocusEventHandlers() {
const focusEvents: Observable<FocusEvent> = this.focusSubject const focusEvents: Observable<FocusEvent> = this.focusSubject
.asObservable()
.pipe( .pipe(
debounceTime(50), debounceTime(50),
filter(($event: any) => { filter(($event: any) => {
return this.isSearchBarActive() && ($event.type === 'blur' || $event.type === 'focusout'); return this.isSearchBarActive() && ($event.type === 'blur' || $event.type === 'focusout');
}) }),
takeUntil(this.onDestroy$)
); );
focusEvents.subscribe(() => { focusEvents.subscribe(() => {

View File

@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { OnInit, Component, ViewEncapsulation } from '@angular/core'; import { OnInit, Component, ViewEncapsulation, OnDestroy } from '@angular/core';
import { FormControl, Validators, FormGroup } from '@angular/forms'; import { FormControl, Validators, FormGroup } from '@angular/forms';
import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE } from '@angular/material/core'; import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE } from '@angular/material/core';
import { MomentDateAdapter, MOMENT_DATE_FORMATS } from '@alfresco/adf-core'; import { MomentDateAdapter, MOMENT_DATE_FORMATS } from '@alfresco/adf-core';
@@ -26,6 +26,8 @@ import { SearchQueryBuilderService } from '../../search-query-builder.service';
import { LiveErrorStateMatcher } from '../../forms/live-error-state-matcher'; import { LiveErrorStateMatcher } from '../../forms/live-error-state-matcher';
import { Moment } from 'moment'; import { Moment } from 'moment';
import { UserPreferencesService, UserPreferenceValues } from '@alfresco/adf-core'; import { UserPreferencesService, UserPreferenceValues } from '@alfresco/adf-core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
declare let moment: any; declare let moment: any;
@@ -42,7 +44,7 @@ const DEFAULT_FORMAT_DATE: string = 'DD/MM/YYYY';
encapsulation: ViewEncapsulation.None, encapsulation: ViewEncapsulation.None,
host: { class: 'adf-search-date-range' } host: { class: 'adf-search-date-range' }
}) })
export class SearchDateRangeComponent implements SearchWidget, OnInit { export class SearchDateRangeComponent implements SearchWidget, OnInit, OnDestroy {
from: FormControl; from: FormControl;
to: FormControl; to: FormControl;
@@ -56,6 +58,8 @@ export class SearchDateRangeComponent implements SearchWidget, OnInit {
maxDate: any; maxDate: any;
datePickerDateFormat = DEFAULT_FORMAT_DATE; datePickerDateFormat = DEFAULT_FORMAT_DATE;
private onDestroy$ = new Subject<boolean>();
constructor(private dateAdapter: DateAdapter<Moment>, constructor(private dateAdapter: DateAdapter<Moment>,
private userPreferencesService: UserPreferencesService) { private userPreferencesService: UserPreferencesService) {
} }
@@ -82,9 +86,10 @@ export class SearchDateRangeComponent implements SearchWidget, OnInit {
const theCustomDateAdapter = <MomentDateAdapter> <any> this.dateAdapter; const theCustomDateAdapter = <MomentDateAdapter> <any> this.dateAdapter;
theCustomDateAdapter.overrideDisplayFormat = this.datePickerDateFormat; theCustomDateAdapter.overrideDisplayFormat = this.datePickerDateFormat;
this.userPreferencesService.select(UserPreferenceValues.Locale).subscribe((locale) => { this.userPreferencesService
this.setLocale(locale); .select(UserPreferenceValues.Locale)
}); .pipe(takeUntil(this.onDestroy$))
.subscribe(locale => this.setLocale(locale));
const validators = Validators.compose([ const validators = Validators.compose([
Validators.required Validators.required
@@ -101,6 +106,11 @@ export class SearchDateRangeComponent implements SearchWidget, OnInit {
this.maxDate = this.dateAdapter.today().startOf('day'); this.maxDate = this.dateAdapter.today().startOf('day');
} }
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
apply(model: { from: string, to: string }, isValid: boolean) { apply(model: { from: string, to: string }, isValid: boolean) {
if (isValid && this.id && this.context && this.settings && this.settings.field) { if (isValid && this.id && this.context && this.settings && this.settings.field) {
const start = moment(model.from).startOf('day').format(); const start = moment(model.from).startOf('day').format();

View File

@@ -22,8 +22,9 @@ import { SearchQueryBuilderService } from '../../search-query-builder.service';
import { FacetFieldBucket } from '../../facet-field-bucket.interface'; import { FacetFieldBucket } from '../../facet-field-bucket.interface';
import { FacetField } from '../../facet-field.interface'; import { FacetField } from '../../facet-field.interface';
import { SearchFilterList } from './models/search-filter-list.model'; import { SearchFilterList } from './models/search-filter-list.model';
import { takeWhile } from 'rxjs/operators'; import { takeUntil } from 'rxjs/operators';
import { ResultSetPaging, GenericBucket, GenericFacetResponse, ResultSetContext } from '@alfresco/js-api'; import { GenericBucket, GenericFacetResponse, ResultSetContext } from '@alfresco/js-api';
import { Subject } from 'rxjs';
@Component({ @Component({
selector: 'adf-search-filter', selector: 'adf-search-filter',
@@ -36,8 +37,6 @@ export class SearchFilterComponent implements OnInit, OnDestroy {
private DEFAULT_PAGE_SIZE = 5; private DEFAULT_PAGE_SIZE = 5;
isAlive = true;
/** All facet field items to be displayed in the component. These are updated according to the response. /** All facet field items to be displayed in the component. These are updated according to the response.
* When a new search is performed, the already existing items are updated with the new bucket count values and * When a new search is performed, the already existing items are updated with the new bucket count values and
* the newly received items are added to the responseFacets. * the newly received items are added to the responseFacets.
@@ -52,6 +51,8 @@ export class SearchFilterComponent implements OnInit, OnDestroy {
displayResetButton: boolean; displayResetButton: boolean;
selectedBuckets: Array<{ field: FacetField, bucket: FacetFieldBucket }> = []; selectedBuckets: Array<{ field: FacetField, bucket: FacetFieldBucket }> = [];
private onDestroy$ = new Subject<boolean>();
constructor(public queryBuilder: SearchQueryBuilderService, constructor(public queryBuilder: SearchQueryBuilderService,
private searchService: SearchService, private searchService: SearchService,
private translationService: TranslationService) { private translationService: TranslationService) {
@@ -68,18 +69,16 @@ export class SearchFilterComponent implements OnInit, OnDestroy {
} }
this.displayResetButton = this.queryBuilder.config && !!this.queryBuilder.config.resetButton; this.displayResetButton = this.queryBuilder.config && !!this.queryBuilder.config.resetButton;
this.queryBuilder.updated.pipe( this.queryBuilder.updated
takeWhile(() => this.isAlive) .pipe(takeUntil(this.onDestroy$))
).subscribe(() => { .subscribe(() => this.queryBuilder.execute());
this.queryBuilder.execute();
});
} }
ngOnInit() { ngOnInit() {
if (this.queryBuilder) { if (this.queryBuilder) {
this.queryBuilder.executed.pipe( this.queryBuilder.executed
takeWhile(() => this.isAlive) .pipe(takeUntil(this.onDestroy$))
).subscribe((resultSetPaging: ResultSetPaging) => { .subscribe(resultSetPaging => {
this.onDataLoaded(resultSetPaging); this.onDataLoaded(resultSetPaging);
this.searchService.dataLoaded.next(resultSetPaging); this.searchService.dataLoaded.next(resultSetPaging);
}); });
@@ -87,7 +86,8 @@ export class SearchFilterComponent implements OnInit, OnDestroy {
} }
ngOnDestroy() { ngOnDestroy() {
this.isAlive = false; this.onDestroy$.next(true);
this.onDestroy$.complete();
} }
private updateSelectedBuckets() { private updateSelectedBuckets() {

View File

@@ -27,11 +27,12 @@ import {
Output, Output,
TemplateRef, TemplateRef,
ViewChild, ViewChild,
ViewEncapsulation ViewEncapsulation,
OnDestroy
} from '@angular/core'; } from '@angular/core';
import { NodePaging } from '@alfresco/js-api'; import { NodePaging } from '@alfresco/js-api';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { debounceTime } from 'rxjs/operators'; import { debounceTime, takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'adf-search', selector: 'adf-search',
@@ -44,7 +45,7 @@ import { debounceTime } from 'rxjs/operators';
'class': 'adf-search' 'class': 'adf-search'
} }
}) })
export class SearchComponent implements AfterContentInit, OnChanges { export class SearchComponent implements AfterContentInit, OnChanges, OnDestroy {
@ViewChild('panel') @ViewChild('panel')
panel: ElementRef; panel: ElementRef;
@@ -99,24 +100,26 @@ export class SearchComponent implements AfterContentInit, OnChanges {
} }
_isOpen: boolean = false; _isOpen: boolean = false;
keyPressedStream = new Subject<string>();
keyPressedStream: Subject<string> = new Subject();
_classList: { [key: string]: boolean } = {}; _classList: { [key: string]: boolean } = {};
private onDestroy$ = new Subject<boolean>();
constructor(private searchService: SearchService, constructor(private searchService: SearchService,
private _elementRef: ElementRef) { private _elementRef: ElementRef) {
this.keyPressedStream.asObservable() this.keyPressedStream
.pipe( .pipe(
debounceTime(200) debounceTime(200),
takeUntil(this.onDestroy$)
) )
.subscribe((searchedWord: string) => { .subscribe(searchedWord => {
this.loadSearchResults(searchedWord); this.loadSearchResults(searchedWord);
}); });
searchService.dataLoaded.subscribe( searchService.dataLoaded
(nodePaging: NodePaging) => this.onSearchDataLoaded(nodePaging), .pipe(takeUntil(this.onDestroy$))
(error) => this.onSearchDataError(error) .subscribe(
nodePaging => this.onSearchDataLoaded(nodePaging),
error => this.onSearchDataError(error)
); );
} }
@@ -130,6 +133,11 @@ export class SearchComponent implements AfterContentInit, OnChanges {
} }
} }
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
resetResults() { resetResults() {
this.cleanResults(); this.cleanResults();
this.setVisibility(); this.setVisibility();

View File

@@ -15,10 +15,12 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, EventEmitter, Input, OnInit, Output, ViewChild, ViewEncapsulation } from '@angular/core'; import { Component, EventEmitter, Input, OnInit, Output, ViewChild, ViewEncapsulation, OnDestroy } from '@angular/core';
import { SitesService, LogService } from '@alfresco/adf-core'; import { SitesService, LogService } from '@alfresco/adf-core';
import { SitePaging, SiteEntry } from '@alfresco/js-api'; import { SitePaging, SiteEntry } from '@alfresco/js-api';
import { MatSelect } from '@angular/material'; import { MatSelect } from '@angular/material';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
export enum Relations { export enum Relations {
Members = 'members', Members = 'members',
@@ -32,7 +34,7 @@ export enum Relations {
encapsulation: ViewEncapsulation.None, encapsulation: ViewEncapsulation.None,
host: { 'class': 'adf-sites-dropdown' } host: { 'class': 'adf-sites-dropdown' }
}) })
export class DropdownSitesComponent implements OnInit { export class DropdownSitesComponent implements OnInit, OnDestroy {
/** Hide the "My Files" option. */ /** Hide the "My Files" option. */
@Input() @Input()
@@ -77,17 +79,19 @@ export class DropdownSitesComponent implements OnInit {
private readonly MAX_ITEMS = 50; private readonly MAX_ITEMS = 50;
private readonly ITEM_HEIGHT = 45; private readonly ITEM_HEIGHT = 45;
private readonly ITEM_HEIGHT_TO_WAIT_BEFORE_LOAD_NEXT = (this.ITEM_HEIGHT * (this.MAX_ITEMS / 2)); private readonly ITEM_HEIGHT_TO_WAIT_BEFORE_LOAD_NEXT = (this.ITEM_HEIGHT * (this.MAX_ITEMS / 2));
private onDestroy$ = new Subject<boolean>();
selected: SiteEntry = null; selected: SiteEntry = null;
MY_FILES_VALUE = '-my-';
public MY_FILES_VALUE = '-my-';
constructor(private sitesService: SitesService, constructor(private sitesService: SitesService,
private logService: LogService) { private logService: LogService) {
} }
ngOnInit() { ngOnInit() {
this.siteSelect.openedChange.subscribe(() => { this.siteSelect.openedChange
.pipe(takeUntil(this.onDestroy$))
.subscribe(() => {
if (this.siteSelect.panelOpen) { if (this.siteSelect.panelOpen) {
this.siteSelect.panel.nativeElement.addEventListener('scroll', (event) => this.loadAllOnScroll(event)); this.siteSelect.panel.nativeElement.addEventListener('scroll', (event) => this.loadAllOnScroll(event));
} }
@@ -98,6 +102,11 @@ export class DropdownSitesComponent implements OnInit {
} }
} }
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
loadAllOnScroll(event) { loadAllOnScroll(event) {
if (this.isInfiniteScrollingEnabled() && this.isScrollInNextFetchArea(event)) { if (this.isInfiniteScrollingEnabled() && this.isScrollInNextFetchArea(event)) {
this.loading = true; this.loading = true;

View File

@@ -18,8 +18,9 @@
import { TranslationService } from '@alfresco/adf-core'; import { TranslationService } from '@alfresco/adf-core';
import { Component, EventEmitter, Input, OnChanges, Output, ViewEncapsulation, OnDestroy, OnInit } from '@angular/core'; import { Component, EventEmitter, Input, OnChanges, Output, ViewEncapsulation, OnDestroy, OnInit } from '@angular/core';
import { TagService } from './services/tag.service'; import { TagService } from './services/tag.service';
import { Subscription } from 'rxjs'; import { Subject } from 'rxjs';
import { TagPaging } from '@alfresco/js-api'; import { TagPaging } from '@alfresco/js-api';
import { takeUntil } from 'rxjs/operators';
/** /**
* *
@@ -55,17 +56,15 @@ export class TagActionsComponent implements OnChanges, OnInit, OnDestroy {
errorMsg: string; errorMsg: string;
disableAddTag: boolean = true; disableAddTag: boolean = true;
private subscriptions: Subscription[] = []; private onDestroy$ = new Subject<boolean>();
constructor(private tagService: TagService, private translateService: TranslationService) { constructor(private tagService: TagService, private translateService: TranslationService) {
} }
ngOnInit() { ngOnInit() {
this.subscriptions.push( this.tagService.refresh
this.tagService.refresh.subscribe(() => { .pipe(takeUntil(this.onDestroy$))
this.refreshTag(); .subscribe(() => this.refreshTag());
})
);
} }
ngOnChanges() { ngOnChanges() {
@@ -73,8 +72,8 @@ export class TagActionsComponent implements OnChanges, OnInit, OnDestroy {
} }
ngOnDestroy() { ngOnDestroy() {
this.subscriptions.forEach((subscription) => subscription.unsubscribe()); this.onDestroy$.next(true);
this.subscriptions = []; this.onDestroy$.complete();
} }
refreshTag() { refreshTag() {

View File

@@ -15,9 +15,11 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, EventEmitter, OnInit, Output, ViewEncapsulation } from '@angular/core'; import { Component, EventEmitter, OnInit, Output, ViewEncapsulation, OnDestroy } from '@angular/core';
import { TagService } from './services/tag.service'; import { TagService } from './services/tag.service';
import { PaginationModel } from '@alfresco/adf-core'; import { PaginationModel } from '@alfresco/adf-core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
/** /**
* This component provide a list of all the tag inside the ECM * This component provide a list of all the tag inside the ECM
@@ -28,7 +30,7 @@ import { PaginationModel } from '@alfresco/adf-core';
styleUrls: ['./tag-list.component.scss'], styleUrls: ['./tag-list.component.scss'],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class TagListComponent implements OnInit { export class TagListComponent implements OnInit, OnDestroy {
/** Emitted when a tag is selected. */ /** Emitted when a tag is selected. */
@Output() @Output()
@@ -50,6 +52,8 @@ export class TagListComponent implements OnInit {
isLoading = false; isLoading = false;
isSizeMinimum = true; isSizeMinimum = true;
private onDestroy$ = new Subject<boolean>();
/** /**
* Constructor * Constructor
* @param tagService * @param tagService
@@ -64,14 +68,21 @@ export class TagListComponent implements OnInit {
this.pagination = this.defaultPagination; this.pagination = this.defaultPagination;
this.tagService.refresh.subscribe(() => { this.tagService.refresh
.pipe(takeUntil(this.onDestroy$))
.subscribe(() => {
this.tagsEntries = []; this.tagsEntries = [];
this.refreshTag(this.defaultPagination); this.refreshTag(this.defaultPagination);
}); });
} }
ngOnInit() { ngOnInit() {
return this.refreshTag(this.defaultPagination); this.refreshTag(this.defaultPagination);
}
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
} }
refreshTag(opts?: any) { refreshTag(opts?: any) {

View File

@@ -15,9 +15,11 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, EventEmitter, Input, OnChanges, Output, ViewEncapsulation } from '@angular/core'; import { Component, EventEmitter, Input, OnChanges, Output, ViewEncapsulation, OnDestroy, OnInit } from '@angular/core';
import { TagService } from './services/tag.service'; import { TagService } from './services/tag.service';
import { TagPaging } from '@alfresco/js-api'; import { TagPaging } from '@alfresco/js-api';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
/** /**
* *
@@ -30,7 +32,7 @@ import { TagPaging } from '@alfresco/js-api';
styleUrls: ['./tag-node-list.component.scss'], styleUrls: ['./tag-node-list.component.scss'],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class TagNodeListComponent implements OnChanges { export class TagNodeListComponent implements OnChanges, OnDestroy, OnInit {
/** The identifier of a node. */ /** The identifier of a node. */
@Input() @Input()
nodeId: string; nodeId: string;
@@ -45,18 +47,28 @@ export class TagNodeListComponent implements OnChanges {
@Output() @Output()
results = new EventEmitter(); results = new EventEmitter();
private onDestroy$ = new Subject<boolean>();
/** /**
* Constructor * Constructor
* @param tagService * @param tagService
*/ */
constructor(private tagService: TagService) { constructor(private tagService: TagService) {
this.tagService.refresh.subscribe(() => {
this.refreshTag();
});
} }
ngOnChanges() { ngOnChanges() {
return this.refreshTag(); this.refreshTag();
}
ngOnInit() {
this.tagService.refresh
.pipe(takeUntil(this.onDestroy$))
.subscribe(() => this.refreshTag());
}
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
} }
refreshTag() { refreshTag() {

View File

@@ -18,8 +18,9 @@
import { FileModel, FileInfo } from '@alfresco/adf-core'; import { FileModel, FileInfo } from '@alfresco/adf-core';
import { EventEmitter, Input, Output, OnInit, OnDestroy, NgZone } from '@angular/core'; import { EventEmitter, Input, Output, OnInit, OnDestroy, NgZone } from '@angular/core';
import { UploadService, TranslationService } from '@alfresco/adf-core'; import { UploadService, TranslationService } from '@alfresco/adf-core';
import { Subscription } from 'rxjs'; import { Subject } from 'rxjs';
import { UploadFilesEvent } from '../upload-files.event'; import { UploadFilesEvent } from '../upload-files.event';
import { takeUntil } from 'rxjs/operators';
export abstract class UploadBase implements OnInit, OnDestroy { export abstract class UploadBase implements OnInit, OnDestroy {
@@ -71,7 +72,7 @@ export abstract class UploadBase implements OnInit, OnDestroy {
@Output() @Output()
beginUpload = new EventEmitter<UploadFilesEvent>(); beginUpload = new EventEmitter<UploadFilesEvent>();
protected subscriptions: Subscription[] = []; protected onDestroy$ = new Subject<boolean>();
constructor(protected uploadService: UploadService, constructor(protected uploadService: UploadService,
protected translationService: TranslationService, protected translationService: TranslationService,
@@ -79,17 +80,14 @@ export abstract class UploadBase implements OnInit, OnDestroy {
} }
ngOnInit() { ngOnInit() {
this.subscriptions.push( this.uploadService.fileUploadError
this.uploadService.fileUploadError.subscribe((error) => { .pipe(takeUntil(this.onDestroy$))
this.error.emit(error); .subscribe(error => this.error.emit(error));
})
);
} }
ngOnDestroy() { ngOnDestroy() {
this.subscriptions.forEach((subscription) => subscription.unsubscribe()); this.onDestroy$.next(true);
this.subscriptions = []; this.onDestroy$.complete();
} }
/** /**

View File

@@ -15,10 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { import { FileModel, FileUploadStatus, UploadService, UserPreferencesService } from '@alfresco/adf-core';
FileModel, FileUploadCompleteEvent, FileUploadDeleteEvent,
FileUploadErrorEvent, FileUploadStatus, UploadService, UserPreferencesService
} from '@alfresco/adf-core';
import { ChangeDetectorRef, Component, Input, Output, EventEmitter, OnDestroy, OnInit, ViewChild, HostBinding } from '@angular/core'; import { ChangeDetectorRef, Component, Input, Output, EventEmitter, OnDestroy, OnInit, ViewChild, HostBinding } from '@angular/core';
import { Subscription, merge, Subject } from 'rxjs'; import { Subscription, merge, Subject } from 'rxjs';
import { FileUploadingListComponent } from './file-uploading-list.component'; import { FileUploadingListComponent } from './file-uploading-list.component';
@@ -33,7 +30,7 @@ import { takeUntil } from 'rxjs/operators';
export class FileUploadingDialogComponent implements OnInit, OnDestroy { export class FileUploadingDialogComponent implements OnInit, OnDestroy {
/** Dialog direction. Can be 'ltr' or 'rtl. */ /** Dialog direction. Can be 'ltr' or 'rtl. */
private direction: Direction = 'ltr'; private direction: Direction = 'ltr';
private onDestroy$: Subject<boolean> = new Subject<boolean>(); private onDestroy$ = new Subject<boolean>();
@ViewChild('uploadList') @ViewChild('uploadList')
uploadList: FileUploadingListComponent; uploadList: FileUploadingListComponent;
@@ -79,8 +76,9 @@ export class FileUploadingDialogComponent implements OnInit, OnDestroy {
} }
ngOnInit() { ngOnInit() {
this.listSubscription = this.uploadService this.listSubscription = this.uploadService.queueChanged
.queueChanged.subscribe((fileList: FileModel[]) => { .pipe(takeUntil(this.onDestroy$))
.subscribe(fileList => {
this.filesUploadingList = fileList; this.filesUploadingList = fileList;
if (this.filesUploadingList.length) { if (this.filesUploadingList.length) {
@@ -92,23 +90,28 @@ export class FileUploadingDialogComponent implements OnInit, OnDestroy {
this.uploadService.fileUploadComplete, this.uploadService.fileUploadComplete,
this.uploadService.fileUploadDeleted this.uploadService.fileUploadDeleted
) )
.subscribe((event: (FileUploadDeleteEvent | FileUploadCompleteEvent)) => { .pipe(takeUntil(this.onDestroy$))
.subscribe(event => {
this.totalCompleted = event.totalComplete; this.totalCompleted = event.totalComplete;
this.changeDetector.detectChanges(); this.changeDetector.detectChanges();
}); });
this.errorSubscription = this.uploadService.fileUploadError this.errorSubscription = this.uploadService.fileUploadError
.subscribe((event: FileUploadErrorEvent) => { .pipe(takeUntil(this.onDestroy$))
.subscribe(event => {
this.totalErrors = event.totalError; this.totalErrors = event.totalError;
this.changeDetector.detectChanges(); this.changeDetector.detectChanges();
}); });
this.fileUploadSubscription = this.uploadService this.fileUploadSubscription = this.uploadService.fileUpload
.fileUpload.subscribe(() => { .pipe(takeUntil(this.onDestroy$))
.subscribe(() => {
this.changeDetector.detectChanges(); this.changeDetector.detectChanges();
}); });
this.uploadService.fileDeleted.subscribe((objId) => { this.uploadService.fileDeleted
.pipe(takeUntil(this.onDestroy$))
.subscribe(objId => {
if (this.filesUploadingList) { if (this.filesUploadingList) {
const file = this.filesUploadingList.find((item) => { const file = this.filesUploadingList.find((item) => {
return item.data.entry.id === objId; return item.data.entry.id === objId;

View File

@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, Input, OnInit, ViewChild } from '@angular/core'; import { Component, Input, OnInit, ViewChild, OnDestroy } from '@angular/core';
import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material'; import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material';
import { MatDatetimepicker, DatetimeAdapter, MAT_DATETIME_FORMATS } from '@mat-datetimepicker/core'; import { MatDatetimepicker, DatetimeAdapter, MAT_DATETIME_FORMATS } from '@mat-datetimepicker/core';
import { MomentDatetimeAdapter, MAT_MOMENT_DATETIME_FORMATS } from '@mat-datetimepicker/moment'; import { MomentDatetimeAdapter, MAT_MOMENT_DATETIME_FORMATS } from '@mat-datetimepicker/moment';
@@ -27,6 +27,8 @@ import { UserPreferencesService, UserPreferenceValues } from '../../../services/
import { MomentDateAdapter } from '../../../utils/momentDateAdapter'; import { MomentDateAdapter } from '../../../utils/momentDateAdapter';
import { MOMENT_DATE_FORMATS } from '../../../utils/moment-date-formats.model'; import { MOMENT_DATE_FORMATS } from '../../../utils/moment-date-formats.model';
import { AppConfigService } from '../../../app-config/app-config.service'; import { AppConfigService } from '../../../app-config/app-config.service';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
providers: [ providers: [
@@ -39,7 +41,7 @@ import { AppConfigService } from '../../../app-config/app-config.service';
templateUrl: './card-view-dateitem.component.html', templateUrl: './card-view-dateitem.component.html',
styleUrls: ['./card-view-dateitem.component.scss'] styleUrls: ['./card-view-dateitem.component.scss']
}) })
export class CardViewDateItemComponent implements OnInit { export class CardViewDateItemComponent implements OnInit, OnDestroy {
@Input() @Input()
property: CardViewDateItemModel; property: CardViewDateItemModel;
@@ -56,6 +58,8 @@ export class CardViewDateItemComponent implements OnInit {
valueDate: Moment; valueDate: Moment;
dateFormat: string; dateFormat: string;
private onDestroy$ = new Subject<boolean>();
constructor(private cardViewUpdateService: CardViewUpdateService, constructor(private cardViewUpdateService: CardViewUpdateService,
private dateAdapter: DateAdapter<Moment>, private dateAdapter: DateAdapter<Moment>,
private userPreferencesService: UserPreferencesService, private userPreferencesService: UserPreferencesService,
@@ -64,9 +68,10 @@ export class CardViewDateItemComponent implements OnInit {
} }
ngOnInit() { ngOnInit() {
this.userPreferencesService.select(UserPreferenceValues.Locale).subscribe((locale) => { this.userPreferencesService
this.dateAdapter.setLocale(locale); .select(UserPreferenceValues.Locale)
}); .pipe(takeUntil(this.onDestroy$))
.subscribe(locale => this.dateAdapter.setLocale(locale));
(<MomentDateAdapter> this.dateAdapter).overrideDisplayFormat = 'MMM DD'; (<MomentDateAdapter> this.dateAdapter).overrideDisplayFormat = 'MMM DD';
@@ -75,6 +80,11 @@ export class CardViewDateItemComponent implements OnInit {
} }
} }
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
showProperty() { showProperty() {
return this.displayEmpty || !this.property.isEmpty(); return this.displayEmpty || !this.property.isEmpty();
} }

View File

@@ -15,11 +15,13 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, EventEmitter, Input, Output, ViewEncapsulation } from '@angular/core'; import { Component, EventEmitter, Input, Output, ViewEncapsulation, OnInit, OnDestroy } from '@angular/core';
import { CommentModel } from '../models/comment.model'; import { CommentModel } from '../models/comment.model';
import { EcmUserService } from '../userinfo/services/ecm-user.service'; import { EcmUserService } from '../userinfo/services/ecm-user.service';
import { PeopleProcessService } from '../services/people-process.service'; import { PeopleProcessService } from '../services/people-process.service';
import { UserPreferencesService, UserPreferenceValues } from '../services/user-preferences.service'; import { UserPreferencesService, UserPreferenceValues } from '../services/user-preferences.service';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'adf-comment-list', selector: 'adf-comment-list',
@@ -28,7 +30,7 @@ import { UserPreferencesService, UserPreferenceValues } from '../services/user-p
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class CommentListComponent { export class CommentListComponent implements OnInit, OnDestroy {
/** The comments data used to populate the list. */ /** The comments data used to populate the list. */
@Input() @Input()
@@ -39,15 +41,24 @@ export class CommentListComponent {
clickRow: EventEmitter<CommentModel> = new EventEmitter<CommentModel>(); clickRow: EventEmitter<CommentModel> = new EventEmitter<CommentModel>();
selectedComment: CommentModel; selectedComment: CommentModel;
currentLocale; currentLocale;
private onDestroy$ = new Subject<boolean>();
constructor(public peopleProcessService: PeopleProcessService, constructor(public peopleProcessService: PeopleProcessService,
public ecmUserService: EcmUserService, public ecmUserService: EcmUserService,
public userPreferenceService: UserPreferencesService) { public userPreferenceService: UserPreferencesService) {
userPreferenceService.select(UserPreferenceValues.Locale).subscribe((locale) => { }
this.currentLocale = locale;
}); ngOnInit() {
this.userPreferenceService
.select(UserPreferenceValues.Locale)
.pipe(takeUntil(this.onDestroy$))
.subscribe(locale => this.currentLocale = locale);
}
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
} }
selectComment(comment: CommentModel): void { selectComment(comment: CommentModel): void {

View File

@@ -27,8 +27,8 @@ import { DataColumn } from '../../data/data-column.model';
import { DataRow } from '../../data/data-row.model'; import { DataRow } from '../../data/data-row.model';
import { DataTableAdapter } from '../../data/datatable-adapter'; import { DataTableAdapter } from '../../data/datatable-adapter';
import { AlfrescoApiService } from '../../../services/alfresco-api.service'; import { AlfrescoApiService } from '../../../services/alfresco-api.service';
import { Subscription, BehaviorSubject } from 'rxjs'; import { BehaviorSubject, Subject } from 'rxjs';
import { Node } from '@alfresco/js-api'; import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'adf-datatable-cell', selector: 'adf-datatable-cell',
@@ -77,13 +77,15 @@ export class DataTableCellComponent implements OnInit, OnDestroy {
@Input() @Input()
tooltip: string; tooltip: string;
private sub: Subscription; protected onDestroy$ = new Subject<boolean>();
constructor(protected alfrescoApiService: AlfrescoApiService) {} constructor(protected alfrescoApiService: AlfrescoApiService) {}
ngOnInit() { ngOnInit() {
this.updateValue(); this.updateValue();
this.sub = this.alfrescoApiService.nodeUpdated.subscribe((node: Node) => { this.alfrescoApiService.nodeUpdated
.pipe(takeUntil(this.onDestroy$))
.subscribe(node => {
if (this.row) { if (this.row) {
if (this.row['node'].entry.id === node.id) { if (this.row['node'].entry.id === node.id) {
this.row['node'].entry = node; this.row['node'].entry = node;
@@ -107,9 +109,7 @@ export class DataTableCellComponent implements OnInit, OnDestroy {
} }
ngOnDestroy() { ngOnDestroy() {
if (this.sub) { this.onDestroy$.next(true);
this.sub.unsubscribe(); this.onDestroy$.complete();
this.sub = null;
}
} }
} }

View File

@@ -23,6 +23,7 @@ import {
} from '../../../services/user-preferences.service'; } from '../../../services/user-preferences.service';
import { AlfrescoApiService } from '../../../services/alfresco-api.service'; import { AlfrescoApiService } from '../../../services/alfresco-api.service';
import { AppConfigService } from '../../../app-config/app-config.service'; import { AppConfigService } from '../../../app-config/app-config.service';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'adf-date-cell', selector: 'adf-date-cell',
@@ -75,9 +76,8 @@ export class DateCellComponent extends DataTableCellComponent {
if (userPreferenceService) { if (userPreferenceService) {
userPreferenceService userPreferenceService
.select(UserPreferenceValues.Locale) .select(UserPreferenceValues.Locale)
.subscribe((locale) => { .pipe(takeUntil(this.onDestroy$))
this.currentLocale = locale; .subscribe(locale => this.currentLocale = locale);
});
} }
} }
} }

View File

@@ -17,7 +17,7 @@
/* tslint:disable:component-selector */ /* tslint:disable:component-selector */
import { Component, OnInit, ViewEncapsulation } from '@angular/core'; import { Component, OnInit, ViewEncapsulation, OnDestroy } from '@angular/core';
import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material'; import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material';
import { DatetimeAdapter, MAT_DATETIME_FORMATS } from '@mat-datetimepicker/core'; import { DatetimeAdapter, MAT_DATETIME_FORMATS } from '@mat-datetimepicker/core';
import { MomentDatetimeAdapter, MAT_MOMENT_DATETIME_FORMATS } from '@mat-datetimepicker/moment'; import { MomentDatetimeAdapter, MAT_MOMENT_DATETIME_FORMATS } from '@mat-datetimepicker/moment';
@@ -28,6 +28,8 @@ import { MomentDateAdapter } from '../../../../utils/momentDateAdapter';
import { MOMENT_DATE_FORMATS } from '../../../../utils/moment-date-formats.model'; import { MOMENT_DATE_FORMATS } from '../../../../utils/moment-date-formats.model';
import { FormService } from './../../../services/form.service'; import { FormService } from './../../../services/form.service';
import { WidgetComponent } from './../widget.component'; import { WidgetComponent } from './../widget.component';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
providers: [ providers: [
@@ -41,12 +43,14 @@ import { WidgetComponent } from './../widget.component';
styleUrls: ['./date-time.widget.scss'], styleUrls: ['./date-time.widget.scss'],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class DateTimeWidgetComponent extends WidgetComponent implements OnInit { export class DateTimeWidgetComponent extends WidgetComponent implements OnInit, OnDestroy {
minDate: Moment; minDate: Moment;
maxDate: Moment; maxDate: Moment;
displayDate: Moment; displayDate: Moment;
private onDestroy$ = new Subject<boolean>();
constructor(public formService: FormService, constructor(public formService: FormService,
private dateAdapter: DateAdapter<Moment>, private dateAdapter: DateAdapter<Moment>,
private userPreferencesService: UserPreferencesService) { private userPreferencesService: UserPreferencesService) {
@@ -54,9 +58,10 @@ export class DateTimeWidgetComponent extends WidgetComponent implements OnInit {
} }
ngOnInit() { ngOnInit() {
this.userPreferencesService.select(UserPreferenceValues.Locale).subscribe((locale) => { this.userPreferencesService
this.dateAdapter.setLocale(locale); .select(UserPreferenceValues.Locale)
}); .pipe(takeUntil(this.onDestroy$))
.subscribe(locale => this.dateAdapter.setLocale(locale));
const momentDateAdapter = <MomentDateAdapter> this.dateAdapter; const momentDateAdapter = <MomentDateAdapter> this.dateAdapter;
momentDateAdapter.overrideDisplayFormat = this.field.dateDisplayFormat; momentDateAdapter.overrideDisplayFormat = this.field.dateDisplayFormat;
@@ -73,6 +78,11 @@ export class DateTimeWidgetComponent extends WidgetComponent implements OnInit {
this.displayDate = moment(this.field.value); this.displayDate = moment(this.field.value);
} }
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
onDateChanged(newDateValue) { onDateChanged(newDateValue) {
if (newDateValue && newDateValue.value) { if (newDateValue && newDateValue.value) {
this.field.value = newDateValue.value.format(this.field.dateDisplayFormat); this.field.value = newDateValue.value.format(this.field.dateDisplayFormat);

View File

@@ -20,12 +20,14 @@
import { UserPreferencesService, UserPreferenceValues } from '../../../../services/user-preferences.service'; import { UserPreferencesService, UserPreferenceValues } from '../../../../services/user-preferences.service';
import { MomentDateAdapter } from '../../../../utils/momentDateAdapter'; import { MomentDateAdapter } from '../../../../utils/momentDateAdapter';
import { MOMENT_DATE_FORMATS } from '../../../../utils/moment-date-formats.model'; import { MOMENT_DATE_FORMATS } from '../../../../utils/moment-date-formats.model';
import { Component, OnInit, ViewEncapsulation } from '@angular/core'; import { Component, OnInit, ViewEncapsulation, OnDestroy } from '@angular/core';
import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material'; import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material';
import moment from 'moment-es6'; import moment from 'moment-es6';
import { Moment } from 'moment'; import { Moment } from 'moment';
import { FormService } from './../../../services/form.service'; import { FormService } from './../../../services/form.service';
import { baseHost, WidgetComponent } from './../widget.component'; import { baseHost, WidgetComponent } from './../widget.component';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'date-widget', selector: 'date-widget',
@@ -37,7 +39,7 @@ import { baseHost, WidgetComponent } from './../widget.component';
host: baseHost, host: baseHost,
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class DateWidgetComponent extends WidgetComponent implements OnInit { export class DateWidgetComponent extends WidgetComponent implements OnInit, OnDestroy {
DATE_FORMAT = 'DD/MM/YYYY'; DATE_FORMAT = 'DD/MM/YYYY';
@@ -45,6 +47,8 @@ export class DateWidgetComponent extends WidgetComponent implements OnInit {
maxDate: Moment; maxDate: Moment;
displayDate: Moment; displayDate: Moment;
private onDestroy$ = new Subject<boolean>();
constructor(public formService: FormService, constructor(public formService: FormService,
private dateAdapter: DateAdapter<Moment>, private dateAdapter: DateAdapter<Moment>,
private userPreferencesService: UserPreferencesService) { private userPreferencesService: UserPreferencesService) {
@@ -52,9 +56,10 @@ export class DateWidgetComponent extends WidgetComponent implements OnInit {
} }
ngOnInit() { ngOnInit() {
this.userPreferencesService.select(UserPreferenceValues.Locale).subscribe((locale) => { this.userPreferencesService
this.dateAdapter.setLocale(locale); .select(UserPreferenceValues.Locale)
}); .pipe(takeUntil(this.onDestroy$))
.subscribe(locale => this.dateAdapter.setLocale(locale));
const momentDateAdapter = <MomentDateAdapter> this.dateAdapter; const momentDateAdapter = <MomentDateAdapter> this.dateAdapter;
momentDateAdapter.overrideDisplayFormat = this.field.dateDisplayFormat; momentDateAdapter.overrideDisplayFormat = this.field.dateDisplayFormat;
@@ -71,6 +76,11 @@ export class DateWidgetComponent extends WidgetComponent implements OnInit {
this.displayDate = moment(this.field.value); this.displayDate = moment(this.field.value);
} }
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
onDateChanged(newDateValue) { onDateChanged(newDateValue) {
if (newDateValue && newDateValue.value) { if (newDateValue && newDateValue.value) {
this.field.value = newDateValue.value.format(this.field.dateDisplayFormat); this.field.value = newDateValue.value.format(this.field.dateDisplayFormat);

View File

@@ -21,13 +21,15 @@ import { UserPreferencesService, UserPreferenceValues } from '../../../../../../
import { MomentDateAdapter } from '../../../../../../utils/momentDateAdapter'; import { MomentDateAdapter } from '../../../../../../utils/momentDateAdapter';
import { MOMENT_DATE_FORMATS } from '../../../../../../utils/moment-date-formats.model'; import { MOMENT_DATE_FORMATS } from '../../../../../../utils/moment-date-formats.model';
import { Component, Input, OnInit } from '@angular/core'; import { Component, Input, OnInit, OnDestroy } from '@angular/core';
import { DateAdapter, MAT_DATE_FORMATS, MatDatepickerInputEvent } from '@angular/material'; import { DateAdapter, MAT_DATE_FORMATS, MatDatepickerInputEvent } from '@angular/material';
import moment from 'moment-es6'; import moment from 'moment-es6';
import { Moment } from 'moment'; import { Moment } from 'moment';
import { DynamicTableColumn } from './../../dynamic-table-column.model'; import { DynamicTableColumn } from './../../dynamic-table-column.model';
import { DynamicTableRow } from './../../dynamic-table-row.model'; import { DynamicTableRow } from './../../dynamic-table-row.model';
import { DynamicTableModel } from './../../dynamic-table.widget.model'; import { DynamicTableModel } from './../../dynamic-table.widget.model';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'adf-date-editor', selector: 'adf-date-editor',
@@ -37,7 +39,7 @@ import { DynamicTableModel } from './../../dynamic-table.widget.model';
{provide: MAT_DATE_FORMATS, useValue: MOMENT_DATE_FORMATS}], {provide: MAT_DATE_FORMATS, useValue: MOMENT_DATE_FORMATS}],
styleUrls: ['./date.editor.scss'] styleUrls: ['./date.editor.scss']
}) })
export class DateEditorComponent implements OnInit { export class DateEditorComponent implements OnInit, OnDestroy {
DATE_FORMAT: string = 'DD-MM-YYYY'; DATE_FORMAT: string = 'DD-MM-YYYY';
@@ -55,14 +57,17 @@ export class DateEditorComponent implements OnInit {
minDate: Moment; minDate: Moment;
maxDate: Moment; maxDate: Moment;
private onDestroy$ = new Subject<boolean>();
constructor(private dateAdapter: DateAdapter<Moment>, constructor(private dateAdapter: DateAdapter<Moment>,
private userPreferencesService: UserPreferencesService) { private userPreferencesService: UserPreferencesService) {
} }
ngOnInit() { ngOnInit() {
this.userPreferencesService.select(UserPreferenceValues.Locale).subscribe((locale) => { this.userPreferencesService
this.dateAdapter.setLocale(locale); .select(UserPreferenceValues.Locale)
}); .pipe(takeUntil(this.onDestroy$))
.subscribe(locale => this.dateAdapter.setLocale(locale));
const momentDateAdapter = <MomentDateAdapter> this.dateAdapter; const momentDateAdapter = <MomentDateAdapter> this.dateAdapter;
momentDateAdapter.overrideDisplayFormat = this.DATE_FORMAT; momentDateAdapter.overrideDisplayFormat = this.DATE_FORMAT;
@@ -70,6 +75,11 @@ export class DateEditorComponent implements OnInit {
this.value = moment(this.table.getCellValue(this.row, this.column), this.DATE_FORMAT); this.value = moment(this.table.getCellValue(this.row, this.column), this.DATE_FORMAT);
} }
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
onDateChanged(newDateValue: MatDatepickerInputEvent<any> | HTMLInputElement) { onDateChanged(newDateValue: MatDatepickerInputEvent<any> | HTMLInputElement) {
if (newDateValue && newDateValue.value) { if (newDateValue && newDateValue.value) {
/* validates the user inputs */ /* validates the user inputs */

View File

@@ -20,7 +20,7 @@
import { UserPreferencesService, UserPreferenceValues } from '../../../../../../services/user-preferences.service'; import { UserPreferencesService, UserPreferenceValues } from '../../../../../../services/user-preferences.service';
import { MomentDateAdapter } from '../../../../../../utils/momentDateAdapter'; import { MomentDateAdapter } from '../../../../../../utils/momentDateAdapter';
import { MOMENT_DATE_FORMATS } from '../../../../../../utils/moment-date-formats.model'; import { MOMENT_DATE_FORMATS } from '../../../../../../utils/moment-date-formats.model';
import { Component, Input, OnInit } from '@angular/core'; import { Component, Input, OnInit, OnDestroy } from '@angular/core';
import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material'; import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material';
import moment from 'moment-es6'; import moment from 'moment-es6';
import { Moment } from 'moment'; import { Moment } from 'moment';
@@ -29,6 +29,8 @@ import { DynamicTableRow } from './../../dynamic-table-row.model';
import { DynamicTableModel } from './../../dynamic-table.widget.model'; import { DynamicTableModel } from './../../dynamic-table.widget.model';
import { DatetimeAdapter, MAT_DATETIME_FORMATS } from '@mat-datetimepicker/core'; import { DatetimeAdapter, MAT_DATETIME_FORMATS } from '@mat-datetimepicker/core';
import { MomentDatetimeAdapter, MAT_MOMENT_DATETIME_FORMATS } from '@mat-datetimepicker/moment'; import { MomentDatetimeAdapter, MAT_MOMENT_DATETIME_FORMATS } from '@mat-datetimepicker/moment';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'adf-datetime-editor', selector: 'adf-datetime-editor',
@@ -41,7 +43,7 @@ import { MomentDatetimeAdapter, MAT_MOMENT_DATETIME_FORMATS } from '@mat-datetim
], ],
styleUrls: ['./datetime.editor.scss'] styleUrls: ['./datetime.editor.scss']
}) })
export class DateTimeEditorComponent implements OnInit { export class DateTimeEditorComponent implements OnInit, OnDestroy {
DATE_TIME_FORMAT: string = 'DD/MM/YYYY HH:mm'; DATE_TIME_FORMAT: string = 'DD/MM/YYYY HH:mm';
@@ -59,14 +61,17 @@ export class DateTimeEditorComponent implements OnInit {
minDate: Moment; minDate: Moment;
maxDate: Moment; maxDate: Moment;
private onDestroy$ = new Subject<boolean>();
constructor(private dateAdapter: DateAdapter<Moment>, constructor(private dateAdapter: DateAdapter<Moment>,
private userPreferencesService: UserPreferencesService) { private userPreferencesService: UserPreferencesService) {
} }
ngOnInit() { ngOnInit() {
this.userPreferencesService.select(UserPreferenceValues.Locale).subscribe((locale) => { this.userPreferencesService
this.dateAdapter.setLocale(locale); .select(UserPreferenceValues.Locale)
}); .pipe(takeUntil(this.onDestroy$))
.subscribe(locale => this.dateAdapter.setLocale(locale));
const momentDateAdapter = <MomentDateAdapter> this.dateAdapter; const momentDateAdapter = <MomentDateAdapter> this.dateAdapter;
momentDateAdapter.overrideDisplayFormat = this.DATE_TIME_FORMAT; momentDateAdapter.overrideDisplayFormat = this.DATE_TIME_FORMAT;
@@ -74,6 +79,11 @@ export class DateTimeEditorComponent implements OnInit {
this.value = moment(this.table.getCellValue(this.row, this.column), this.DATE_TIME_FORMAT); this.value = moment(this.table.getCellValue(this.row, this.column), this.DATE_TIME_FORMAT);
} }
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
onDateChanged(newDateValue) { onDateChanged(newDateValue) {
if (newDateValue && newDateValue.value) { if (newDateValue && newDateValue.value) {
const newValue = moment(newDateValue.value, this.DATE_TIME_FORMAT); const newValue = moment(newDateValue.value, this.DATE_TIME_FORMAT);

View File

@@ -17,7 +17,7 @@
import { import {
Component, EventEmitter, Component, EventEmitter,
Input, OnInit, Output, TemplateRef, ViewEncapsulation Input, OnInit, Output, TemplateRef, ViewEncapsulation, OnDestroy
} from '@angular/core'; } from '@angular/core';
import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms'; import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Router, ActivatedRoute, Params } from '@angular/router'; import { Router, ActivatedRoute, Params } from '@angular/router';
@@ -36,6 +36,8 @@ import {
} from '../../app-config/app-config.service'; } from '../../app-config/app-config.service';
import { OauthConfigModel } from '../../models/oauth-config.model'; import { OauthConfigModel } from '../../models/oauth-config.model';
import { DomSanitizer } from '@angular/platform-browser'; import { DomSanitizer } from '@angular/platform-browser';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
enum LoginSteps { enum LoginSteps {
Landing = 0, Landing = 0,
@@ -57,7 +59,7 @@ interface ValidationMessage {
class: 'adf-login' class: 'adf-login'
} }
}) })
export class LoginComponent implements OnInit { export class LoginComponent implements OnInit, OnDestroy {
isPasswordShow: boolean = false; isPasswordShow: boolean = false;
/** /**
@@ -127,6 +129,7 @@ export class LoginComponent implements OnInit {
data: any; data: any;
private _message: { [id: string]: { [id: string]: ValidationMessage } }; private _message: { [id: string]: { [id: string]: ValidationMessage } };
private onDestroy$ = new Subject<boolean>();
/** /**
* Constructor * Constructor
@@ -175,7 +178,14 @@ export class LoginComponent implements OnInit {
this.initFormFieldsDefault(); this.initFormFieldsDefault();
this.initFormFieldsMessagesDefault(); this.initFormFieldsMessagesDefault();
} }
this.form.valueChanges.subscribe((data) => this.onValueChanged(data)); this.form.valueChanges
.pipe(takeUntil(this.onDestroy$))
.subscribe(data => this.onValueChanged(data));
}
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
} }
submit() { submit() {

View File

@@ -24,12 +24,13 @@ import {
} from '@angular/core'; } from '@angular/core';
import { PaginatedComponent } from './paginated-component.interface'; import { PaginatedComponent } from './paginated-component.interface';
import { Subscription } from 'rxjs'; import { Subject } from 'rxjs';
import { PaginationComponentInterface } from './pagination-component.interface'; import { PaginationComponentInterface } from './pagination-component.interface';
import { PaginationModel } from '../models/pagination.model'; import { PaginationModel } from '../models/pagination.model';
import { RequestPaginationModel } from '../models/request-pagination.model'; import { RequestPaginationModel } from '../models/request-pagination.model';
import { UserPreferencesService, UserPreferenceValues } from '../services/user-preferences.service'; import { UserPreferencesService, UserPreferenceValues } from '../services/user-preferences.service';
import { Pagination } from '@alfresco/js-api'; import { Pagination } from '@alfresco/js-api';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'adf-infinite-pagination', selector: 'adf-infinite-pagination',
@@ -48,13 +49,16 @@ export class InfinitePaginationComponent implements OnInit, OnDestroy, Paginatio
}); });
_target: PaginatedComponent; _target: PaginatedComponent;
private onDestroy$ = new Subject<boolean>();
/** Component that provides custom pagination support. */ /** Component that provides custom pagination support. */
@Input() @Input()
set target(target: PaginatedComponent) { set target(target: PaginatedComponent) {
if (target) { if (target) {
this._target = target; this._target = target;
this.paginationSubscription = target.pagination.subscribe((pagination: PaginationModel) => { target.pagination
.pipe(takeUntil(this.onDestroy$))
.subscribe(pagination => {
this.isLoading = false; this.isLoading = false;
this.pagination = pagination; this.pagination = pagination;
@@ -90,14 +94,15 @@ export class InfinitePaginationComponent implements OnInit, OnDestroy, Paginatio
merge: true merge: true
}; };
private paginationSubscription: Subscription;
constructor(private cdr: ChangeDetectorRef, constructor(private cdr: ChangeDetectorRef,
private userPreferencesService: UserPreferencesService) { private userPreferencesService: UserPreferencesService) {
} }
ngOnInit() { ngOnInit() {
this.userPreferencesService.select(UserPreferenceValues.PaginationSize).subscribe((pageSize: number) => { this.userPreferencesService
.select(UserPreferenceValues.PaginationSize)
.pipe(takeUntil(this.onDestroy$))
.subscribe((pageSize: number) => {
this.pageSize = this.pageSize || pageSize; this.pageSize = this.pageSize || pageSize;
this.requestPaginationModel.maxItems = this.pageSize; this.requestPaginationModel.maxItems = this.pageSize;
}); });
@@ -127,8 +132,7 @@ export class InfinitePaginationComponent implements OnInit, OnDestroy, Paginatio
} }
ngOnDestroy() { ngOnDestroy() {
if (this.paginationSubscription) { this.onDestroy$.next(true);
this.paginationSubscription.unsubscribe(); this.onDestroy$.complete();
}
} }
} }

View File

@@ -23,9 +23,10 @@ import {
import { Pagination } from '@alfresco/js-api'; import { Pagination } from '@alfresco/js-api';
import { PaginatedComponent } from './paginated-component.interface'; import { PaginatedComponent } from './paginated-component.interface';
import { PaginationComponentInterface } from './pagination-component.interface'; import { PaginationComponentInterface } from './pagination-component.interface';
import { Subscription } from 'rxjs'; import { Subject } from 'rxjs';
import { PaginationModel } from '../models/pagination.model'; import { PaginationModel } from '../models/pagination.model';
import { UserPreferencesService, UserPreferenceValues } from '../services/user-preferences.service'; import { UserPreferencesService, UserPreferenceValues } from '../services/user-preferences.service';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'adf-pagination', selector: 'adf-pagination',
@@ -82,22 +83,25 @@ export class PaginationComponent implements OnInit, OnDestroy, PaginationCompone
@Output() @Output()
prevPage: EventEmitter<PaginationModel> = new EventEmitter<PaginationModel>(); prevPage: EventEmitter<PaginationModel> = new EventEmitter<PaginationModel>();
private paginationSubscription: Subscription; private onDestroy$ = new Subject<boolean>();
constructor(private cdr: ChangeDetectorRef, private userPreferencesService: UserPreferencesService) { constructor(private cdr: ChangeDetectorRef, private userPreferencesService: UserPreferencesService) {
this.userPreferencesService.select(UserPreferenceValues.PaginationSize).subscribe((pagSize) => {
this.pagination.maxItems = pagSize;
});
} }
ngOnInit() { ngOnInit() {
this.userPreferencesService
.select(UserPreferenceValues.PaginationSize)
.pipe(takeUntil(this.onDestroy$))
.subscribe(pagSize => this.pagination.maxItems = pagSize);
if (!this.supportedPageSizes) { if (!this.supportedPageSizes) {
this.supportedPageSizes = this.userPreferencesService.supportedPageSizes; this.supportedPageSizes = this.userPreferencesService.supportedPageSizes;
} }
if (this.target) { if (this.target) {
this.paginationSubscription = this.target.pagination.subscribe((pagination: PaginationModel) => { this.target.pagination
.pipe(takeUntil(this.onDestroy$))
.subscribe(pagination => {
if (pagination.count === 0 && !this.isFirstPage) { if (pagination.count === 0 && !this.isFirstPage) {
this.goPrevious(); this.goPrevious();
} }
@@ -217,6 +221,11 @@ export class PaginationComponent implements OnInit, OnDestroy, PaginationCompone
}); });
} }
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
handlePaginationEvent(action: string, params: PaginationModel) { handlePaginationEvent(action: string, params: PaginationModel) {
const { const {
NEXT_PAGE, NEXT_PAGE,
@@ -258,10 +267,4 @@ export class PaginationComponent implements OnInit, OnDestroy, PaginationCompone
this.target.updatePagination(params); this.target.updatePagination(params);
} }
} }
ngOnDestroy() {
if (this.paginationSubscription) {
this.paginationSubscription.unsubscribe();
}
}
} }

View File

@@ -16,15 +16,17 @@
*/ */
import { DatePipe } from '@angular/common'; import { DatePipe } from '@angular/common';
import { Pipe, PipeTransform } from '@angular/core'; import { Pipe, PipeTransform, OnDestroy } from '@angular/core';
import { AppConfigService } from '../app-config/app-config.service'; import { AppConfigService } from '../app-config/app-config.service';
import { UserPreferencesService, UserPreferenceValues } from '../services/user-preferences.service'; import { UserPreferencesService, UserPreferenceValues } from '../services/user-preferences.service';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Pipe({ @Pipe({
name: 'adfLocalizedDate', name: 'adfLocalizedDate',
pure: false pure: false
}) })
export class LocalizedDatePipe implements PipeTransform { export class LocalizedDatePipe implements PipeTransform, OnDestroy {
static DEFAULT_LOCALE = 'en-US'; static DEFAULT_LOCALE = 'en-US';
static DEFAULT_DATE_FORMAT = 'mediumDate'; static DEFAULT_DATE_FORMAT = 'mediumDate';
@@ -32,11 +34,16 @@ export class LocalizedDatePipe implements PipeTransform {
defaultLocale: string = LocalizedDatePipe.DEFAULT_LOCALE; defaultLocale: string = LocalizedDatePipe.DEFAULT_LOCALE;
defaultFormat: string = LocalizedDatePipe.DEFAULT_DATE_FORMAT; defaultFormat: string = LocalizedDatePipe.DEFAULT_DATE_FORMAT;
private onDestroy$ = new Subject<boolean>();
constructor(public userPreferenceService?: UserPreferencesService, constructor(public userPreferenceService?: UserPreferencesService,
public appConfig?: AppConfigService) { public appConfig?: AppConfigService) {
if (this.userPreferenceService) { if (this.userPreferenceService) {
this.userPreferenceService.select(UserPreferenceValues.Locale).subscribe((locale) => { this.userPreferenceService
.select(UserPreferenceValues.Locale)
.pipe(takeUntil(this.onDestroy$))
.subscribe(locale => {
if (locale) { if (locale) {
this.defaultLocale = locale; this.defaultLocale = locale;
} }
@@ -55,4 +62,9 @@ export class LocalizedDatePipe implements PipeTransform {
return datePipe.transform(value, actualFormat); return datePipe.transform(value, actualFormat);
} }
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
} }

View File

@@ -16,15 +16,17 @@
*/ */
import moment from 'moment-es6'; import moment from 'moment-es6';
import { Pipe, PipeTransform } from '@angular/core'; import { Pipe, PipeTransform, OnDestroy } from '@angular/core';
import { AppConfigService } from '../app-config/app-config.service'; import { AppConfigService } from '../app-config/app-config.service';
import { UserPreferenceValues, UserPreferencesService } from '../services/user-preferences.service'; import { UserPreferenceValues, UserPreferencesService } from '../services/user-preferences.service';
import { DatePipe } from '@angular/common'; import { DatePipe } from '@angular/common';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Pipe({ @Pipe({
name: 'adfTimeAgo' name: 'adfTimeAgo'
}) })
export class TimeAgoPipe implements PipeTransform { export class TimeAgoPipe implements PipeTransform, OnDestroy {
static DEFAULT_LOCALE = 'en-US'; static DEFAULT_LOCALE = 'en-US';
static DEFAULT_DATE_TIME_FORMAT = 'dd/MM/yyyy HH:mm'; static DEFAULT_DATE_TIME_FORMAT = 'dd/MM/yyyy HH:mm';
@@ -32,9 +34,14 @@ export class TimeAgoPipe implements PipeTransform {
defaultLocale: string; defaultLocale: string;
defaultDateTimeFormat: string; defaultDateTimeFormat: string;
private onDestroy$ = new Subject<boolean>();
constructor(public userPreferenceService: UserPreferencesService, constructor(public userPreferenceService: UserPreferencesService,
public appConfig: AppConfigService) { public appConfig: AppConfigService) {
this.userPreferenceService.select(UserPreferenceValues.Locale).subscribe((locale) => { this.userPreferenceService
.select(UserPreferenceValues.Locale)
.pipe(takeUntil(this.onDestroy$))
.subscribe(locale => {
this.defaultLocale = locale || TimeAgoPipe.DEFAULT_LOCALE; this.defaultLocale = locale || TimeAgoPipe.DEFAULT_LOCALE;
}); });
this.defaultDateTimeFormat = this.appConfig.get<string>('dateValues.defaultDateTimeFormat', TimeAgoPipe.DEFAULT_DATE_TIME_FORMAT); this.defaultDateTimeFormat = this.appConfig.get<string>('dateValues.defaultDateTimeFormat', TimeAgoPipe.DEFAULT_DATE_TIME_FORMAT);
@@ -54,4 +61,9 @@ export class TimeAgoPipe implements PipeTransform {
} }
return ''; return '';
} }
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
} }

View File

@@ -15,13 +15,15 @@
* limitations under the License. * limitations under the License.
*/ */
import { AfterContentInit, ContentChild, Directive, Input, TemplateRef } from '@angular/core'; import { AfterContentInit, ContentChild, Directive, Input, TemplateRef, OnDestroy } from '@angular/core';
import { ViewerComponent } from '../components/viewer.component'; import { ViewerComponent } from '../components/viewer.component';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Directive({ @Directive({
selector: 'adf-viewer-extension' selector: 'adf-viewer-extension'
}) })
export class ViewerExtensionDirective implements AfterContentInit { export class ViewerExtensionDirective implements AfterContentInit, OnDestroy {
@ContentChild(TemplateRef) @ContentChild(TemplateRef)
template: any; template: any;
@@ -37,6 +39,8 @@ export class ViewerExtensionDirective implements AfterContentInit {
templateModel: any; templateModel: any;
private onDestroy$ = new Subject<boolean>();
constructor(private viewerComponent: ViewerComponent) { constructor(private viewerComponent: ViewerComponent) {
} }
@@ -45,7 +49,9 @@ export class ViewerExtensionDirective implements AfterContentInit {
this.viewerComponent.extensionTemplates.push(this.templateModel); this.viewerComponent.extensionTemplates.push(this.templateModel);
this.viewerComponent.extensionChange.subscribe((fileExtension) => { this.viewerComponent.extensionChange
.pipe(takeUntil(this.onDestroy$))
.subscribe(fileExtension => {
this.templateModel.isVisible = this.isVisible(fileExtension); this.templateModel.isVisible = this.isVisible(fileExtension);
}); });
@@ -56,6 +62,11 @@ export class ViewerExtensionDirective implements AfterContentInit {
} }
} }
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
/** /**
* check if the current extension in the viewer is compatible with this extension checking against supportedExtensions * check if the current extension in the viewer is compatible with this extension checking against supportedExtensions
*/ */

View File

@@ -37,6 +37,8 @@ import { ReportParameterDetailsModel } from '../../diagram/models/report/reportP
import { ReportParametersModel } from '../../diagram/models/report/reportParameters.model'; import { ReportParametersModel } from '../../diagram/models/report/reportParameters.model';
import { ReportQuery } from '../../diagram/models/report/reportQuery.model'; import { ReportQuery } from '../../diagram/models/report/reportQuery.model';
import { AnalyticsService } from '../services/analytics.service'; import { AnalyticsService } from '../services/analytics.service';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'adf-analytics-report-parameters', selector: 'adf-analytics-report-parameters',
@@ -80,7 +82,7 @@ export class AnalyticsReportParametersComponent implements OnInit, OnChanges, On
onDropdownChanged = new EventEmitter(); onDropdownChanged = new EventEmitter();
successReportParams = new EventEmitter(); successReportParams = new EventEmitter<ReportParametersModel>();
successParamOpt = new EventEmitter(); successParamOpt = new EventEmitter();
@@ -94,12 +96,10 @@ export class AnalyticsReportParametersComponent implements OnInit, OnChanges, On
reportName: string; reportName: string;
private dropDownSub;
private reportParamsSub;
private paramOpts;
reportParamQuery: ReportQuery; reportParamQuery: ReportQuery;
private hideParameters: boolean = true; private hideParameters: boolean = true;
formValidState: boolean = false; formValidState: boolean = false;
private onDestroy$ = new Subject<boolean>();
constructor(private analyticsService: AnalyticsService, constructor(private analyticsService: AnalyticsService,
private formBuilder: FormBuilder, private formBuilder: FormBuilder,
@@ -110,14 +110,22 @@ export class AnalyticsReportParametersComponent implements OnInit, OnChanges, On
} }
ngOnInit() { ngOnInit() {
this.dropDownSub = this.onDropdownChanged.subscribe((field) => { this.onDropdownChanged
const paramDependOn: ReportParameterDetailsModel = this.reportParameters.definition.parameters.find((p) => p.dependsOn === field.id); .pipe(takeUntil(this.onDestroy$))
.subscribe((field: any) => {
const paramDependOn = this.reportParameters.definition.parameters.find(
(param) => param.dependsOn === field.id
);
if (paramDependOn) { if (paramDependOn) {
this.retrieveParameterOptions(this.reportParameters.definition.parameters, this.appId, this.reportId, field.value); this.retrieveParameterOptions(
this.reportParameters.definition.parameters, this.appId, this.reportId, field.value
);
} }
}); });
this.paramOpts = this.successReportParams.subscribe((report: ReportParametersModel) => { this.successReportParams
.pipe(takeUntil(this.onDestroy$))
.subscribe(report => {
if (report.hasParameters()) { if (report.hasParameters()) {
this.retrieveParameterOptions(report.definition.parameters, this.appId); this.retrieveParameterOptions(report.definition.parameters, this.appId);
this.generateFormGroupFromParameter(report.definition.parameters); this.generateFormGroupFromParameter(report.definition.parameters);
@@ -195,7 +203,7 @@ export class AnalyticsReportParametersComponent implements OnInit, OnChanges, On
} }
public getReportParams(reportId: string) { public getReportParams(reportId: string) {
this.reportParamsSub = this.analyticsService.getReportParams(reportId).subscribe( this.analyticsService.getReportParams(reportId).subscribe(
(res: ReportParametersModel) => { (res: ReportParametersModel) => {
this.reportParameters = res; this.reportParameters = res;
if (this.reportParameters.hasParameters()) { if (this.reportParameters.hasParameters()) {
@@ -293,11 +301,8 @@ export class AnalyticsReportParametersComponent implements OnInit, OnChanges, On
} }
ngOnDestroy() { ngOnDestroy() {
this.dropDownSub.unsubscribe(); this.onDestroy$.next(true);
this.paramOpts.unsubscribe(); this.onDestroy$.complete();
if (this.reportParamsSub) {
this.reportParamsSub.unsubscribe();
}
} }
public editEnable() { public editEnable() {
@@ -309,12 +314,14 @@ export class AnalyticsReportParametersComponent implements OnInit, OnChanges, On
} }
public editTitle() { public editTitle() {
this.reportParamsSub = this.analyticsService.updateReport(this.reportParameters.id, this.reportParameters.name).subscribe( this.analyticsService
(res: ReportParametersModel) => { .updateReport(this.reportParameters.id, this.reportParameters.name)
.subscribe(
() => {
this.editDisable(); this.editDisable();
this.edit.emit(this.reportParameters.name); this.edit.emit(this.reportParameters.name);
}, },
(err: any) => { err => {
this.error.emit(err); this.error.emit(err);
} }
); );

View File

@@ -18,11 +18,13 @@
/* tslint:disable:no-input-rename */ /* tslint:disable:no-input-rename */
import { MOMENT_DATE_FORMATS, MomentDateAdapter, UserPreferencesService, UserPreferenceValues } from '@alfresco/adf-core'; import { MOMENT_DATE_FORMATS, MomentDateAdapter, UserPreferencesService, UserPreferenceValues } 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 { AbstractControl, FormControl, FormGroup, Validators } from '@angular/forms'; import { AbstractControl, FormControl, FormGroup, Validators } from '@angular/forms';
import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material'; import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material';
import moment from 'moment-es6'; import moment from 'moment-es6';
import { Moment } from 'moment'; import { Moment } from 'moment';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'adf-date-range-widget', selector: 'adf-date-range-widget',
@@ -33,7 +35,7 @@ import { Moment } from 'moment';
styleUrls: ['./date-range.widget.scss'], styleUrls: ['./date-range.widget.scss'],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class DateRangeWidgetComponent implements OnInit { export class DateRangeWidgetComponent implements OnInit, OnDestroy {
public FORMAT_DATE_ACTIVITI: string = 'YYYY-MM-DD'; public FORMAT_DATE_ACTIVITI: string = 'YYYY-MM-DD';
public SHOW_FORMAT: string = 'DD/MM/YYYY'; public SHOW_FORMAT: string = 'DD/MM/YYYY';
@@ -52,15 +54,18 @@ export class DateRangeWidgetComponent implements OnInit {
startDatePicker: Moment = moment(); startDatePicker: Moment = moment();
endDatePicker: Moment = moment(); endDatePicker: Moment = moment();
private onDestroy$ = new Subject<boolean>();
constructor( constructor(
private dateAdapter: DateAdapter<Moment>, private dateAdapter: DateAdapter<Moment>,
private userPreferencesService: UserPreferencesService) { private userPreferencesService: UserPreferencesService) {
} }
ngOnInit() { ngOnInit() {
this.userPreferencesService.select(UserPreferenceValues.Locale).subscribe((locale) => { this.userPreferencesService
this.dateAdapter.setLocale(locale); .select(UserPreferenceValues.Locale)
}); .pipe(takeUntil(this.onDestroy$))
.subscribe(locale => this.dateAdapter.setLocale(locale));
const momentDateAdapter = <MomentDateAdapter> this.dateAdapter; const momentDateAdapter = <MomentDateAdapter> this.dateAdapter;
momentDateAdapter.overrideDisplayFormat = this.SHOW_FORMAT; momentDateAdapter.overrideDisplayFormat = this.SHOW_FORMAT;
@@ -87,6 +92,11 @@ export class DateRangeWidgetComponent implements OnInit {
this.dateRange.valueChanges.subscribe(() => this.onGroupValueChanged()); this.dateRange.valueChanges.subscribe(() => this.onGroupValueChanged());
} }
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
onGroupValueChanged() { onGroupValueChanged() {
if (this.dateRange.valid) { if (this.dateRange.valid) {
const dateStart = this.convertToMomentDateWithTime(this.dateRange.controls.startDate.value); const dateStart = this.convertToMomentDateWithTime(this.dateRange.controls.startDate.value);

View File

@@ -56,7 +56,7 @@ describe('AttachFileCloudWidgetComponent', () => {
} }
}; };
const contentSourceparam = { const contentSourceParam = {
fileSource: { fileSource: {
name: 'mock-alf-content', name: 'mock-alf-content',
serviceId: 'alfresco-content' serviceId: 'alfresco-content'
@@ -130,7 +130,7 @@ describe('AttachFileCloudWidgetComponent', () => {
value: [] value: []
}); });
widget.field.id = 'attach-file-alfresco'; widget.field.id = 'attach-file-alfresco';
widget.field.params = <FormFieldMetadata> contentSourceparam; widget.field.params = <FormFieldMetadata> contentSourceParam;
fixture.detectChanges(); fixture.detectChanges();
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
expect(element.querySelector('.adf-attach-widget__menu-upload')).not.toBeNull(); expect(element.querySelector('.adf-attach-widget__menu-upload')).not.toBeNull();
@@ -144,7 +144,7 @@ describe('AttachFileCloudWidgetComponent', () => {
value: [] value: []
}); });
widget.field.id = 'attach-file-alfresco'; widget.field.id = 'attach-file-alfresco';
widget.field.params = <FormFieldMetadata> contentSourceparam; widget.field.params = <FormFieldMetadata> contentSourceParam;
fixture.detectChanges(); fixture.detectChanges();
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
const attachButton: HTMLButtonElement = element.querySelector('#attach-file-alfresco'); 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(() => { it('should fetch process instance filter by id', async(() => {
const processFilterIDchange = new SimpleChange(null, 'mock-process-filter-id', true); const processFilterIdChange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIDchange }); component.ngOnChanges({ 'id': processFilterIdChange });
fixture.detectChanges(); fixture.detectChanges();
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
fixture.detectChanges(); fixture.detectChanges();
@@ -103,8 +103,8 @@ describe('EditProcessFilterCloudComponent', () => {
})); }));
it('should display filter name as title', async(() => { it('should display filter name as title', async(() => {
const processFilterIDchange = new SimpleChange(null, 'mock-process-filter-id', true); const processFilterIdChange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIDchange }); component.ngOnChanges({ 'id': processFilterIdChange });
fixture.detectChanges(); fixture.detectChanges();
const title = fixture.debugElement.nativeElement.querySelector('#adf-edit-process-filter-title-id'); 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'); 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(() => { it('should not display mat-spinner if isloading set to false', async(() => {
const processFilterIDchange = new SimpleChange(null, 'mock-process-filter-id', true); const processFilterIdChange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIDchange }); component.ngOnChanges({ 'id': processFilterIdChange });
fixture.detectChanges(); fixture.detectChanges();
const title = fixture.debugElement.nativeElement.querySelector('#adf-edit-process-filter-title-id'); 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'); 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(() => { it('should display mat-spinner if isloading set to true', async(() => {
component.isLoading = true; component.isLoading = true;
const processFilterIDchange = new SimpleChange(null, 'mock-process-filter-id', true); const processFilterIdChange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIDchange }); component.ngOnChanges({ 'id': processFilterIdChange });
fixture.detectChanges(); fixture.detectChanges();
const matSpinnerElement = fixture.debugElement.nativeElement.querySelector('.adf-cloud-edit-process-filter-loading-margin'); const matSpinnerElement = fixture.debugElement.nativeElement.querySelector('.adf-cloud-edit-process-filter-loading-margin');
@@ -150,8 +150,8 @@ describe('EditProcessFilterCloudComponent', () => {
describe('EditProcessFilter form', () => { describe('EditProcessFilter form', () => {
beforeEach(() => { beforeEach(() => {
const processFilterIDchange = new SimpleChange(null, 'mock-process-filter-id', true); const processFilterIdChange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIDchange }); component.ngOnChanges({ 'id': processFilterIdChange });
fixture.detectChanges(); fixture.detectChanges();
}); });
@@ -245,14 +245,17 @@ describe('EditProcessFilterCloudComponent', () => {
it('should display state drop down', async(() => { it('should display state drop down', async(() => {
fixture.detectChanges(); fixture.detectChanges();
const expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header'); const expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header');
expansionPanel.click(); expansionPanel.click();
const stateElement = fixture.debugElement.nativeElement.querySelector('[data-automation-id="adf-cloud-edit-process-property-status"] .mat-select-trigger'); const stateElement = fixture.debugElement.nativeElement.querySelector('[data-automation-id="adf-cloud-edit-process-property-status"] .mat-select-trigger');
stateElement.click(); stateElement.click();
fixture.detectChanges(); fixture.detectChanges();
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
const statusOptions = fixture.debugElement.queryAll(By.css('.mat-option-text')); 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(); fixture.detectChanges();
component.filterProperties = ['appName', 'processName']; component.filterProperties = ['appName', 'processName'];
fixture.detectChanges(); fixture.detectChanges();
const processFilterIDchange = new SimpleChange(null, 'mock-process-filter-id', true); const processFilterIdChange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIDchange }); component.ngOnChanges({ 'id': processFilterIdChange });
fixture.detectChanges(); fixture.detectChanges();
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
fixture.detectChanges(); fixture.detectChanges();
@@ -302,8 +305,8 @@ describe('EditProcessFilterCloudComponent', () => {
fixture.detectChanges(); fixture.detectChanges();
component.filterProperties = []; component.filterProperties = [];
fixture.detectChanges(); fixture.detectChanges();
const processFilterIDchange = new SimpleChange(null, 'mock-process-filter-id', true); const processFilterIdChange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIDchange }); component.ngOnChanges({ 'id': processFilterIdChange });
fixture.detectChanges(); fixture.detectChanges();
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
const stateController = component.editProcessFilterForm.get('status'); const stateController = component.editProcessFilterForm.get('status');
@@ -330,8 +333,8 @@ describe('EditProcessFilterCloudComponent', () => {
fixture.detectChanges(); fixture.detectChanges();
component.filterProperties = ['appName', 'processName']; component.filterProperties = ['appName', 'processName'];
fixture.detectChanges(); fixture.detectChanges();
const processFilterIDchange = new SimpleChange(null, 'mock-process-filter-id', true); const processFilterIdChange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIDchange }); component.ngOnChanges({ 'id': processFilterIdChange });
fixture.detectChanges(); fixture.detectChanges();
const appController = component.editProcessFilterForm.get('appName'); const appController = component.editProcessFilterForm.get('appName');
fixture.detectChanges(); fixture.detectChanges();
@@ -343,8 +346,8 @@ describe('EditProcessFilterCloudComponent', () => {
})); }));
it('should display default sort properties', async(() => { it('should display default sort properties', async(() => {
const processFilterIdchange = new SimpleChange(null, 'mock-process-filter-id', true); const processFilterIdChange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIdchange }); component.ngOnChanges({ 'id': processFilterIdChange });
fixture.detectChanges(); fixture.detectChanges();
const expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header'); const expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header');
expansionPanel.click(); expansionPanel.click();
@@ -373,8 +376,8 @@ describe('EditProcessFilterCloudComponent', () => {
})); }));
component.sortProperties = ['id', 'processName', 'processDefinitionId']; component.sortProperties = ['id', 'processName', 'processDefinitionId'];
fixture.detectChanges(); fixture.detectChanges();
const processFilterIdchange = new SimpleChange(null, 'mock-process-filter-id', true); const processFilterIdChange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIdchange }); component.ngOnChanges({ 'id': processFilterIdChange });
fixture.detectChanges(); fixture.detectChanges();
const expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header'); const expansionPanel = fixture.debugElement.nativeElement.querySelector('mat-expansion-panel-header');
expansionPanel.click(); expansionPanel.click();
@@ -396,8 +399,8 @@ describe('EditProcessFilterCloudComponent', () => {
describe('edit filter actions', () => { describe('edit filter actions', () => {
beforeEach(() => { beforeEach(() => {
const processFilterIDchange = new SimpleChange(null, 'mock-process-filter-id', true); const processFilterIdChange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIDchange }); component.ngOnChanges({ 'id': processFilterIdChange });
getProcessFilterByIdSpy.and.returnValue(of(fakeFilter)); getProcessFilterByIdSpy.and.returnValue(of(fakeFilter));
fixture.detectChanges(); 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; 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'); const deleteSpy: jasmine.Spy = spyOn(component.action, 'emit');
fixture.detectChanges(); fixture.detectChanges();
@@ -442,9 +445,14 @@ describe('EditProcessFilterCloudComponent', () => {
fixture.detectChanges(); fixture.detectChanges();
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
expect(deleteFilterSpy).toHaveBeenCalled(); expect(deleteFilterSpy).toHaveBeenCalled();
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(deleteSpy).toHaveBeenCalled(); expect(deleteSpy).toHaveBeenCalled();
done();
});
});
}); });
}));
it('should emit saveAs event and add filter on click saveAs button', async(() => { it('should emit saveAs event and add filter on click saveAs button', async(() => {
component.toggleFilterActions = true; component.toggleFilterActions = true;
@@ -497,8 +505,8 @@ describe('EditProcessFilterCloudComponent', () => {
fixture.detectChanges(); fixture.detectChanges();
component.actions = ['save']; component.actions = ['save'];
fixture.detectChanges(); fixture.detectChanges();
const processFilterIDchange = new SimpleChange(null, 'mock-process-filter-id', true); const processFilterIdChange = new SimpleChange(null, 'mock-process-filter-id', true);
component.ngOnChanges({ 'id': processFilterIDchange }); component.ngOnChanges({ 'id': processFilterIdChange });
fixture.detectChanges(); fixture.detectChanges();
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
expect(component.processFilterActions).toBeDefined(); expect(component.processFilterActions).toBeDefined();
@@ -534,8 +542,8 @@ describe('EditProcessFilterCloudComponent', () => {
it('should set the correct lastModifiedTo date', (done) => { it('should set the correct lastModifiedTo date', (done) => {
component.appName = 'fake'; component.appName = 'fake';
component.filterProperties = ['appName', 'processInstanceId', 'priority', 'lastModified']; component.filterProperties = ['appName', 'processInstanceId', 'priority', 'lastModified'];
const taskFilterIDchange = new SimpleChange(undefined, 'mock-task-filter-id', true); const taskFilterIdChange = new SimpleChange(undefined, 'mock-task-filter-id', true);
component.ngOnChanges({ 'id': taskFilterIDchange }); component.ngOnChanges({ 'id': taskFilterIdChange });
fixture.detectChanges(); fixture.detectChanges();
const lastModifiedToControl: AbstractControl = component.editProcessFilterForm.get('lastModifiedTo'); 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 { Component, Input, Output, EventEmitter, OnInit, OnChanges, SimpleChanges, OnDestroy } from '@angular/core';
import { FormGroup, FormBuilder, AbstractControl } from '@angular/forms'; import { FormGroup, FormBuilder, AbstractControl } from '@angular/forms';
import { MatDialog, DateAdapter } from '@angular/material'; 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 { Subject } from 'rxjs';
import moment from 'moment-es6'; import moment from 'moment-es6';
import { Moment } from 'moment'; import { Moment } from 'moment';
import { ApplicationInstanceModel } from '../../../app/models/application-instance.model';
import { AppsProcessCloudService } from '../../../app/services/apps-process-cloud.service'; import { AppsProcessCloudService } from '../../../app/services/apps-process-cloud.service';
import { ProcessFilterCloudModel, ProcessFilterProperties, ProcessFilterAction, ProcessFilterOptions } from '../models/process-filter-cloud.model'; import { ProcessFilterCloudModel, ProcessFilterProperties, ProcessFilterAction, ProcessFilterOptions } from '../models/process-filter-cloud.model';
import { TranslationService, UserPreferencesService, UserPreferenceValues } from '@alfresco/adf-core'; import { TranslationService, UserPreferencesService, UserPreferenceValues } from '@alfresco/adf-core';
@@ -120,9 +119,10 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes
private appsProcessCloudService: AppsProcessCloudService) { } private appsProcessCloudService: AppsProcessCloudService) { }
ngOnInit() { ngOnInit() {
this.userPreferencesService.select(UserPreferenceValues.Locale).subscribe((locale) => { this.userPreferencesService
this.dateAdapter.setLocale(locale); .select(UserPreferenceValues.Locale)
}); .pipe(takeUntil(this.onDestroy$))
.subscribe(locale => this.dateAdapter.setLocale(locale));
} }
ngOnChanges(changes: SimpleChanges) { ngOnChanges(changes: SimpleChanges) {
@@ -153,15 +153,14 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes
*/ */
retrieveProcessFilterAndBuildForm() { retrieveProcessFilterAndBuildForm() {
this.isLoading = true; this.isLoading = true;
this.processFilterCloudService.getFilterById(this.appName, this.id) this.processFilterCloudService
.pipe(takeUntil(this.onDestroy$)).subscribe((response) => { .getFilterById(this.appName, this.id)
this.isLoading = false; .pipe(finalize(() => this.isLoading = false))
.subscribe(response => {
this.processFilter = new ProcessFilterCloudModel(response); this.processFilter = new ProcessFilterCloudModel(response);
this.processFilterProperties = this.createAndFilterProperties(); this.processFilterProperties = this.createAndFilterProperties();
this.processFilterActions = this.createAndFilterActions(); this.processFilterActions = this.createAndFilterActions();
this.buildForm(this.processFilterProperties); this.buildForm(this.processFilterProperties);
}, (error) => {
this.isLoading = false;
}); });
} }
@@ -170,7 +169,11 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes
*/ */
onFilterChange() { onFilterChange() {
this.editProcessFilterForm.valueChanges this.editProcessFilterForm.valueChanges
.pipe(debounceTime(500), filter(() => this.isFormValid())) .pipe(
debounceTime(500),
filter(() => this.isFormValid()),
takeUntil(this.onDestroy$)
)
.subscribe((formValues: ProcessFilterCloudModel) => { .subscribe((formValues: ProcessFilterCloudModel) => {
this.setLastModifiedToFilter(formValues); this.setLastModifiedToFilter(formValues);
this.changedProcessFilter = new ProcessFilterCloudModel(Object.assign({}, this.processFilter, formValues)); this.changedProcessFilter = new ProcessFilterCloudModel(Object.assign({}, this.processFilter, formValues));
@@ -292,8 +295,9 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes
} }
getRunningApplications() { getRunningApplications() {
this.appsProcessCloudService.getDeployedApplicationsByStatus(EditProcessFilterCloudComponent.APP_RUNNING_STATUS) this.appsProcessCloudService
.pipe(takeUntil(this.onDestroy$)).subscribe((applications: ApplicationInstanceModel[]) => { .getDeployedApplicationsByStatus(EditProcessFilterCloudComponent.APP_RUNNING_STATUS)
.subscribe(applications => {
if (applications && applications.length > 0) { if (applications && applications.length > 0) {
applications.map((application) => { applications.map((application) => {
this.applicationNames.push({ label: application.name, value: application.name }); this.applicationNames.push({ label: application.name, value: application.name });
@@ -316,8 +320,9 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes
* Save a process instance filter * Save a process instance filter
*/ */
save(saveAction: ProcessFilterAction) { save(saveAction: ProcessFilterAction) {
this.processFilterCloudService.updateFilter(this.changedProcessFilter) this.processFilterCloudService
.pipe(takeUntil(this.onDestroy$)).subscribe((res) => { .updateFilter(this.changedProcessFilter)
.subscribe(() => {
saveAction.filter = this.changedProcessFilter; saveAction.filter = this.changedProcessFilter;
this.action.emit(saveAction); this.action.emit(saveAction);
this.formHasBeenChanged = this.compareFilters(this.changedProcessFilter, this.processFilter); this.formHasBeenChanged = this.compareFilters(this.changedProcessFilter, this.processFilter);
@@ -328,8 +333,9 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes
* Delete a process instance filter * Delete a process instance filter
*/ */
delete(deleteAction: ProcessFilterAction) { delete(deleteAction: ProcessFilterAction) {
this.processFilterCloudService.deleteFilter(this.processFilter) this.processFilterCloudService
.pipe(takeUntil(this.onDestroy$)).subscribe((res) => { .deleteFilter(this.processFilter)
.subscribe(() => {
deleteAction.filter = this.processFilter; deleteAction.filter = this.processFilter;
this.action.emit(deleteAction); this.action.emit(deleteAction);
}); });
@@ -357,8 +363,9 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes
key: 'custom-' + filterKey key: 'custom-' + filterKey
}; };
const resultFilter: ProcessFilterCloudModel = Object.assign({}, this.changedProcessFilter, newFilter); const resultFilter: ProcessFilterCloudModel = Object.assign({}, this.changedProcessFilter, newFilter);
this.processFilterCloudService.addFilter(resultFilter) this.processFilterCloudService
.pipe(takeUntil(this.onDestroy$)).subscribe((res) => { .addFilter(resultFilter)
.subscribe(() => {
saveAsAction.filter = resultFilter; saveAsAction.filter = resultFilter;
this.action.emit(saveAsAction); this.action.emit(saveAsAction);
}); });

View File

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

View File

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

View File

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

View File

@@ -16,9 +16,9 @@
*/ */
import { FormControl } from '@angular/forms'; import { FormControl } from '@angular/forms';
import { Component, OnInit, Output, EventEmitter, ViewEncapsulation, Input, ViewChild, ElementRef, SimpleChanges, OnChanges } from '@angular/core'; import { Component, OnInit, Output, EventEmitter, ViewEncapsulation, Input, ViewChild, ElementRef, SimpleChanges, OnChanges, OnDestroy } from '@angular/core';
import { Observable, of, BehaviorSubject } from 'rxjs'; import { Observable, of, BehaviorSubject, Subject } from 'rxjs';
import { switchMap, debounceTime, distinctUntilChanged, mergeMap, tap, filter, map } from 'rxjs/operators'; import { switchMap, debounceTime, distinctUntilChanged, mergeMap, tap, filter, map, takeUntil } from 'rxjs/operators';
import { FullNamePipe, IdentityUserModel, IdentityUserService, LogService } from '@alfresco/adf-core'; import { FullNamePipe, IdentityUserModel, IdentityUserService, LogService } from '@alfresco/adf-core';
import { trigger, state, style, transition, animate } from '@angular/animations'; 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 encapsulation: ViewEncapsulation.None
}) })
export class PeopleCloudComponent implements OnInit, OnChanges { export class PeopleCloudComponent implements OnInit, OnChanges, OnDestroy {
static MODE_SINGLE = 'single'; static MODE_SINGLE = 'single';
static MODE_MULTIPLE = 'multiple'; static MODE_MULTIPLE = 'multiple';
@@ -98,15 +98,13 @@ export class PeopleCloudComponent implements OnInit, OnChanges {
private _searchUsers: IdentityUserModel[] = []; private _searchUsers: IdentityUserModel[] = [];
private selectedUsersSubject: BehaviorSubject<IdentityUserModel[]>; private selectedUsersSubject: BehaviorSubject<IdentityUserModel[]>;
private searchUsersSubject: BehaviorSubject<IdentityUserModel[]>; private searchUsersSubject: BehaviorSubject<IdentityUserModel[]>;
private onDestroy$ = new Subject<boolean>();
selectedUsers$: Observable<IdentityUserModel[]>; selectedUsers$: Observable<IdentityUserModel[]>;
searchUsers$: Observable<IdentityUserModel[]>; searchUsers$: Observable<IdentityUserModel[]>;
_subscriptAnimationState: string = 'enter'; _subscriptAnimationState: string = 'enter';
clientId: string; clientId: string;
isFocused: boolean; isFocused: boolean;
invalidUsers: IdentityUserModel[] = []; invalidUsers: IdentityUserModel[] = [];
constructor(private identityUserService: IdentityUserService, private logService: LogService) { 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() { initSubjects() {
if (this.selectedUsersSubject === undefined) { if (this.selectedUsersSubject === undefined) {
this.selectedUsersSubject = new BehaviorSubject<IdentityUserModel[]>(this.preSelectUsers); 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 return result
&& (result.id !== undefined && (result.id !== undefined
|| result.username !== undefined || result.username !== undefined
|| result.amil !== undefined); || result.email !== undefined);
} }
private initSearch() { private initSearch() {
@@ -285,8 +288,9 @@ export class PeopleCloudComponent implements OnInit, OnChanges {
} else { } else {
return of(user); return of(user);
} }
}) }),
).subscribe((user) => { takeUntil(this.onDestroy$)
).subscribe((user: any) => {
this._searchUsers.push(user); this._searchUsers.push(user);
this.searchUsersSubject.next(this._searchUsers); 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_DATE_FORMATS, MomentDateAdapter } from '@alfresco/adf-core';
import moment from 'moment-es6'; import moment from 'moment-es6';
import { Moment } from 'moment'; import { Moment } from 'moment';
import { Observable, Subscription } from 'rxjs'; import { Observable, Subject } from 'rxjs';
import { FormBuilder, AbstractControl, Validators, FormGroup, FormControl } from '@angular/forms'; import { FormBuilder, AbstractControl, Validators, FormGroup, FormControl } from '@angular/forms';
import { import {
LogService, LogService,
@@ -32,6 +32,7 @@ import { PeopleCloudComponent } from './people-cloud/people-cloud.component';
import { GroupCloudComponent } from '../../../../lib/group/components/group-cloud.component'; import { GroupCloudComponent } from '../../../../lib/group/components/group-cloud.component';
import { TaskCloudService } from '../../services/task-cloud.service'; import { TaskCloudService } from '../../services/task-cloud.service';
import { StartTaskCloudRequestModel } from '../models/start-task-cloud-request.model'; import { StartTaskCloudRequestModel } from '../models/start-task-cloud-request.model';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'adf-cloud-start-task', selector: 'adf-cloud-start-task',
@@ -101,9 +102,7 @@ export class StartTaskCloudComponent implements OnInit, OnDestroy {
private assigneeForm: AbstractControl = new FormControl(''); private assigneeForm: AbstractControl = new FormControl('');
private groupForm: AbstractControl = new FormControl(''); private groupForm: AbstractControl = new FormControl('');
private onDestroy$ = new Subject<boolean>();
private localeSub: Subscription;
private createTaskSub: Subscription;
constructor(private taskService: TaskCloudService, constructor(private taskService: TaskCloudService,
private dateAdapter: DateAdapter<Moment>, private dateAdapter: DateAdapter<Moment>,
@@ -114,21 +113,17 @@ export class StartTaskCloudComponent implements OnInit, OnDestroy {
} }
ngOnInit() { ngOnInit() {
this.userPreferencesService.select(UserPreferenceValues.Locale).subscribe((locale) => { this.userPreferencesService
this.dateAdapter.setLocale(locale); .select(UserPreferenceValues.Locale)
}); .pipe(takeUntil(this.onDestroy$))
.subscribe(locale => this.dateAdapter.setLocale(locale));
this.loadCurrentUser(); this.loadCurrentUser();
this.buildForm(); this.buildForm();
} }
ngOnDestroy() { ngOnDestroy() {
if (this.localeSub) { this.onDestroy$.next(true);
this.localeSub.unsubscribe(); this.onDestroy$.complete();
}
if (this.createTaskSub) {
this.createTaskSub.unsubscribe();
}
} }
buildForm() { buildForm() {
@@ -162,7 +157,7 @@ export class StartTaskCloudComponent implements OnInit, OnDestroy {
} }
private createNewTask(newTask: StartTaskCloudRequestModel) { private createNewTask(newTask: StartTaskCloudRequestModel) {
this.createTaskSub = this.taskService.createNewTask(newTask, this.appName) this.taskService.createNewTask(newTask, this.appName)
.subscribe( .subscribe(
(res: any) => { (res: any) => {
this.submitted = false; this.submitted = false;

View File

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

View File

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

View File

@@ -49,7 +49,7 @@ export class TaskFilterCloudService {
} else if (!this.hasTaskFilters(preferences, key)) { } else if (!this.hasTaskFilters(preferences, key)) {
return this.createTaskFilters(appName, key, this.defaultTaskFilters(appName)); return this.createTaskFilters(appName, key, this.defaultTaskFilters(appName));
} else { } else {
return of(this.findFiltersByKeyInPrefrences(preferences, key)); return of(this.findFiltersByKeyInPreferences(preferences, key));
} }
}), }),
catchError((err) => this.handleTaskError(err)) catchError((err) => this.handleTaskError(err))
@@ -138,7 +138,7 @@ export class TaskFilterCloudService {
/** /**
* Adds a new task filter. * Adds a new task filter.
* @param filter The new filter to add * @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) { addFilter(newFilter: TaskFilterCloudModel) {
const key: string = this.prepareKey(newFilter.appName); const key: string = this.prepareKey(newFilter.appName);
@@ -244,7 +244,7 @@ export class TaskFilterCloudService {
* @param appName Name of the target app * @param appName Name of the target app
* @returns Array of TaskFilterCloudModel * @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; }); const result = preferences.find((filter: any) => { return filter.entry.key === key; });
return result && result.entry ? JSON.parse(result.entry.value) : []; 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 { TaskDetailsCloudModel, TaskStatusEnum } from '../../start-task/models/task-details-cloud.model';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { TaskCloudService } from '../../services/task-cloud.service'; import { TaskCloudService } from '../../services/task-cloud.service';
import { Subscription } from 'rxjs'; import { Subject } from 'rxjs';
import { NumericFieldValidator } from '../../../validators/numeric-field.validator'; import { NumericFieldValidator } from '../../../validators/numeric-field.validator';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'adf-cloud-task-header', selector: 'adf-cloud-task-header',
@@ -62,7 +63,7 @@ export class TaskHeaderCloudComponent implements OnInit, OnDestroy {
dateFormat: string; dateFormat: string;
dateLocale: string; dateLocale: string;
private subscriptions: Subscription[] = []; private onDestroy$ = new Subject<boolean>();
constructor( constructor(
private taskCloudService: TaskCloudService, private taskCloudService: TaskCloudService,
@@ -80,19 +81,21 @@ export class TaskHeaderCloudComponent implements OnInit, OnDestroy {
this.loadTaskDetailsById(this.appName, this.taskId); 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 { loadTaskDetailsById(appName: string, taskId: string): any {
this.subscriptions.push(this.taskCloudService.getTaskById(appName, taskId).subscribe( this.taskCloudService.getTaskById(appName, taskId).subscribe(
(taskDetails) => { (taskDetails) => {
this.taskDetails = taskDetails; this.taskDetails = taskDetails;
if (this.taskDetails.parentTaskId) { if (this.taskDetails.parentTaskId) {
this.loadParentName(this.taskDetails.parentTaskId); this.loadParentName(`${this.taskDetails.parentTaskId}`);
} else { } else {
this.refreshData(); this.refreshData();
} }
})); });
} }
private initDefaultProperties() { 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) this.taskCloudService.getTaskById(this.appName, taskId)
.subscribe( .subscribe(
(taskDetails) => { (taskDetails) => {
@@ -263,7 +266,7 @@ export class TaskHeaderCloudComponent implements OnInit, OnDestroy {
} }
ngOnDestroy() { ngOnDestroy() {
this.subscriptions.forEach((subscription) => subscription.unsubscribe()); this.onDestroy$.next(true);
this.subscriptions = []; this.onDestroy$.complete();
} }
} }

View File

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

View File

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

View File

@@ -16,18 +16,18 @@
*/ */
import { AppsProcessService, TranslationService, CustomEmptyContentTemplateDirective } from '@alfresco/adf-core'; import { AppsProcessService, TranslationService, CustomEmptyContentTemplateDirective } from '@alfresco/adf-core';
import { AfterContentInit, Component, EventEmitter, Input, OnInit, Output, ContentChild } from '@angular/core'; import { AfterContentInit, Component, EventEmitter, Input, OnInit, Output, ContentChild, OnDestroy } from '@angular/core';
import { Observable, Observer, of } from 'rxjs'; import { Observable, Observer, of, Subject } from 'rxjs';
import { AppDefinitionRepresentationModel } from '../task-list'; import { AppDefinitionRepresentationModel } from '../task-list';
import { IconModel } from './icon.model'; import { IconModel } from './icon.model';
import { share } from 'rxjs/operators'; import { share, takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'adf-apps', selector: 'adf-apps',
templateUrl: 'apps-list.component.html', templateUrl: 'apps-list.component.html',
styleUrls: ['./apps-list.component.scss'] styleUrls: ['./apps-list.component.scss']
}) })
export class AppsListComponent implements OnInit, AfterContentInit { export class AppsListComponent implements OnInit, AfterContentInit, OnDestroy {
public static LAYOUT_LIST: string = 'LIST'; public static LAYOUT_LIST: string = 'LIST';
public static LAYOUT_GRID: string = 'GRID'; public static LAYOUT_GRID: string = 'GRID';
@@ -60,17 +60,16 @@ export class AppsListComponent implements OnInit, AfterContentInit {
private appsObserver: Observer<AppDefinitionRepresentationModel>; private appsObserver: Observer<AppDefinitionRepresentationModel>;
apps$: Observable<AppDefinitionRepresentationModel>; apps$: Observable<AppDefinitionRepresentationModel>;
currentApp: AppDefinitionRepresentationModel; currentApp: AppDefinitionRepresentationModel;
appList: AppDefinitionRepresentationModel [] = []; appList: AppDefinitionRepresentationModel [] = [];
private iconsMDL: IconModel; private iconsMDL: IconModel;
loading: boolean = false; loading: boolean = false;
hasEmptyCustomContentTemplate: boolean = false; hasEmptyCustomContentTemplate: boolean = false;
private onDestroy$ = new Subject<boolean>();
constructor( constructor(
private appsProcessService: AppsProcessService, private appsProcessService: AppsProcessService,
private translationService: TranslationService) { private translationService: TranslationService) {
@@ -83,13 +82,19 @@ export class AppsListComponent implements OnInit, AfterContentInit {
this.setDefaultLayoutType(); this.setDefaultLayoutType();
} }
this.apps$.subscribe((app: any) => { this.apps$
this.appList.push(app); .pipe(takeUntil(this.onDestroy$))
}); .subscribe((app: any) => this.appList.push(app));
this.iconsMDL = new IconModel(); this.iconsMDL = new IconModel();
this.load(); this.load();
} }
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
ngAfterContentInit() { ngAfterContentInit() {
if (this.emptyCustomContent) { if (this.emptyCustomContent) {
this.hasEmptyCustomContentTemplate = true; this.hasEmptyCustomContentTemplate = true;

View File

@@ -17,7 +17,7 @@
/* tslint:disable:component-selector */ /* tslint:disable:component-selector */
import { Component, ViewEncapsulation, OnInit } from '@angular/core'; import { Component, ViewEncapsulation, OnInit, OnDestroy } from '@angular/core';
import { import {
UploadWidgetComponent, UploadWidgetComponent,
FormService, FormService,
@@ -26,14 +26,13 @@ import {
ProcessContentService, ProcessContentService,
ActivitiContentService, ActivitiContentService,
ContentService, ContentService,
FormEvent,
AppConfigValues, AppConfigValues,
AppConfigService AppConfigService
} from '@alfresco/adf-core'; } from '@alfresco/adf-core';
import { ContentNodeDialogService } from '@alfresco/adf-content-services'; import { ContentNodeDialogService } from '@alfresco/adf-content-services';
import { Node, RelatedContentRepresentation } from '@alfresco/js-api'; import { Node, RelatedContentRepresentation } from '@alfresco/js-api';
import { from, zip, of } from 'rxjs'; import { from, zip, of, Subject } from 'rxjs';
import { mergeMap } from 'rxjs/operators'; import { mergeMap, takeUntil } from 'rxjs/operators';
import { AttachFileWidgetDialogService } from './attach-file-widget-dialog.service'; import { AttachFileWidgetDialogService } from './attach-file-widget-dialog.service';
@Component({ @Component({
@@ -53,10 +52,11 @@ import { AttachFileWidgetDialogService } from './attach-file-widget-dialog.servi
}, },
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class AttachFileWidgetComponent extends UploadWidgetComponent implements OnInit { export class AttachFileWidgetComponent extends UploadWidgetComponent implements OnInit, OnDestroy {
repositoryList = []; repositoryList = [];
private tempFilesList = []; private tempFilesList = [];
private onDestroy$ = new Subject<boolean>();
constructor(public formService: FormService, constructor(public formService: FormService,
private logger: LogService, private logger: LogService,
@@ -82,13 +82,20 @@ export class AttachFileWidgetComponent extends UploadWidgetComponent implements
this.repositoryList = repoList; this.repositoryList = repoList;
}); });
this.formService.taskSaved.subscribe((formSaved: FormEvent) => { this.formService.taskSaved
.pipe(takeUntil(this.onDestroy$))
.subscribe(formSaved => {
if (formSaved.form.id === this.field.form.id) { if (formSaved.form.id === this.field.form.id) {
this.tempFilesList = []; this.tempFilesList = [];
} }
}); });
} }
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
isFileSourceConfigured(): boolean { isFileSourceConfigured(): boolean {
return !!this.field.params && !!this.field.params.fileSource; return !!this.field.params && !!this.field.params.fileSource;
} }

View File

@@ -15,17 +15,14 @@
* limitations under the License. * limitations under the License.
*/ */
import { import { Component, EventEmitter, Input, Output, ViewEncapsulation, SimpleChanges, OnInit, OnDestroy, OnChanges } from '@angular/core';
Component, EventEmitter, Input, Output, ViewEncapsulation, SimpleChanges, OnInit, OnDestroy, OnChanges
} from '@angular/core';
import { AttachFileWidgetComponent, AttachFolderWidgetComponent } from '../content-widget'; import { AttachFileWidgetComponent, AttachFolderWidgetComponent } from '../content-widget';
import { EcmModelService, NodeService, WidgetVisibilityService, import { EcmModelService, NodeService, WidgetVisibilityService,
FormService, FormRenderingService, FormBaseComponent, FormOutcomeModel, FormService, FormRenderingService, FormBaseComponent, FormOutcomeModel,
ValidateFormEvent, FormEvent, FormErrorEvent, FormFieldModel, FormEvent, FormErrorEvent, FormFieldModel,
FormModel, FormOutcomeEvent, FormValues, ContentLinkModel } from '@alfresco/adf-core'; FormModel, FormOutcomeEvent, FormValues, ContentLinkModel } from '@alfresco/adf-core';
import { Observable, of, Subject } from 'rxjs';
import { Observable, of, Subscription } from 'rxjs'; import { switchMap, takeUntil } from 'rxjs/operators';
import { switchMap } from 'rxjs/operators';
@Component({ @Component({
selector: 'adf-form', selector: 'adf-form',
@@ -84,7 +81,7 @@ export class FormComponent extends FormBaseComponent implements OnInit, OnDestro
debugMode: boolean = false; debugMode: boolean = false;
protected subscriptions: Subscription[] = []; protected onDestroy$ = new Subject<boolean>();
constructor(protected formService: FormService, constructor(protected formService: FormService,
protected visibilityService: WidgetVisibilityService, protected visibilityService: WidgetVisibilityService,
@@ -97,21 +94,22 @@ export class FormComponent extends FormBaseComponent implements OnInit, OnDestro
} }
ngOnInit() { ngOnInit() {
this.subscriptions.push( this.formService.formContentClicked
this.formService.formContentClicked.subscribe((content: ContentLinkModel) => { .pipe(takeUntil(this.onDestroy$))
this.formContentClicked.emit(content); .subscribe(content => this.formContentClicked.emit(content));
}),
this.formService.validateForm.subscribe((validateFormEvent: ValidateFormEvent) => { this.formService.validateForm
.pipe(takeUntil(this.onDestroy$))
.subscribe(validateFormEvent => {
if (validateFormEvent.errorsField.length > 0) { if (validateFormEvent.errorsField.length > 0) {
this.formError.next(validateFormEvent.errorsField); this.formError.next(validateFormEvent.errorsField);
} }
}) });
);
} }
ngOnDestroy() { ngOnDestroy() {
this.subscriptions.forEach((subscription) => subscription.unsubscribe()); this.onDestroy$.next(true);
this.subscriptions = []; this.onDestroy$.complete();
} }
ngOnChanges(changes: SimpleChanges) { ngOnChanges(changes: SimpleChanges) {
@@ -187,8 +185,8 @@ export class FormComponent extends FormBaseComponent implements OnInit, OnDestro
} }
getFormByTaskId(taskId: string): Promise<FormModel> { getFormByTaskId(taskId: string): Promise<FormModel> {
return new Promise<FormModel>((resolve, reject) => { return new Promise<FormModel>(resolve => {
this.findProcessVariablesByTaskId(taskId).subscribe((processVariables) => { this.findProcessVariablesByTaskId(taskId).subscribe(() => {
this.formService this.formService
.getTaskForm(taskId) .getTaskForm(taskId)
.subscribe( .subscribe(

View File

@@ -29,7 +29,7 @@ import {
OnDestroy OnDestroy
} from '@angular/core'; } from '@angular/core';
import { FormComponent } from './form.component'; import { FormComponent } from './form.component';
import { ContentLinkModel, FormService, WidgetVisibilityService, FormRenderingService, ValidateFormEvent, FormOutcomeModel } from '@alfresco/adf-core'; import { ContentLinkModel, FormService, WidgetVisibilityService, FormRenderingService, FormOutcomeModel } from '@alfresco/adf-core';
@Component({ @Component({
selector: 'adf-start-form', selector: 'adf-start-form',
@@ -77,24 +77,6 @@ export class StartFormComponent extends FormComponent implements OnChanges, OnIn
this.showTitle = false; this.showTitle = false;
} }
ngOnInit() {
this.subscriptions.push(
this.formService.formContentClicked.subscribe((content) => {
this.formContentClicked.emit(content);
}),
this.formService.validateForm.subscribe((validateFormEvent: ValidateFormEvent) => {
if (validateFormEvent.errorsField.length > 0) {
this.formError.next(validateFormEvent.errorsField);
}
})
);
}
ngOnDestroy() {
this.subscriptions.forEach((subscription) => subscription.unsubscribe());
this.subscriptions = [];
}
ngOnChanges(changes: SimpleChanges) { ngOnChanges(changes: SimpleChanges) {
const processDefinitionId = changes['processDefinitionId']; const processDefinitionId = changes['processDefinitionId'];
if (processDefinitionId && processDefinitionId.currentValue) { if (processDefinitionId && processDefinitionId.currentValue) {

View File

@@ -16,16 +16,16 @@
*/ */
import { CommentModel, CommentProcessService } from '@alfresco/adf-core'; import { CommentModel, CommentProcessService } from '@alfresco/adf-core';
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core'; import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, OnDestroy } from '@angular/core';
import { Observable, Observer } from 'rxjs'; import { Observable, Observer, Subject } from 'rxjs';
import { share } from 'rxjs/operators'; import { share, takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'adf-process-instance-comments', selector: 'adf-process-instance-comments',
templateUrl: './process-comments.component.html', templateUrl: './process-comments.component.html',
styleUrls: ['./process-comments.component.scss'] styleUrls: ['./process-comments.component.scss']
}) })
export class ProcessCommentsComponent implements OnChanges { export class ProcessCommentsComponent implements OnChanges, OnDestroy {
/** (**required**) The numeric ID of the process instance to display comments for. */ /** (**required**) The numeric ID of the process instance to display comments for. */
@Input() @Input()
@@ -44,16 +44,22 @@ export class ProcessCommentsComponent implements OnChanges {
private commentObserver: Observer<CommentModel>; private commentObserver: Observer<CommentModel>;
comment$: Observable<CommentModel>; comment$: Observable<CommentModel>;
private onDestroy$ = new Subject<boolean>();
message: string; message: string;
beingAdded: boolean = false; beingAdded: boolean = false;
constructor(private commentProcessService: CommentProcessService) { constructor(private commentProcessService: CommentProcessService) {
this.comment$ = new Observable<CommentModel>((observer) => this.commentObserver = observer) this.comment$ = new Observable<CommentModel>(observer => this.commentObserver = observer).pipe(share());
.pipe(share()); this.comment$
this.comment$.subscribe((comment: CommentModel) => { .pipe(takeUntil(this.onDestroy$))
this.comments.push(comment); .subscribe(comment => this.comments.push(comment));
}); }
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
} }
ngOnChanges(changes: SimpleChanges) { ngOnChanges(changes: SimpleChanges) {

View File

@@ -17,20 +17,20 @@
import { LogService } from '@alfresco/adf-core'; import { LogService } from '@alfresco/adf-core';
import { DatePipe } from '@angular/common'; import { DatePipe } from '@angular/common';
import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, ViewChild } from '@angular/core'; import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, ViewChild, OnDestroy } from '@angular/core';
import { MatDialog } from '@angular/material'; import { MatDialog } from '@angular/material';
import { Observable, Observer } from 'rxjs'; import { Observable, Observer, Subject } from 'rxjs';
import { TaskDetailsEvent, TaskDetailsModel } from '../../task-list'; import { TaskDetailsEvent, TaskDetailsModel } from '../../task-list';
import { ProcessInstance } from '../models/process-instance.model'; import { ProcessInstance } from '../models/process-instance.model';
import { ProcessService } from './../services/process.service'; import { ProcessService } from './../services/process.service';
import { share } from 'rxjs/operators'; import { share, takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'adf-process-instance-tasks', selector: 'adf-process-instance-tasks',
templateUrl: './process-instance-tasks.component.html', templateUrl: './process-instance-tasks.component.html',
styleUrls: ['./process-instance-tasks.component.css'] styleUrls: ['./process-instance-tasks.component.css']
}) })
export class ProcessInstanceTasksComponent implements OnInit, OnChanges { export class ProcessInstanceTasksComponent implements OnInit, OnChanges, OnDestroy {
/** (**required**) The ID of the process instance to display tasks for. */ /** (**required**) The ID of the process instance to display tasks for. */
@Input() @Input()
@@ -51,10 +51,10 @@ export class ProcessInstanceTasksComponent implements OnInit, OnChanges {
private taskObserver: Observer<TaskDetailsModel>; private taskObserver: Observer<TaskDetailsModel>;
private completedTaskObserver: Observer<TaskDetailsModel>; private completedTaskObserver: Observer<TaskDetailsModel>;
private onDestroy$ = new Subject<boolean>();
task$: Observable<TaskDetailsModel>; task$: Observable<TaskDetailsModel>;
completedTask$: Observable<TaskDetailsModel>; completedTask$: Observable<TaskDetailsModel>;
message: string; message: string;
processId: string; processId: string;
@@ -78,12 +78,18 @@ export class ProcessInstanceTasksComponent implements OnInit, OnChanges {
} }
ngOnInit() { ngOnInit() {
this.task$.subscribe((task: TaskDetailsModel) => { this.task$
this.activeTasks.push(task); .pipe(takeUntil(this.onDestroy$))
}); .subscribe(task => this.activeTasks.push(task));
this.completedTask$.subscribe((task: TaskDetailsModel) => {
this.completedTasks.push(task); this.completedTask$
}); .pipe(takeUntil(this.onDestroy$))
.subscribe(task => this.completedTasks.push(task));
}
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
} }
ngOnChanges(changes: SimpleChanges) { ngOnChanges(changes: SimpleChanges) {

View File

@@ -17,7 +17,7 @@
import { import {
Component, EventEmitter, Input, OnChanges, OnInit, Component, EventEmitter, Input, OnChanges, OnInit,
Output, SimpleChanges, ViewChild, ViewEncapsulation Output, SimpleChanges, ViewChild, ViewEncapsulation, OnDestroy
} from '@angular/core'; } from '@angular/core';
import { import {
ActivitiContentService, AppConfigService, AppConfigValues, ActivitiContentService, AppConfigService, AppConfigValues,
@@ -28,8 +28,8 @@ import { ProcessDefinitionRepresentation } from './../models/process-definition.
import { ProcessInstance } from './../models/process-instance.model'; import { ProcessInstance } from './../models/process-instance.model';
import { ProcessService } from './../services/process.service'; import { ProcessService } from './../services/process.service';
import { FormControl, Validators, AbstractControl } from '@angular/forms'; import { FormControl, Validators, AbstractControl } from '@angular/forms';
import { Observable } from 'rxjs'; import { Observable, Subject } from 'rxjs';
import { map } from 'rxjs/operators'; import { map, takeUntil } from 'rxjs/operators';
import { MatAutocompleteTrigger } from '@angular/material'; import { MatAutocompleteTrigger } from '@angular/material';
import { StartFormComponent } from '../../form'; import { StartFormComponent } from '../../form';
@@ -39,7 +39,7 @@ import { StartFormComponent } from '../../form';
styleUrls: ['./start-process.component.scss'], styleUrls: ['./start-process.component.scss'],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class StartProcessInstanceComponent implements OnChanges, OnInit { export class StartProcessInstanceComponent implements OnChanges, OnInit, OnDestroy {
MAX_LENGTH: number = 255; MAX_LENGTH: number = 255;
@@ -101,6 +101,8 @@ export class StartProcessInstanceComponent implements OnChanges, OnInit {
filteredProcesses: Observable<ProcessDefinitionRepresentation[]>; filteredProcesses: Observable<ProcessDefinitionRepresentation[]>;
maxProcessNameLength: number = this.MAX_LENGTH; maxProcessNameLength: number = this.MAX_LENGTH;
private onDestroy$ = new Subject<boolean>();
constructor(private activitiProcess: ProcessService, constructor(private activitiProcess: ProcessService,
private activitiContentService: ActivitiContentService, private activitiContentService: ActivitiContentService,
private appConfig: AppConfigService) { private appConfig: AppConfigService) {
@@ -112,13 +114,22 @@ export class StartProcessInstanceComponent implements OnChanges, OnInit {
this.loadStartProcess(); this.loadStartProcess();
this.processNameInput.valueChanges.subscribe((name) => this.name = name); this.processNameInput.valueChanges
.pipe(takeUntil(this.onDestroy$))
.subscribe(name => this.name = name);
this.filteredProcesses = this.processDefinitionInput.valueChanges this.filteredProcesses = this.processDefinitionInput.valueChanges
.pipe( .pipe(
map((value) => this._filter(value)) map((value) => this._filter(value)),
takeUntil(this.onDestroy$)
); );
} }
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
ngOnChanges(changes: SimpleChanges) { ngOnChanges(changes: SimpleChanges) {
if (changes['values'] && changes['values'].currentValue) { if (changes['values'] && changes['values'].currentValue) {
this.moveNodeFromCStoPS(); this.moveNodeFromCStoPS();

View File

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

View File

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

View File

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

View File

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

View File

@@ -29,7 +29,7 @@
"lint-lib": "./node_modules/.bin/tslint -p ./lib/tsconfig.json -c ./lib/tslint.json", "lint-lib": "./node_modules/.bin/tslint -p ./lib/tsconfig.json -c ./lib/tslint.json",
"lint-e2e": "tsc -p ./e2e/tsconfig.e2e.json && ./node_modules/.bin/tslint -p ./e2e/tsconfig.e2e.json -c ./tslint.json", "lint-e2e": "tsc -p ./e2e/tsconfig.e2e.json && ./node_modules/.bin/tslint -p ./e2e/tsconfig.e2e.json -c ./tslint.json",
"validate-config": "ajv validate -s ./lib/core/app-config/schema.json -d ./demo-shell/src/app.config.json --errors=text --verbose", "validate-config": "ajv validate -s ./lib/core/app-config/schema.json -d ./demo-shell/src/app.config.json --errors=text --verbose",
"spellcheck": "cspell 'demo-shell/{src,e2e}/**/*.ts' 'e2e/**/*.ts' 'lib/{content-services,core,extensions,insights,process-services}/**/*.ts'", "spellcheck": "cspell 'demo-shell/{src,e2e}/**/*.ts' 'e2e/**/*.ts' 'lib/{content-services,core,extensions,insights,process-services,process-services-cloud}/**/*.ts'",
"stylelint": "stylelint ./**/*.scss --config stylelint-config.json", "stylelint": "stylelint ./**/*.scss --config stylelint-config.json",
"04": "echo -------------------------------------------- Demo Shell -----------------------------------------------", "04": "echo -------------------------------------------- Demo Shell -----------------------------------------------",
"04s": "", "04s": "",

View File

@@ -175,7 +175,6 @@
"format": "PascalCase" "format": "PascalCase"
} }
], ],
"arrow-parens": true,
"no-input-prefix": true, "no-input-prefix": true,
"ordered-imports": false, "ordered-imports": false,
"template-conditional-complexity": [ "template-conditional-complexity": [