From eba478e1bf20f85a6d4ff28a3df1183b0e97bf85 Mon Sep 17 00:00:00 2001 From: David Klingenberg Date: Thu, 7 Sep 2017 11:53:47 +0200 Subject: [PATCH] Use takeWhile to cancel Observables --- .../analysis-context-form.component.ts | 25 ++++++-------- .../custom-rule-selection.component.ts | 9 +++-- .../src/app/components/app.component.ts | 14 ++++++-- .../add-rules-path-modal.component.ts | 33 ++++++++----------- .../configuration/configuration.component.ts | 19 ++++++----- .../executions/all-executions.component.ts | 4 ++- .../executions/execution-detail.component.ts | 10 ++++-- .../executions/executions-layout.component.ts | 15 +++++---- .../executions/executions-list.component.ts | 10 +++--- .../project-executions.component.ts | 8 +++-- .../rule-provider-executions.component.ts | 11 ++++--- .../webapp/src/app/misc/about.component.ts | 8 +++-- .../migration-project-form.component.ts | 14 +++----- .../app/project/project-layout.component.ts | 9 ++--- .../src/app/project/project-list.component.ts | 21 ++++++------ .../application-list.component.ts | 12 ++++--- .../application-queue-list.component.ts | 10 +++--- .../edit-application-form.component.ts | 6 ++-- .../register-application-form.component.ts | 20 ++++++----- .../application-details.component.ts | 8 ++--- .../application-index.component.ts | 12 +++---- .../dependencies-report.component.ts | 9 ++--- .../execution-application-list.component.ts | 8 ++--- .../reports/filter/report-filter.component.ts | 22 ++++++------- .../hardcoded-ip/hardcoded-ip.component.ts | 6 ++-- .../migration-issues-table.component.ts | 20 ++++++----- .../migration-issues.component.ts | 6 ++-- .../reports/source/source-report.component.ts | 16 ++++----- .../hibernate/hibernate-report.component.ts | 12 +++---- .../src/app/shared/AbstractComponent.ts | 4 +++ .../webapp/src/app/shared/form.component.ts | 4 ++- 31 files changed, 206 insertions(+), 179 deletions(-) diff --git a/ui/src/main/webapp/src/app/analysis-context/analysis-context-form.component.ts b/ui/src/main/webapp/src/app/analysis-context/analysis-context-form.component.ts index e0084027f..7289f2d92 100644 --- a/ui/src/main/webapp/src/app/analysis-context/analysis-context-form.component.ts +++ b/ui/src/main/webapp/src/app/analysis-context/analysis-context-form.component.ts @@ -28,8 +28,7 @@ import {ConfirmationModalComponent} from "../shared/dialog/confirmation-modal.co templateUrl: './analysis-context-form.component.html', styleUrls: ['analysis-context-form.component.scss'] }) -export class AnalysisContextFormComponent extends FormComponent - implements OnInit, OnDestroy, IsDirty +export class AnalysisContextFormComponent extends FormComponent implements OnInit, IsDirty { @ViewChild(NgForm) private analysisContextForm: NgForm; @@ -131,17 +130,17 @@ export class AnalysisContextFormComponent extends FormComponent this.initializeAnalysisContext(); this.dialog = this._dialogService.getConfirmationDialog(); - this.dialogSubscription = this.dialog.confirmed.subscribe(() => this.saveConfiguration()); + this.dialogSubscription = this.dialog.confirmed.takeUntil(this.destroy).subscribe(() => this.saveConfiguration()); } ngOnInit() { this.saveInProgress = false; - this._configurationOptionsService.getAll().subscribe((options: ConfigurationOption[]) => { + this._configurationOptionsService.getAll().takeUntil(this.destroy).subscribe((options: ConfigurationOption[]) => { this.configurationOptions = options; }); - this.routerSubscription = this._router.events.filter(event => event instanceof NavigationEnd).subscribe(_ => { + this._router.events.filter(event => event instanceof NavigationEnd).takeUntil(this.destroy).subscribe(_ => { let flatRouteData = this._routeFlattener.getFlattenedRouteData(this._activatedRoute.snapshot); this.flatRouteData = flatRouteData; @@ -149,17 +148,17 @@ export class AnalysisContextFormComponent extends FormComponent let project = flatRouteData.data['project']; // Load the apps of this project. - this._appService.getApplicationsByProjectID(project.id).subscribe(apps => { + this._appService.getApplicationsByProjectID(project.id).takeUntil(this.destroy).subscribe(apps => { this.availableApps = apps; // Reload the App from the service to ensure fresh data - this._migrationProjectService.get(project.id).subscribe(loadedProject => { + this._migrationProjectService.get(project.id).takeUntil(this.destroy).subscribe(loadedProject => { this.project = loadedProject; if (project.defaultAnalysisContextId == null) { this.initializeAnalysisContext(); this.analysisContext.applications = apps.slice(); } else { - this._analysisContextService.get(project.defaultAnalysisContextId) + this._analysisContextService.get(project.defaultAnalysisContextId).takeUntil(this.destroy) .subscribe(context => { this.analysisContext = context; if (this.analysisContext.migrationPath == null) @@ -181,11 +180,6 @@ export class AnalysisContextFormComponent extends FormComponent } - ngOnDestroy(): void { - this.routerSubscription.unsubscribe(); - this.dialogSubscription.unsubscribe(); - } - // Apps selection checkboxes static getDefaultAnalysisContext() { let analysisContext = {}; @@ -254,7 +248,7 @@ export class AnalysisContextFormComponent extends FormComponent }); */ - forkJoin(registeredPackagesObservables).subscribe((packageMetadataArray: PackageMetadata[]) => { + forkJoin(registeredPackagesObservables).takeUntil(this.destroy).subscribe((packageMetadataArray: PackageMetadata[]) => { let arrayOfRoots = [].concat(...packageMetadataArray.map((singlePackageMetadata) => singlePackageMetadata.packageTree)); let mergedRoots = this._packageRegistryService.mergePackageRoots(arrayOfRoots); mergedRoots.forEach(singleRoot => this._packageRegistryService.putHierarchy(singleRoot)); @@ -322,7 +316,7 @@ export class AnalysisContextFormComponent extends FormComponent this.saveInProgress = true; - this._analysisContextService.saveAsDefault(this.analysisContext, this.project).subscribe( + this._analysisContextService.saveAsDefault(this.analysisContext, this.project).takeUntil(this.destroy).subscribe( updatedContext => { this._dirty = false; this.onSuccess(updatedContext); @@ -338,6 +332,7 @@ export class AnalysisContextFormComponent extends FormComponent if (this.action === Action.SaveAndRun) { this._windupExecutionService.execute(analysisContext, this.project) + .takeUntil(this.destroy) .subscribe(execution => { this.saveInProgress = false; this._router.navigate([`/projects/${this.project.id}`]); diff --git a/ui/src/main/webapp/src/app/analysis-context/custom-rule-selection.component.ts b/ui/src/main/webapp/src/app/analysis-context/custom-rule-selection.component.ts index 2eb3dc1fe..ea6e6a644 100644 --- a/ui/src/main/webapp/src/app/analysis-context/custom-rule-selection.component.ts +++ b/ui/src/main/webapp/src/app/analysis-context/custom-rule-selection.component.ts @@ -3,13 +3,14 @@ import {Component, Input, OnInit, Output, EventEmitter} from '@angular/core'; import {RulesPath} from "../generated/windup-services"; import {ConfigurationService} from "../configuration/configuration.service"; +import {AbstractComponent} from "../shared/AbstractComponent"; @Component({ selector: 'wu-custom-rule-selection', templateUrl: './custom-rule-selection.component.html' }) -export class CustomRuleSelectionComponent implements OnInit { +export class CustomRuleSelectionComponent extends AbstractComponent implements OnInit { private _selectedRulePaths: RulesPath[]; @Output() @@ -43,10 +44,12 @@ export class CustomRuleSelectionComponent implements OnInit { rulesPaths: RulesPath[] = []; - constructor(private _configurationService: ConfigurationService) { } + constructor(private _configurationService: ConfigurationService) { + super(); + } ngOnInit() { - this._configurationService.getCustomRulesetPaths().subscribe( + this._configurationService.getCustomRulesetPaths().takeUntil(this.destroy).subscribe( rulesPaths => { this.rulesPaths = rulesPaths; }, diff --git a/ui/src/main/webapp/src/app/components/app.component.ts b/ui/src/main/webapp/src/app/components/app.component.ts index efb3f4a40..7543e5ace 100644 --- a/ui/src/main/webapp/src/app/components/app.component.ts +++ b/ui/src/main/webapp/src/app/components/app.component.ts @@ -1,18 +1,21 @@ -import {AfterViewInit, Component, ViewChild} from "@angular/core"; +import {AfterViewInit, Component, OnDestroy, ViewChild} from "@angular/core"; import {Router, NavigationEnd, ActivatedRouteSnapshot, ActivatedRoute} from "@angular/router"; import {RouteHistoryService} from "../core/routing/route-history.service"; import {RouteFlattenerService} from "../core/routing/route-flattener.service"; import {ConfirmationModalComponent} from "../shared/dialog/confirmation-modal.component"; import {DialogService} from "../shared/dialog/dialog.service"; +import {Subscription} from "rxjs/Subscription"; @Component({ selector: 'windup-app', templateUrl: './app.component.html' }) -export class AppComponent implements AfterViewInit { +export class AppComponent implements AfterViewInit, OnDestroy { @ViewChild('reusableModalDialog') confirmationDialog: ConfirmationModalComponent; + routerSubscription: Subscription; + /* * This is for Augury Chrome extension to display router tree * See https://github.com/rangle/augury/issues/715 @@ -26,7 +29,7 @@ export class AppComponent implements AfterViewInit { private activatedRoute: ActivatedRoute, private dialogService: DialogService ) { - router.events + this.routerSubscription = router.events .filter(event => event instanceof NavigationEnd) .subscribe((event: NavigationEnd) => { this.routeHistoryService.addNavigationEvent(event); @@ -37,4 +40,9 @@ export class AppComponent implements AfterViewInit { ngAfterViewInit(): void { this.dialogService.setConfirmationDialog(this.confirmationDialog); } + + + ngOnDestroy(): void { + this.routerSubscription.unsubscribe(); + } } diff --git a/ui/src/main/webapp/src/app/configuration/add-rules-path-modal.component.ts b/ui/src/main/webapp/src/app/configuration/add-rules-path-modal.component.ts index 65fdbe25e..3f3668b0e 100644 --- a/ui/src/main/webapp/src/app/configuration/add-rules-path-modal.component.ts +++ b/ui/src/main/webapp/src/app/configuration/add-rules-path-modal.component.ts @@ -56,8 +56,6 @@ export class AddRulesPathModalComponent extends FormComponent implements OnInit, return paths[paths.length - 1]; }; - private subscriptions: Subscription[] = []; - constructor( private _formBuilder: FormBuilder, private _fileService: FileService, @@ -68,17 +66,17 @@ export class AddRulesPathModalComponent extends FormComponent implements OnInit, super(); this.multipartUploader = _ruleService.getMultipartUploader(); - this.subscriptions.push(this.multipartUploader.observables.onSuccessItem.subscribe((result) => { + this.multipartUploader.observables.onSuccessItem.takeUntil(this.destroy).subscribe((result) => { this.countUploadedRules++; const rulesPath = JSON.parse(result.response); this.uploadedRules = [ ...this.uploadedRules, rulesPath ]; - })); + }); - this.subscriptions.push(this.multipartUploader.observables.onErrorItem.subscribe((result) => { + this.multipartUploader.observables.onErrorItem.takeUntil(this.destroy).subscribe((result) => { this.handleError(utils.parseServerResponse(result.response)); - })); - this.subscriptions.push(this.multipartUploader.observables.onAfterAddingFile.subscribe(() => this.uploadRule())); - this.subscriptions.push(this.multipartUploader.observables.onWhenAddingFileFailed.subscribe(result => { + }); + this.multipartUploader.observables.onAfterAddingFile.takeUntil(this.destroy).subscribe(() => this.uploadRule()); + this.multipartUploader.observables.onWhenAddingFileFailed.takeUntil(this.destroy).subscribe(result => { const item = result.item; const filter = result.filter; @@ -109,7 +107,7 @@ export class AddRulesPathModalComponent extends FormComponent implements OnInit, } } this.handleError(msg); - })); + }); let suffixes = ['.xml']; this.multipartUploader.options.filters.push({ @@ -128,11 +126,6 @@ export class AddRulesPathModalComponent extends FormComponent implements OnInit, }); } - ngOnDestroy(): void { - this.subscriptions.forEach(subscription => subscription.unsubscribe()); - this.subscriptions = []; - } - show(): void { this.countUploadedRules = 0; this.uploadedRules = []; @@ -153,7 +146,7 @@ export class AddRulesPathModalComponent extends FormComponent implements OnInit, if (this.mode === 'PATH') { this.addPath(); } else { - this._configurationService.get().subscribe(configuration => { + this._configurationService.get().takeUntil(this.destroy).subscribe(configuration => { this.configurationSaved.emit({ configuration }); this.hide(); }); @@ -166,11 +159,11 @@ export class AddRulesPathModalComponent extends FormComponent implements OnInit, let newPath = {}; newPath.path = this.inputPath; newPath.rulesPathType = "USER_PROVIDED"; - newPath.scanRecursively = this.scanRecursively; + (newPath).scanRecursively = this.scanRecursively; newConfiguration.rulesPaths.push(newPath); - this._configurationService.save(newConfiguration).subscribe( + this._configurationService.save(newConfiguration).takeUntil(this.destroy).subscribe( configuration => { this.configuration = configuration; this.configurationSaved.emit({ @@ -188,7 +181,7 @@ export class AddRulesPathModalComponent extends FormComponent implements OnInit, return; } - this._ruleService.uploadRules().subscribe( + this._ruleService.uploadRules().takeUntil(this.destroy).subscribe( () => {}, error => this.handleError(error) ); @@ -204,11 +197,11 @@ export class AddRulesPathModalComponent extends FormComponent implements OnInit, dialog.body = `Are you sure you want to remove rule provider '${rulesPath.path}'?`; dialog.data = rulesPath; dialog.show(); - this.dialogSubscription = dialog.confirmed.subscribe(rulePath => this.removeRulesPath(rulePath)); + this.dialogSubscription = dialog.confirmed.takeUntil(this.destroy).subscribe(rulePath => this.removeRulesPath(rulePath)); } removeRulesPath(rulesPath: RulesPath) { - this._ruleService.deleteRule(rulesPath).subscribe(() => { + this._ruleService.deleteRule(rulesPath).takeUntil(this.destroy).subscribe(() => { this.uploadedRules = this.uploadedRules.filter(item => item.id !== rulesPath.id); }); } diff --git a/ui/src/main/webapp/src/app/configuration/configuration.component.ts b/ui/src/main/webapp/src/app/configuration/configuration.component.ts index d06a225dc..1e13f03d6 100644 --- a/ui/src/main/webapp/src/app/configuration/configuration.component.ts +++ b/ui/src/main/webapp/src/app/configuration/configuration.component.ts @@ -13,6 +13,7 @@ import Arrays = utils.Arrays; import {FilterConfiguration} from "../shared/toolbar/toolbar.component"; import {getAvailableFilters} from "./technology-filter"; import {DomSanitizer} from '@angular/platform-browser'; +import {AbstractComponent} from "../shared/AbstractComponent"; declare function prettyPrint(); @@ -20,7 +21,7 @@ declare function prettyPrint(); templateUrl: './configuration.component.html', styleUrls: ['./configuration.component.scss'] }) -export class ConfigurationComponent implements OnInit, AfterViewInit { +export class ConfigurationComponent extends AbstractComponent implements OnInit, AfterViewInit { forceReloadAttempted: boolean = false; rescanInProgress: boolean = false; @@ -68,18 +69,18 @@ export class ConfigurationComponent implements OnInit, AfterViewInit { private _element: ElementRef, private _sanitizer: DomSanitizer ) { - + super(); } ngOnInit(): void { - this._activatedRoute.data.subscribe((data: {configuration: Configuration}) => { + this._activatedRoute.data.takeUntil(this.destroy).subscribe((data: {configuration: Configuration}) => { this.configuration = data.configuration; this.loadProviders(); }); } ngAfterViewInit(): void { - this.removeRulesConfirmationModal.confirmed.subscribe(rulePath => this.removeRulesPath(rulePath)); + this.removeRulesConfirmationModal.confirmed.takeUntil(this.destroy).subscribe(rulePath => this.removeRulesPath(rulePath)); } loadProviders() { @@ -92,7 +93,7 @@ export class ConfigurationComponent implements OnInit, AfterViewInit { forceReload() { this.forceReloadAttempted = true; this.rescanInProgress = true; - this._configurationService.reloadConfigration().subscribe(() => { + this._configurationService.reloadConfigration().takeUntil(this.destroy).subscribe(() => { this.rescanInProgress = false; this.loadRuleProviderDetails() }); @@ -100,7 +101,7 @@ export class ConfigurationComponent implements OnInit, AfterViewInit { loadRuleProviderDetails() { this.configuration.rulesPaths.forEach((rulesPath) => { - this._ruleService.getByRulesPath(rulesPath).subscribe( + this._ruleService.getByRulesPath(rulesPath).takeUntil(this.destroy).subscribe( (ruleProviders:RuleProviderEntity[]) => { this.ruleProvidersByPath.set(rulesPath, ruleProviders); if (!this.forceReloadAttempted && rulesPath.rulesPathType == "SYSTEM_PROVIDED" && ruleProviders.length == 0) // needs to be loaded @@ -178,7 +179,7 @@ export class ConfigurationComponent implements OnInit, AfterViewInit { } removeRulesPath(rulesPath: RulesPath) { - this._ruleService.deleteRule(rulesPath).subscribe(() => { + this._ruleService.deleteRule(rulesPath).takeUntil(this.destroy).subscribe(() => { this._notificationService.success('Rule was deleted'); this._configurationService.get().subscribe(newConfig => { @@ -189,7 +190,7 @@ export class ConfigurationComponent implements OnInit, AfterViewInit { } reloadConfiguration() { - this._configurationService.reloadConfigration().subscribe( + this._configurationService.reloadConfigration().takeUntil(this.destroy).subscribe( configuration => { this.configuration = configuration; this.loadProviders(); @@ -202,7 +203,7 @@ export class ConfigurationComponent implements OnInit, AfterViewInit { confirmRemoveRules(rulesPath: RulesPath) { console.log("Checking rules path " + rulesPath.path); - this._ruleService.checkIfUsedRulesPath(rulesPath).subscribe( + this._ruleService.checkIfUsedRulesPath(rulesPath).takeUntil(this.destroy).subscribe( response => { if (response.valueOf()) { diff --git a/ui/src/main/webapp/src/app/executions/all-executions.component.ts b/ui/src/main/webapp/src/app/executions/all-executions.component.ts index 374adbbc5..b8d4a6b46 100644 --- a/ui/src/main/webapp/src/app/executions/all-executions.component.ts +++ b/ui/src/main/webapp/src/app/executions/all-executions.component.ts @@ -29,18 +29,20 @@ export class AllExecutionsComponent extends ExecutionsMonitoringComponent implem this.addSubscription( this._eventBus.onEvent .filter(event => event.isTypeOf(ExecutionEvent)) + .takeUntil(this.destroy) .subscribe((event: ExecutionEvent) => this.onExecutionEvent(event)) ); this.addSubscription( this._eventBus.onEvent .filter(event => event.isTypeOf(NewExecutionStartedEvent)) + .takeUntil(this.destroy) .subscribe((event: NewExecutionStartedEvent) => { this.loadExecutions(); }) ); } protected loadExecutions() { - this._windupService.getAllExecutions().subscribe( + this._windupService.getAllExecutions().takeUntil(this.destroy).subscribe( executions => { this.executions = executions; super.loadActiveExecutions(executions); diff --git a/ui/src/main/webapp/src/app/executions/execution-detail.component.ts b/ui/src/main/webapp/src/app/executions/execution-detail.component.ts index 0ca73e30f..120830aa9 100644 --- a/ui/src/main/webapp/src/app/executions/execution-detail.component.ts +++ b/ui/src/main/webapp/src/app/executions/execution-detail.component.ts @@ -37,12 +37,13 @@ export class ExecutionDetailComponent extends RoutedComponent implements OnInit } ngOnInit(): void { - this.subscriptions.push(this.flatRouteLoaded.subscribe(flatRouteData => { + this.flatRouteLoaded.takeUntil(this.destroy).subscribe(flatRouteData => { let executionId = +flatRouteData.params.executionId; this._eventBus.onEvent .filter(event => event.isTypeOf(ExecutionEvent)) .filter((event: ExecutionEvent) => event.execution.id === executionId) + .takeUntil(this.destroy) .subscribe((event: ExecutionEvent) => { this.execution = event.execution; this.loadLogData(); @@ -52,11 +53,12 @@ export class ExecutionDetailComponent extends RoutedComponent implements OnInit this.execution = execution; this.loadLogData(); this._ruleProviderExecutionsService.getPhases(executionId) + .takeUntil(this.destroy) .subscribe(phases => { this.phases = phases; }); }); - })); + }); } get loglines(): Observable { @@ -72,7 +74,9 @@ export class ExecutionDetailComponent extends RoutedComponent implements OnInit } private loadLogData() { - this._windupService.getLogData(this.execution.id).subscribe(logLines => this.logLines = logLines); + this._windupService.getLogData(this.execution.id) + .takeUntil(this.destroy) + .subscribe(logLines => this.logLines = logLines); } getAnalyzedApplications(execution : WindupExecution) : RegisteredApplication[] { diff --git a/ui/src/main/webapp/src/app/executions/executions-layout.component.ts b/ui/src/main/webapp/src/app/executions/executions-layout.component.ts index d8496768d..6cbc55ab8 100644 --- a/ui/src/main/webapp/src/app/executions/executions-layout.component.ts +++ b/ui/src/main/webapp/src/app/executions/executions-layout.component.ts @@ -41,20 +41,21 @@ export class ExecutionsLayoutComponent extends ProjectLayoutComponent implements this.loadProjects(); let executionId = +flatRoute.params.executionId; - this.addSubscription(this._eventBus.onEvent + this._eventBus.onEvent .filter(event => event.isTypeOf(ExecutionEvent)) .filter((event: ExecutionEvent) => event.execution.id === executionId) + .takeUntil(this.destroy) .subscribe((event: ExecutionEvent) => { this.execution = event.execution; this.createContextMenuItems(); - })); + }); this.loadSelectedExecution(executionId); } protected loadSelectedExecution(executionId: number) { let observable = this._windupService.getExecution(executionId); - observable.subscribe(execution => { + observable.takeUntil(this.destroy).subscribe(execution => { this.execution = execution; this.createContextMenuItems(); }); @@ -63,9 +64,11 @@ export class ExecutionsLayoutComponent extends ProjectLayoutComponent implements } protected loadProjectExecutions() { - this._windupService.getProjectExecutions(this.project.id).subscribe((executions: WindupExecution[]) => { - this.allExecutions = executions.sort((a,b) => (a.id||0) - (b.id||0)); - }); + this._windupService.getProjectExecutions(this.project.id) + .takeUntil(this.destroy) + .subscribe((executions: WindupExecution[]) => { + this.allExecutions = executions.sort((a,b) => (a.id||0) - (b.id||0)); + }); } public getExecutionLabel = (execution: WindupExecution): string => { diff --git a/ui/src/main/webapp/src/app/executions/executions-list.component.ts b/ui/src/main/webapp/src/app/executions/executions-list.component.ts index b9149eee2..8174bbe95 100644 --- a/ui/src/main/webapp/src/app/executions/executions-list.component.ts +++ b/ui/src/main/webapp/src/app/executions/executions-list.component.ts @@ -60,15 +60,15 @@ export class ExecutionsListComponent extends AbstractComponent implements OnInit } ngOnInit(): void { - this._projectService.getAll().subscribe(projects => { + this._projectService.getAll().takeUntil(this.destroy).subscribe(projects => { this.projectsMap.clear(); projects.forEach(project => this.projectsMap.set(project.id, project)); }); - this.cancelExecutionDialog.confirmed.subscribe((execution) => { + this.cancelExecutionDialog.confirmed.takeUntil(this.destroy).subscribe((execution) => { this.doCancelExecution(execution); }); - this.deleteExecutionDialog.confirmed.subscribe((execution) => { + this.deleteExecutionDialog.confirmed.takeUntil(this.destroy).subscribe((execution) => { this.doDeleteExecution(execution); }); @@ -119,7 +119,7 @@ export class ExecutionsListComponent extends AbstractComponent implements OnInit } doCancelExecution(execution: WindupExecution) { - this._windupService.cancelExecution(execution).subscribe( + this._windupService.cancelExecution(execution).takeUntil(this.destroy).subscribe( success => { this._notificationService.success(`Analysis #${execution.id} was cancelled.`); this.reloadRequestEvent.emit(true); @@ -140,7 +140,7 @@ export class ExecutionsListComponent extends AbstractComponent implements OnInit this.deletedExecutions.set(execution.id, execution); this._windupService.deleteExecution(execution).finally(() => { this.deletedExecutions.delete(execution.id); - }).subscribe( + }).takeUntil(this.destroy).subscribe( success => { this._notificationService.success(`Analysis #${execution.id} was deleted.`); this.reloadRequestEvent.emit(true); diff --git a/ui/src/main/webapp/src/app/executions/project-executions.component.ts b/ui/src/main/webapp/src/app/executions/project-executions.component.ts index 8b9fa12a8..1293ecb32 100644 --- a/ui/src/main/webapp/src/app/executions/project-executions.component.ts +++ b/ui/src/main/webapp/src/app/executions/project-executions.component.ts @@ -33,10 +33,11 @@ export class ProjectExecutionsComponent extends ExecutionsMonitoringComponent im } ngOnInit(): void { - this._activatedRoute.parent.data.subscribe((data: {project: MigrationProject}) => { + this._activatedRoute.parent.data.takeUntil(this.destroy).subscribe((data: {project: MigrationProject}) => { this.project = data.project; this._analysisContextService.get(this.project.defaultAnalysisContextId) + .takeUntil(this.destroy) .subscribe(context => { this.analysisContext = context; this.analysisContext.applications = context.applications.filter(function( app: RegisteredApplication ) { @@ -51,13 +52,14 @@ export class ProjectExecutionsComponent extends ExecutionsMonitoringComponent im this.addSubscription(this._eventBus.onEvent .filter(event => event.isTypeOf(ExecutionEvent)) .filter((event: ExecutionEvent) => event.migrationProject.id === this.project.id) + .takeUntil(this.destroy) .subscribe((event: ExecutionEvent) => this.onExecutionEvent(event))); this.doNotRefreshList = false; } refreshExecutionList() { - this._windupService.getProjectExecutions(this.project.id).subscribe(executions => { + this._windupService.getProjectExecutions(this.project.id).takeUntil(this.destroy).subscribe(executions => { this.executions = executions; // If there are cancelled jobs that have not yet had a cancelled date added, then refresh the list @@ -93,7 +95,7 @@ export class ProjectExecutionsComponent extends ExecutionsMonitoringComponent im public startExecution() { if (this.analysisContext && this.project) { - this._windupExecutionService.execute(this.analysisContext, this.project).subscribe( + this._windupExecutionService.execute(this.analysisContext, this.project).takeUntil(this.destroy).subscribe( execution => { this.refreshExecutionList(); console.log('load active executions'); diff --git a/ui/src/main/webapp/src/app/executions/rule-provider-executions/rule-provider-executions.component.ts b/ui/src/main/webapp/src/app/executions/rule-provider-executions/rule-provider-executions.component.ts index f1ccce1bc..007e71b08 100644 --- a/ui/src/main/webapp/src/app/executions/rule-provider-executions/rule-provider-executions.component.ts +++ b/ui/src/main/webapp/src/app/executions/rule-provider-executions/rule-provider-executions.component.ts @@ -2,6 +2,7 @@ import {Component, OnInit, AfterViewChecked, ElementRef} from "@angular/core"; import {ActivatedRoute} from "@angular/router"; import {RuleProviderExecutionsService} from "./rule-provider-executions.service"; import {ExecutionPhaseModel} from "../../generated/tsModels/ExecutionPhaseModel"; +import {AbstractComponent} from "../../shared/AbstractComponent"; @Component({ templateUrl: './rule-provider-executions.component.html', @@ -18,7 +19,7 @@ import {ExecutionPhaseModel} from "../../generated/tsModels/ExecutionPhaseModel" }` ] }) -export class RuleProviderExecutionsComponent implements OnInit, AfterViewChecked { +export class RuleProviderExecutionsComponent extends AbstractComponent implements OnInit, AfterViewChecked { phases: ExecutionPhaseModel[]; protected anchor: string; @@ -27,18 +28,18 @@ export class RuleProviderExecutionsComponent implements OnInit, AfterViewChecked private _activatedRoute: ActivatedRoute, private _element: ElementRef ) { - + super(); } ngOnInit(): void { - this._activatedRoute.parent.params.subscribe((params: {executionId: number}) => { - this._ruleProviderExecutionsService.getPhases(params.executionId) + this._activatedRoute.parent.params.takeUntil(this.destroy).subscribe((params: {executionId: number}) => { + this._ruleProviderExecutionsService.getPhases(params.executionId).takeUntil(this.destroy) .subscribe(phases => { this.phases = phases; }); }); - this._activatedRoute.queryParams.subscribe((queryParams) => { + this._activatedRoute.queryParams.takeUntil(this.destroy).subscribe((queryParams) => { if (queryParams.hasOwnProperty('ruleID')) { this.anchor = queryParams['ruleID']; } diff --git a/ui/src/main/webapp/src/app/misc/about.component.ts b/ui/src/main/webapp/src/app/misc/about.component.ts index e0e0415f9..43565148a 100644 --- a/ui/src/main/webapp/src/app/misc/about.component.ts +++ b/ui/src/main/webapp/src/app/misc/about.component.ts @@ -1,6 +1,7 @@ import {Component, OnInit, AfterViewInit} from "@angular/core"; import {Constants} from "../constants"; import {Http} from "@angular/http"; +import {AbstractComponent} from "../shared/AbstractComponent"; @Component({ templateUrl: './about.component.html', @@ -11,7 +12,7 @@ import {Http} from "@angular/http"; } `] }) -export class AboutPageComponent implements OnInit, AfterViewInit { +export class AboutPageComponent extends AbstractComponent implements OnInit, AfterViewInit { private WINDUP_CORE_VERSION_URL: string = "/windup/coreVersion"; @@ -24,13 +25,14 @@ export class AboutPageComponent implements OnInit, AfterViewInit { contributors: {login: string, html_url: string; avatar_url: string }[] = []; constructor (private _http: Http) { + super(); } ngOnInit(): any { this._http.get(Constants.REST_BASE + this.WINDUP_CORE_VERSION_URL) .map(res => res.json()) - .subscribe(versionAndRevision => - { + .takeUntil(this.destroy) + .subscribe(versionAndRevision => { this.versionWindupCore = versionAndRevision.version; this.scmRevisionWindupCore = versionAndRevision.scmRevision; }); diff --git a/ui/src/main/webapp/src/app/project/migration-project-form.component.ts b/ui/src/main/webapp/src/app/project/migration-project-form.component.ts index 8a0bd3896..2d12301ee 100644 --- a/ui/src/main/webapp/src/app/project/migration-project-form.component.ts +++ b/ui/src/main/webapp/src/app/project/migration-project-form.component.ts @@ -40,7 +40,7 @@ export class MigrationProjectFormComponent extends FormComponent implements OnIn } ngOnInit(): void { - this.routerSubscription = this._router.events.filter(event => event instanceof NavigationEnd).subscribe(_ => { + this._router.events.filter(event => event instanceof NavigationEnd).takeUntil(this.destroy).subscribe(_ => { let flatRouteData = this._routeFlattener.getFlattenedRouteData(this._activatedRoute.snapshot); if (flatRouteData.data['displayName']) this.title = flatRouteData.data['displayName']; @@ -50,20 +50,16 @@ export class MigrationProjectFormComponent extends FormComponent implements OnIn let projectID = flatRouteData.data['project'].id; // Reload it as we always need the latest data (route resolver does not guarantee this) - this._migrationProjectService.get(projectID).subscribe(model => this.model = model); + this._migrationProjectService.get(projectID).takeUntil(this.destroy).subscribe(model => this.model = model); } if(!this.editMode) // Creating a new project. - this._migrationProjectService.deleteProvisionalProjects().subscribe(res => {}); + this._migrationProjectService.deleteProvisionalProjects().takeUntil(this.destroy).subscribe(res => {}); this.isInWizard = flatRouteData.data.hasOwnProperty('wizard') && flatRouteData.data['wizard']; }); } - ngOnDestroy(): void { - this.routerSubscription.unsubscribe(); - } - ngAfterViewInit(): void { this.inputProjectName.first.nativeElement.focus(); } @@ -85,12 +81,12 @@ export class MigrationProjectFormComponent extends FormComponent implements OnIn this.model.description = this.model.description.trim(); if (this.editMode) { - this._migrationProjectService.update(this.model).subscribe( + this._migrationProjectService.update(this.model).takeUntil(this.destroy).subscribe( migrationProject => this.navigateOnSuccess(migrationProject), error => this.handleError( error) ); } else { - this._migrationProjectService.create(this.model).subscribe( + this._migrationProjectService.create(this.model).takeUntil(this.destroy).subscribe( migrationProject => this.navigateOnSuccess(migrationProject), error => this.handleError( error) ); diff --git a/ui/src/main/webapp/src/app/project/project-layout.component.ts b/ui/src/main/webapp/src/app/project/project-layout.component.ts index 00ebcbc7f..7eda5bf3a 100644 --- a/ui/src/main/webapp/src/app/project/project-layout.component.ts +++ b/ui/src/main/webapp/src/app/project/project-layout.component.ts @@ -39,13 +39,14 @@ export class ProjectLayoutComponent extends RoutedComponent implements OnInit, O } ngOnInit(): void { - this.addSubscription(this._eventBus.onEvent.filter(event => event.isTypeOf(UpdateMigrationProjectEvent)) + this._eventBus.onEvent.filter(event => event.isTypeOf(UpdateMigrationProjectEvent)) + .takeUntil(this.destroy) .subscribe((event: MigrationProjectEvent) => { this.project = event.migrationProject; this.createContextMenuItems(); - })); + }); - this.addSubscription(this.flatRouteLoaded.subscribe(flattenedRoute => this.loadDataFromRoute(flattenedRoute))); + this.flatRouteLoaded.takeUntil(this.destroy).subscribe(flattenedRoute => this.loadDataFromRoute(flattenedRoute)); this.loadProjects(); } @@ -56,7 +57,7 @@ export class ProjectLayoutComponent extends RoutedComponent implements OnInit, O } protected loadProjects() { - this._migrationProjectService.getAll().subscribe((projects: MigrationProject[]) => { + this._migrationProjectService.getAll().takeUntil(this.destroy).subscribe((projects: MigrationProject[]) => { this.allProjects = projects.sort((a,b) => a.title.localeCompare(b.title)); }); } diff --git a/ui/src/main/webapp/src/app/project/project-list.component.ts b/ui/src/main/webapp/src/app/project/project-list.component.ts index 0517b583b..12a23cd5a 100644 --- a/ui/src/main/webapp/src/app/project/project-list.component.ts +++ b/ui/src/main/webapp/src/app/project/project-list.component.ts @@ -10,6 +10,7 @@ import {OrderDirection, SortingService} from "../shared/sort/sorting.service"; import {WindupService} from "../services/windup.service"; import {EventBusService} from "../core/events/event-bus.service"; import {DeleteMigrationProjectEvent} from "../core/events/windup-event"; +import {AbstractComponent} from "../shared/AbstractComponent"; @Component({ templateUrl: './project-list.component.html', @@ -20,7 +21,7 @@ import {DeleteMigrationProjectEvent} from "../core/events/windup-event"; SortingService ] }) -export class ProjectListComponent implements OnDestroy, OnInit, AfterViewInit { +export class ProjectListComponent extends AbstractComponent implements OnDestroy, OnInit, AfterViewInit { private _originalProjects: MigrationProject[] = []; loading: boolean = true; @@ -58,11 +59,13 @@ export class ProjectListComponent implements OnDestroy, OnInit, AfterViewInit { private _windupService: WindupService, private _eventBus: EventBusService ) { + super(); this.deletedEventSubscription = this._eventBus.onEvent .filter(event => event.isTypeOf(DeleteMigrationProjectEvent)) + .takeUntil(this.destroy) .subscribe(event => { this.getMigrationProjects(); - }) + }); } ngOnInit(): any { @@ -70,12 +73,8 @@ export class ProjectListComponent implements OnDestroy, OnInit, AfterViewInit { this.getMigrationProjects(); } - ngOnDestroy(): void { - this.deletedEventSubscription.unsubscribe(); - } - ngAfterViewInit(): void { - this.deleteProjectModal.closed.subscribe(() => { + this.deleteProjectModal.closed.takeUntil(this.destroy).subscribe(() => { this.deleteProjectModal.title = ''; this.deleteProjectModal.body = ''; this.deleteProjectModal.confirmPhrase = ''; @@ -83,11 +82,11 @@ export class ProjectListComponent implements OnDestroy, OnInit, AfterViewInit { this.deleteProjectModal.data = null; }); - this.deleteProjectModal.confirmed.subscribe(project => this.doDeleteProject(project)); + this.deleteProjectModal.confirmed.takeUntil(this.destroy).subscribe(project => this.doDeleteProject(project)); } getMigrationProjects() { - return this._migrationProjectService.getAll().subscribe( + return this._migrationProjectService.getAll().takeUntil(this.destroy).subscribe( projects => this.projectsLoaded(projects), error => this._notificationService.error(utils.getErrorMessage(error)) ); @@ -143,7 +142,7 @@ export class ProjectListComponent implements OnDestroy, OnInit, AfterViewInit { } private doDeleteProject(project: MigrationProject) { - this._migrationProjectService.delete(project).subscribe( + this._migrationProjectService.delete(project).takeUntil(this.destroy).subscribe( success => { this._notificationService.success(`Project '${project.title}' was deleted.`); let index = this._originalProjects.indexOf(project); @@ -167,7 +166,7 @@ export class ProjectListComponent implements OnDestroy, OnInit, AfterViewInit { return false; } - this._windupService.getProjectExecutions(project.id).subscribe((executions) => { + this._windupService.getProjectExecutions(project.id).takeUntil(this.destroy).subscribe((executions) => { let inProgressExecution = executions.find((execution) => { return execution.state == "QUEUED" || execution.state == "STARTED"; }); diff --git a/ui/src/main/webapp/src/app/registered-application/application-list.component.ts b/ui/src/main/webapp/src/app/registered-application/application-list.component.ts index ab71aa126..3b52470ca 100644 --- a/ui/src/main/webapp/src/app/registered-application/application-list.component.ts +++ b/ui/src/main/webapp/src/app/registered-application/application-list.component.ts @@ -49,33 +49,36 @@ export class ApplicationListComponent extends ExecutionsMonitoringComponent impl this._eventBus.onEvent .filter(event => event.isTypeOf(ExecutionEvent)) .filter((event: ExecutionEvent) => event.migrationProject.id === this.project.id) + .takeUntil(this.destroy) .subscribe((event: ExecutionEvent) => { this.onExecutionEvent(event); }); this._eventBus.onEvent .filter(event => event.isTypeOf(ApplicationDeletedEvent)) + .takeUntil(this.destroy) .subscribe((event: ApplicationDeletedEvent) => this.onApplicationDeleted(event)); this._eventBus.onEvent .filter(event => event.isTypeOf(UpdateMigrationProjectEvent)) .filter((event: UpdateMigrationProjectEvent) => event.migrationProject.id === this.project.id) + .takeUntil(this.destroy) .subscribe((event: UpdateMigrationProjectEvent) => this.reloadMigrationProject(event.migrationProject)); - this._activatedRoute.parent.parent.data.subscribe((data: {project: MigrationProject}) => { + this._activatedRoute.parent.parent.data.takeUntil(this.destroy).subscribe((data: {project: MigrationProject}) => { this.reloadMigrationProject(data.project); - this._windupService.getProjectExecutions(this.project.id).subscribe(executions => { + this._windupService.getProjectExecutions(this.project.id).takeUntil(this.destroy).subscribe(executions => { this.loadActiveExecutions(executions); }); }); } ngAfterViewInit(): any { - this.deleteAppDialog.confirmed.subscribe((application) => { + this.deleteAppDialog.confirmed.takeUntil(this.destroy).subscribe((application) => { this.doDeleteApplication(application); }); - this.deleteAppDialog.cancelled.subscribe(() => { + this.deleteAppDialog.cancelled.takeUntil(this.destroy).subscribe(() => { this.deleteAppDialog.data = null; this.deleteAppDialog.body = ''; this.deleteAppDialog.title = ''; @@ -112,6 +115,7 @@ export class ApplicationListComponent extends ExecutionsMonitoringComponent impl .finally(() => { this.deletedApplications.delete(application.id); }) + .takeUntil(this.destroy) .subscribe( () => this._notificationService.success(`The application ‘${application.title}’ was deleted.`), error => this._notificationService.error(utils.getErrorMessage(error)) diff --git a/ui/src/main/webapp/src/app/registered-application/application-queue-list.component.ts b/ui/src/main/webapp/src/app/registered-application/application-queue-list.component.ts index 91a883e94..4388c4d86 100644 --- a/ui/src/main/webapp/src/app/registered-application/application-queue-list.component.ts +++ b/ui/src/main/webapp/src/app/registered-application/application-queue-list.component.ts @@ -5,6 +5,7 @@ import {FileItem} from "ng2-file-upload"; import {RegisteredApplicationService} from "./registered-application.service"; import {NotificationService} from "../core/notification/notification.service"; import {utils} from "../shared/utils"; +import {AbstractComponent} from "../shared/AbstractComponent"; /** * This component is quite hacky way how to show the same visuals as in alternative-upload-queue. @@ -33,7 +34,7 @@ import {utils} from "../shared/utils"; ], changeDetection: ChangeDetectionStrategy.OnPush }) -export class ApplicationQueueListComponent implements AfterViewInit +export class ApplicationQueueListComponent extends AbstractComponent implements AfterViewInit { @Input() public registeredApplications: RegisteredApplication[] = []; @@ -48,14 +49,15 @@ export class ApplicationQueueListComponent implements AfterViewInit protected _registeredApplicationsService: RegisteredApplicationService, protected _notificationService: NotificationService ) { + super(); } ngAfterViewInit(): any { - this.deleteAppDialog.confirmed.subscribe((application) => { + this.deleteAppDialog.confirmed.takeUntil(this.destroy).subscribe((application) => { this.doDeleteApplication(application); }); - this.deleteAppDialog.cancelled.subscribe(() => { + this.deleteAppDialog.cancelled.takeUntil(this.destroy).subscribe(() => { this.deleteAppDialog.data = null; this.deleteAppDialog.body = ''; this.deleteAppDialog.title = ''; @@ -63,7 +65,7 @@ export class ApplicationQueueListComponent implements AfterViewInit } public doDeleteApplication(application: RegisteredApplication) { - this._registeredApplicationsService.deleteApplication(this.project, application).subscribe( + this._registeredApplicationsService.deleteApplication(this.project, application).takeUntil(this.destroy).subscribe( //() => this._notificationService.success('Application was successfully deleted'), () => console.log(`Application ${application.id} was successfully deleted`), error => this._notificationService.error(utils.getErrorMessage(error)) diff --git a/ui/src/main/webapp/src/app/registered-application/edit-application-form.component.ts b/ui/src/main/webapp/src/app/registered-application/edit-application-form.component.ts index 67103705f..71faac95e 100644 --- a/ui/src/main/webapp/src/app/registered-application/edit-application-form.component.ts +++ b/ui/src/main/webapp/src/app/registered-application/edit-application-form.component.ts @@ -45,7 +45,7 @@ export class EditApplicationFormComponent extends RegisterApplicationFormCompone appPathToRegister: ["", Validators.compose([Validators.required, Validators.minLength(4)]), FileExistsValidator.create(this._fileService)] }); - this._activatedRoute.data.subscribe((data: {application: RegisteredApplication}) => { + this._activatedRoute.data.takeUntil(this.destroy).subscribe((data: {application: RegisteredApplication}) => { this.application = data.application; this.mode = this.application.registrationType; this.fileInputPath = this.application.inputPath; @@ -61,14 +61,14 @@ export class EditApplicationFormComponent extends RegisterApplicationFormCompone register() { if (this.mode == "PATH") { this.application.inputPath = this.fileInputPath; - this._registeredApplicationService.updateByPath(this.application).subscribe( + this._registeredApplicationService.updateByPath(this.application).takeUntil(this.destroy).subscribe( // application => this.rerouteToApplicationList(), application => this.rerouteToConfigurationForm(), error => this.handleError(error) ); } else { if (this.multipartUploader.getNotUploadedItems().length > 0) { - this._registeredApplicationService.updateByUpload(this.application).subscribe( + this._registeredApplicationService.updateByUpload(this.application).takeUntil(this.destroy).subscribe( //application => this.rerouteToApplicationList(), application => this.rerouteToApplicationList(), error => this.handleError(error) diff --git a/ui/src/main/webapp/src/app/registered-application/register-application-form.component.ts b/ui/src/main/webapp/src/app/registered-application/register-application-form.component.ts index 8b5188802..45f54170d 100644 --- a/ui/src/main/webapp/src/app/registered-application/register-application-form.component.ts +++ b/ui/src/main/webapp/src/app/registered-application/register-application-form.component.ts @@ -93,6 +93,7 @@ export class RegisterApplicationFormComponent extends FormComponent implements O ngOnInit(): any { this._eventBus.onEvent .filter(event => event.isTypeOf(UpdateMigrationProjectEvent)) + .takeUntil(this.destroy) .subscribe((event: UpdateMigrationProjectEvent) => this.project = event.migrationProject); this.registrationForm = this._formBuilder.group({ @@ -107,7 +108,7 @@ export class RegisterApplicationFormComponent extends FormComponent implements O isDirWithExplodedApp: [], }); - this.routerSubscription = this._router.events.filter(event => event instanceof NavigationEnd).subscribe(_ => { + this._router.events.filter(event => event instanceof NavigationEnd).takeUntil(this.destroy).subscribe(_ => { let flatRouteData = this._routeFlattener.getFlattenedRouteData(this._activatedRoute.snapshot); this.isInWizard = flatRouteData.data.hasOwnProperty('wizard') && flatRouteData.data['wizard']; @@ -132,8 +133,8 @@ export class RegisterApplicationFormComponent extends FormComponent implements O } ngOnDestroy(): void { + super.ngOnDestroy(); this.multipartUploader.clearQueue(); - this.routerSubscription.unsubscribe(); this._migrationProjectService.stopMonitoringProject(this.project); } @@ -158,18 +159,21 @@ export class RegisterApplicationFormComponent extends FormComponent implements O return; } - this._fileService.queryServerPathTargetType(this.fileInputPath).subscribe((type_: string) => { + this._fileService.queryServerPathTargetType(this.fileInputPath).takeUntil(this.destroy).subscribe((type_: string) => { if (type_ === "DIRECTORY" && !this.isDirWithExplodedApp) { //this.isDirWithApps this._registeredApplicationService.registerApplicationInDirectoryByPath(this.project, this.fileInputPath) + .takeUntil(this.destroy) .subscribe( application => this.navigateOnSuccess(), error => this.handleError(error) ); } else { - this._registeredApplicationService.registerByPath(this.project, this.fileInputPath, this.isDirWithExplodedApp).subscribe( - application => this.navigateOnSuccess(), - error => this.handleError(error) - ) + this._registeredApplicationService.registerByPath(this.project, this.fileInputPath, this.isDirWithExplodedApp) + .takeUntil(this.destroy) + .subscribe( + application => this.navigateOnSuccess(), + error => this.handleError(error) + ); } }); } @@ -180,7 +184,7 @@ export class RegisterApplicationFormComponent extends FormComponent implements O return; } - this._registeredApplicationService.uploadApplications(this.project).subscribe( + this._registeredApplicationService.uploadApplications(this.project).takeUntil(this.destroy).subscribe( () => {}, error => { if (!error.hasOwnProperty('code') || error.code !== RegisteredApplicationService.ERROR_FILE_EXISTS) { diff --git a/ui/src/main/webapp/src/app/reports/application-details/application-details.component.ts b/ui/src/main/webapp/src/app/reports/application-details/application-details.component.ts index 89d7f48c9..22643cc89 100644 --- a/ui/src/main/webapp/src/app/reports/application-details/application-details.component.ts +++ b/ui/src/main/webapp/src/app/reports/application-details/application-details.component.ts @@ -62,13 +62,13 @@ export class ApplicationDetailsComponent extends FilterableReportComponent imple } ngOnInit(): void { - this.addSubscription(this.flatRouteLoaded.subscribe(flattenedRoute => { + this.flatRouteLoaded.takeUntil(this.destroy).subscribe(flattenedRoute => { this.loadFilterFromRouteData(flattenedRoute); - this._applicationDetailsService.getApplicationDetailsData(this.execution.id, this.reportFilter).subscribe( + this._applicationDetailsService.getApplicationDetailsData(this.execution.id, this.reportFilter).takeUntil(this.destroy).subscribe( applicationDetailsDto => { // Make sure tag data is loaded first - this._tagDataService.getTagData().subscribe((tagData) => { + this._tagDataService.getTagData().takeUntil(this.destroy).subscribe((tagData) => { this.applicationDetails = applicationDetailsDto; this.rootProjects = applicationDetailsDto.traversals; @@ -82,7 +82,7 @@ export class ApplicationDetailsComponent extends FilterableReportComponent imple }, error => this._notificationService.error(utils.getErrorMessage(error)) ); - })); + }); } selectedProject(treeData:TreeData) { diff --git a/ui/src/main/webapp/src/app/reports/application-index/application-index.component.ts b/ui/src/main/webapp/src/app/reports/application-index/application-index.component.ts index e9b3c7b4f..156f124c6 100644 --- a/ui/src/main/webapp/src/app/reports/application-index/application-index.component.ts +++ b/ui/src/main/webapp/src/app/reports/application-index/application-index.component.ts @@ -51,7 +51,7 @@ export class ApplicationIndexComponent extends FilterableReportComponent impleme ngOnInit(): void { - this.addSubscription(this.flatRouteLoaded.subscribe(flatRouteData => { + this.flatRouteLoaded.takeUntil(this.destroy).subscribe(flatRouteData => { this.loadFilterFromRouteData(flatRouteData); this.analyzedApplications = this.execution.filterApplications.slice(); @@ -64,7 +64,7 @@ export class ApplicationIndexComponent extends FilterableReportComponent impleme this.projectId = +flatRouteData.params.projectId; - this._aggregatedStatsService.getAggregatedCategories(this.execution.id, this.reportFilter).subscribe( + this._aggregatedStatsService.getAggregatedCategories(this.execution.id, this.reportFilter).takeUntil(this.destroy).subscribe( result => { this.categoriesMultiStats = this.getCategoriesStats(this.calculateCategoryIncidents(result), this.calculateStoryPointsInCategories(result)); this.mandatoryMultiStats = this.getMandatoryMultiStats(result.categories.find(category => category.categoryID == "mandatory")); @@ -75,7 +75,7 @@ export class ApplicationIndexComponent extends FilterableReportComponent impleme } ); - this._aggregatedStatsService.getAggregatedJavaPackages(this.execution.id, this.reportFilter).subscribe( + this._aggregatedStatsService.getAggregatedJavaPackages(this.execution.id, this.reportFilter).takeUntil(this.destroy).subscribe( result => this.globalPackageUseData = this.convertPackagesToChartStatistic(result), error => { this._notificationService.error(utils.getErrorMessage(error)); @@ -83,7 +83,7 @@ export class ApplicationIndexComponent extends FilterableReportComponent impleme } ); - this._aggregatedStatsService.getAggregatedArchives(this.execution.id, this.reportFilter).subscribe( + this._aggregatedStatsService.getAggregatedArchives(this.execution.id, this.reportFilter).takeUntil(this.destroy).subscribe( result => this.componentsStats = result, error => { this._notificationService.error(utils.getErrorMessage(error)); @@ -91,14 +91,14 @@ export class ApplicationIndexComponent extends FilterableReportComponent impleme } ); - this._aggregatedStatsService.getAggregatedDependencies(this.execution.id, this.reportFilter).subscribe( + this._aggregatedStatsService.getAggregatedDependencies(this.execution.id, this.reportFilter).takeUntil(this.destroy).subscribe( result => this.dependenciesStats = result, error => { this._notificationService.error(utils.getErrorMessage(error)); this._router.navigate(['']); } ); - })); + }); } sumStatsList(statsList:StatisticsList): number { diff --git a/ui/src/main/webapp/src/app/reports/dependencies/dependencies-report.component.ts b/ui/src/main/webapp/src/app/reports/dependencies/dependencies-report.component.ts index af7443e3d..1399f51b2 100644 --- a/ui/src/main/webapp/src/app/reports/dependencies/dependencies-report.component.ts +++ b/ui/src/main/webapp/src/app/reports/dependencies/dependencies-report.component.ts @@ -1,22 +1,23 @@ import {Component} from "@angular/core"; import {DependenciesService} from "./dependencies.service"; import {ActivatedRoute} from "@angular/router"; +import {AbstractComponent} from "../../shared/AbstractComponent"; @Component({ template: `` }) -export class DependenciesReportComponent { +export class DependenciesReportComponent extends AbstractComponent { dependencies: any[]; constructor(private _activatedRoute: ActivatedRoute, private _dependenciesService: DependenciesService) { - + super(); } ngOnInit(): void { - this._activatedRoute.parent.parent.params.subscribe((params: {executionId: number}) => { + this._activatedRoute.parent.parent.params.takeUntil(this.destroy).subscribe((params: {executionId: number}) => { let executionId = params.executionId; - this._dependenciesService.getDependencies(executionId) + this._dependenciesService.getDependencies(executionId).takeUntil(this.destroy) .subscribe(dependencies => this.dependencies = dependencies); }); } diff --git a/ui/src/main/webapp/src/app/reports/execution-application-list/execution-application-list.component.ts b/ui/src/main/webapp/src/app/reports/execution-application-list/execution-application-list.component.ts index 845717ff7..d5a656f25 100644 --- a/ui/src/main/webapp/src/app/reports/execution-application-list/execution-application-list.component.ts +++ b/ui/src/main/webapp/src/app/reports/execution-application-list/execution-application-list.component.ts @@ -46,15 +46,15 @@ export class ExecutionApplicationListComponent extends RoutedComponent implement } ngOnInit(): any { - this.addSubscription(this.flatRouteLoaded.subscribe(flatRouteData => { + this.flatRouteLoaded.takeUntil(this.destroy).subscribe(flatRouteData => { let executionId = parseInt(flatRouteData.params['executionId']); this.execID = executionId; - this._windupService.getExecution(executionId) + this._windupService.getExecution(executionId).takeUntil(this.destroy) .subscribe(execution => { this.loadExecution(execution); }); - })); + }); } loadExecution(execution: WindupExecution) { @@ -64,7 +64,7 @@ export class ExecutionApplicationListComponent extends RoutedComponent implement this.sortedApplications = execution.filterApplications; this.updateSearch(); - this._applicationDetailsService.getApplicationDetailsData(this.execID).subscribe( + this._applicationDetailsService.getApplicationDetailsData(this.execID).takeUntil(this.destroy).subscribe( applicationDetailsDto => { this.applicationDetailsDTO = applicationDetailsDto; this.flattenReportData(); diff --git a/ui/src/main/webapp/src/app/reports/filter/report-filter.component.ts b/ui/src/main/webapp/src/app/reports/filter/report-filter.component.ts index c26ad8abf..068ebd434 100644 --- a/ui/src/main/webapp/src/app/reports/filter/report-filter.component.ts +++ b/ui/src/main/webapp/src/app/reports/filter/report-filter.component.ts @@ -9,17 +9,17 @@ import {CustomSelectConfiguration} from "../../shared/custom-select/custom-selec import {utils} from "../../shared/utils"; import {Location} from "@angular/common"; import {TagDataService} from "../tag-data.service"; +import {AbstractComponent} from "../../shared/AbstractComponent"; @Component({ templateUrl: './report-filter.component.html' }) -export class ReportFilterComponent implements OnInit, OnDestroy { +export class ReportFilterComponent extends AbstractComponent implements OnInit, OnDestroy { project: MigrationProject = {}; execution: WindupExecution = {}; filter: ReportFilter; tags: Tag[] = []; categories: Category[] = []; - routerSubscriptions: Subscription[] = []; filterApplications: FilterApplication[] = []; appSelectConfig: CustomSelectConfiguration; @@ -34,6 +34,8 @@ export class ReportFilterComponent implements OnInit, OnDestroy { private _notificationService: NotificationService, private _routeFlattenerService: RouteFlattenerService, private _location: Location) { + super(); + this.filter = this.getDefaultFilter(); this.categoryTagSelectConfig = { @@ -66,21 +68,21 @@ export class ReportFilterComponent implements OnInit, OnDestroy { } ngOnInit(): void { - this.routerSubscriptions.push(this._router.events.filter(event => event instanceof NavigationEnd).subscribe(_ => { + this._router.events.filter(event => event instanceof NavigationEnd).takeUntil(this.destroy).subscribe(_ => { let flatData = this._routeFlattenerService.getFlattenedRouteData(this._activatedRoute.snapshot); // TODO: Fix this this.execution = flatData.data['applicationGroup']; this.filter = this.execution.reportFilter || this.getDefaultFilter(); - this._filterService.getTags(this.execution).subscribe( + this._filterService.getTags(this.execution).takeUntil(this.destroy).subscribe( tags => { this.tags = this.accumulateAllTags([], tags); }, error => this._notificationService.error(utils.getErrorMessage(error)) ); - this._filterService.getCategories(this.execution).subscribe( + this._filterService.getCategories(this.execution).takeUntil(this.destroy).subscribe( categories => this.categories = categories, error => this._notificationService.error(utils.getErrorMessage(error)) ); @@ -88,13 +90,13 @@ export class ReportFilterComponent implements OnInit, OnDestroy { let lastExecution = this.getLastExecution(this.project); if (lastExecution != null) { - this._filterService.getFilterApplications(lastExecution) + this._filterService.getFilterApplications(lastExecution).takeUntil(this.destroy) .subscribe(filterApplications => { this.filterApplications = filterApplications; this.isFilterUpToDate = this.areApplicationsInFilterUpToDate(); }); } - })); + }); } private areApplicationsInFilterUpToDate(): boolean { @@ -145,12 +147,8 @@ export class ReportFilterComponent implements OnInit, OnDestroy { return accumulatedTags; } - ngOnDestroy(): void { - this.routerSubscriptions.forEach(_ => _.unsubscribe()); - } - saveFilter() { - this._filterService.updateFilter(this.execution, this.filter).subscribe(() => { + this._filterService.updateFilter(this.execution, this.filter).takeUntil(this.destroy).subscribe(() => { this._notificationService.success('Filter successfully updated'); }, error => this._notificationService.error(utils.getErrorMessage(error)) diff --git a/ui/src/main/webapp/src/app/reports/hardcoded-ip/hardcoded-ip.component.ts b/ui/src/main/webapp/src/app/reports/hardcoded-ip/hardcoded-ip.component.ts index 587dada7e..ff2ffeae7 100644 --- a/ui/src/main/webapp/src/app/reports/hardcoded-ip/hardcoded-ip.component.ts +++ b/ui/src/main/webapp/src/app/reports/hardcoded-ip/hardcoded-ip.component.ts @@ -30,11 +30,11 @@ export class HardcodedIPReportComponent extends FilterableReportComponent implem } ngOnInit(): void { - this.addSubscription(this.flatRouteLoaded.subscribe(flatRouteData => { + this.flatRouteLoaded.takeUntil(this.destroy).subscribe(flatRouteData => { this.loadFilterFromRouteData(flatRouteData); this.loadHardcodedIPs(); - })); + }); } updateSearch(): void { @@ -60,7 +60,7 @@ export class HardcodedIPReportComponent extends FilterableReportComponent implem } private loadHardcodedIPs() { - this._hardcodedIPService.getHardcodedIPModels(this.execution.id, this.reportFilter) + this._hardcodedIPService.getHardcodedIPModels(this.execution.id, this.reportFilter).takeUntil(this.destroy) .subscribe( hardcodedIPDTOs => { this.hardcodedIPs = this.filteredHardcodedIPs = this.sortedHardcodedIPs = hardcodedIPDTOs; diff --git a/ui/src/main/webapp/src/app/reports/migration-issues/migration-issues-table.component.ts b/ui/src/main/webapp/src/app/reports/migration-issues/migration-issues-table.component.ts index 3d9cded85..df5520190 100644 --- a/ui/src/main/webapp/src/app/reports/migration-issues/migration-issues-table.component.ts +++ b/ui/src/main/webapp/src/app/reports/migration-issues/migration-issues-table.component.ts @@ -53,7 +53,7 @@ export class MigrationIssuesTableComponent extends FilterableReportComponent imp let flatRouteData = this._routeFlattener.getFlattenedRouteData(this._activatedRoute.snapshot); this.loadFilterFromRouteData(flatRouteData); - this.addSubscription(this._routeFlattener.OnFlatRouteLoaded.subscribe( + this.addSubscription(this._routeFlattener.OnFlatRouteLoaded.takeUntil(this.destroy).subscribe( flatRouteData => this.loadFilterFromRouteData(flatRouteData) )); } @@ -90,15 +90,17 @@ export class MigrationIssuesTableComponent extends FilterableReportComponent imp } protected loadIssuesPerFile(summary: ProblemSummary) { - this._migrationIssuesService.getIssuesPerFile(this.execution.id, summary, this.reportFilter).subscribe(fileSummaries => { - this.problemSummariesFiles.set(summary, { - files: fileSummaries, - visible: true + this._migrationIssuesService.getIssuesPerFile(this.execution.id, summary, this.reportFilter) + .takeUntil(this.destroy) + .subscribe(fileSummaries => { + this.problemSummariesFiles.set(summary, { + files: fileSummaries, + visible: true + }); + }, + error => { + this._notificationService.error('Could not load file summaries due to: ' + error); }); - }, - error => { - this._notificationService.error('Could not load file summaries due to: ' + error); - }); } filesVisible(summary: ProblemSummary): boolean { diff --git a/ui/src/main/webapp/src/app/reports/migration-issues/migration-issues.component.ts b/ui/src/main/webapp/src/app/reports/migration-issues/migration-issues.component.ts index ff8aefbed..394782c70 100644 --- a/ui/src/main/webapp/src/app/reports/migration-issues/migration-issues.component.ts +++ b/ui/src/main/webapp/src/app/reports/migration-issues/migration-issues.component.ts @@ -40,10 +40,10 @@ export class MigrationIssuesComponent extends FilterableReportComponent implemen } ngOnInit(): void { - this.addSubscription(this.flatRouteLoaded.subscribe(flatRouteData => { + this.flatRouteLoaded.takeUntil(this.destroy).subscribe(flatRouteData => { this.loadFilterFromRouteData(flatRouteData); - this._migrationIssuesService.getAggregatedIssues(this.execution.id, this.reportFilter).subscribe( + this._migrationIssuesService.getAggregatedIssues(this.execution.id, this.reportFilter).takeUntil(this.destroy).subscribe( result => { this.categorizedIssues = result; this.categories = Object.keys(result); @@ -54,7 +54,7 @@ export class MigrationIssuesComponent extends FilterableReportComponent implemen this._notificationService.error(utils.getErrorMessage(error)); this._router.navigate(['']); }); - })); + }); } reloadData() { diff --git a/ui/src/main/webapp/src/app/reports/source/source-report.component.ts b/ui/src/main/webapp/src/app/reports/source/source-report.component.ts index 0d0b6659f..27d29501a 100644 --- a/ui/src/main/webapp/src/app/reports/source/source-report.component.ts +++ b/ui/src/main/webapp/src/app/reports/source/source-report.component.ts @@ -59,40 +59,40 @@ export class SourceReportComponent extends RoutedComponent implements OnInit, Af } ngOnInit(): void { - this.addSubscription(this.flatRouteLoaded.subscribe(flatRouteData => { + this.flatRouteLoaded.takeUntil(this.destroy).subscribe(flatRouteData => { this.execID = +flatRouteData.params['executionId']; this.fileID = +flatRouteData.params['fileId']; - this.fileModelService.getFileModel(this.execID, this.fileID).subscribe( + this.fileModelService.getFileModel(this.execID, this.fileID).takeUntil(this.destroy).subscribe( (fileModel) => { this.fileModel = fileModel; // Assume this is a source file model and deserialize it as one... if it is not, this will have a lot of null // properties this.sourceFileModel = this._graphJsonToModelService.fromJSON(this.fileModel.data, SourceFileModel); - this.sourceFileModel.linksToTransformedFiles.subscribe((links) => this.transformedLinks = links); + this.sourceFileModel.linksToTransformedFiles.takeUntil(this.destroy).subscribe((links) => this.transformedLinks = links); }, error => this.notificationService.error(utils.getErrorMessage(error))); - this.classificationService.getClassificationsForFile(this.execID, this.fileID) + this.classificationService.getClassificationsForFile(this.execID, this.fileID).takeUntil(this.destroy) .subscribe((classifications) => this.classifications = classifications, error => this.notificationService.error(utils.getErrorMessage(error))); - this.hintService.getHintsForFile(this.execID, this.fileID) + this.hintService.getHintsForFile(this.execID, this.fileID).takeUntil(this.destroy) .subscribe((hints) => this.hints = hints, error => this.notificationService.error(utils.getErrorMessage(error))); - this.fileModelService.getSource(this.execID, this.fileID) + this.fileModelService.getSource(this.execID, this.fileID).takeUntil(this.destroy) .subscribe((fileSource) => { this.fileSource = fileSource; this.fileLines = fileSource.split(/[\r\n]/).map((line) => line + "\n"); }, error => this.notificationService.error(utils.getErrorMessage(error))); - this.technologyTagService.getTagsForFile(this.execID, this.fileID) + this.technologyTagService.getTagsForFile(this.execID, this.fileID).takeUntil(this.destroy) .subscribe((technologyTags) => this.technologyTags = technologyTags, error => this.notificationService.error(utils.getErrorMessage(error))); - })); + }); } private getClassificationLinks(classification: ClassificationModel): Observable { diff --git a/ui/src/main/webapp/src/app/reports/technologies/hibernate/hibernate-report.component.ts b/ui/src/main/webapp/src/app/reports/technologies/hibernate/hibernate-report.component.ts index f05e51c6b..1ab3fd872 100644 --- a/ui/src/main/webapp/src/app/reports/technologies/hibernate/hibernate-report.component.ts +++ b/ui/src/main/webapp/src/app/reports/technologies/hibernate/hibernate-report.component.ts @@ -57,14 +57,14 @@ export class TechnologiesHibernateReportComponent extends FilterableReportCompon } ngOnInit(): void { - this.addSubscription(this.flatRouteLoaded.subscribe(flatRouteData => { + this.flatRouteLoaded.takeUntil(this.destroy).subscribe(flatRouteData => { this.title = flatRouteData.data.displayName; this.loadFilterFromRouteData(flatRouteData); const execId = this.execution.id; - this.techReportService.getHibernateEntityModel(execId, this.reportFilter).subscribe( + this.techReportService.getHibernateEntityModel(execId, this.reportFilter).takeUntil(this.destroy).subscribe( data => { this.entities = data; this.loading.entities = false; @@ -73,27 +73,27 @@ export class TechnologiesHibernateReportComponent extends FilterableReportCompon this._notificationService.error(utils.getErrorMessage(error)); }); - this.techReportService.getHibernateConfigurationFileModel(execId, this.reportFilter).subscribe(configurations => { + this.techReportService.getHibernateConfigurationFileModel(execId, this.reportFilter).takeUntil(this.destroy).subscribe(configurations => { this.configurationFiles = configurations; this.loading.configurationFiles = false; }, error => { this._notificationService.error(utils.getErrorMessage(error)); }); - this.techReportService.getHibernateMappingFileModel(execId, this.reportFilter).subscribe(mappings => { + this.techReportService.getHibernateMappingFileModel(execId, this.reportFilter).takeUntil(this.destroy).subscribe(mappings => { this.mappingFiles = mappings; this.loading.mappingFiles = false; }, error => { this._notificationService.error(utils.getErrorMessage(error)); }); - this.techReportService.getHibernateSessionFactoryModel(execId, this.reportFilter).subscribe(sessionFactories => { + this.techReportService.getHibernateSessionFactoryModel(execId, this.reportFilter).takeUntil(this.destroy).subscribe(sessionFactories => { this.sessionFactories = sessionFactories; this.loading.sessionFactories = false; }, error => { this._notificationService.error(utils.getErrorMessage(error)); }); - })); + }); } updateSearch() { diff --git a/ui/src/main/webapp/src/app/shared/AbstractComponent.ts b/ui/src/main/webapp/src/app/shared/AbstractComponent.ts index 2097eab1b..70f33b7d7 100644 --- a/ui/src/main/webapp/src/app/shared/AbstractComponent.ts +++ b/ui/src/main/webapp/src/app/shared/AbstractComponent.ts @@ -1,14 +1,18 @@ import {OnDestroy} from "@angular/core"; import {Subscription} from "rxjs"; +import {Subject} from "rxjs/Subject"; export abstract class AbstractComponent implements OnDestroy { protected subscriptions: Subscription[] = []; + protected destroy: Subject = new Subject(); public addSubscription(subscription: Subscription) { this.subscriptions.push(subscription); } ngOnDestroy(): void { + this.destroy.next(true); + this.destroy.unsubscribe(); this.subscriptions.forEach(subscription => subscription.unsubscribe()); } } diff --git a/ui/src/main/webapp/src/app/shared/form.component.ts b/ui/src/main/webapp/src/app/shared/form.component.ts index b28de961c..180d5d851 100644 --- a/ui/src/main/webapp/src/app/shared/form.component.ts +++ b/ui/src/main/webapp/src/app/shared/form.component.ts @@ -1,10 +1,12 @@ import {AbstractControl, NgControl} from "@angular/forms"; import {utils} from "./utils"; +import {AbstractComponent} from "./AbstractComponent"; -export class FormComponent { +export class FormComponent extends AbstractComponent { errorMessages: string[] = []; constructor() { + super(); } /**